Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RollupProcessorV2
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 2000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IVerifier} from "../interfaces/IVerifier.sol";
import {IRollupProcessorV2, IRollupProcessor} from "rollup-encoder/interfaces/IRollupProcessorV2.sol";
import {IDefiBridge} from "../interfaces/IDefiBridge.sol";
import {Decoder} from "../Decoder.sol";
import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol";
import {TokenTransfers} from "../libraries/TokenTransfers.sol";
import {RollupProcessorLibrary} from "rollup-encoder/libraries/RollupProcessorLibrary.sol";
import {SafeCast} from "../libraries/SafeCast.sol";
/**
* @title Rollup Processor
* @dev Smart contract responsible for processing Aztec zkRollups, relaying them to a verifier
* contract for validation and performing all the relevant ERC20 token transfers
*/
contract RollupProcessorV2 is IRollupProcessorV2, Decoder, Initializable, AccessControl {
using SafeCast for uint256;
/*----------------------------------------
ERROR TAGS
----------------------------------------*/
error PAUSED();
error NOT_PAUSED();
error LOCKED_NO_REENTER();
error INVALID_PROVIDER();
error THIRD_PARTY_CONTRACTS_FLAG_NOT_SET();
error INSUFFICIENT_DEPOSIT();
error INVALID_ADDRESS_NO_CODE();
error INVALID_ASSET_GAS();
error INVALID_ASSET_ID();
error INVALID_ASSET_ADDRESS();
error INVALID_BRIDGE_GAS();
error INVALID_BRIDGE_CALL_DATA();
error INVALID_BRIDGE_ADDRESS();
error INVALID_ESCAPE_BOUNDS();
error INCONSISTENT_BRIDGE_CALL_DATA();
error BRIDGE_WITH_IDENTICAL_INPUT_ASSETS(uint256 inputAssetId);
error BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS(uint256 outputAssetId);
error ZERO_TOTAL_INPUT_VALUE();
error ARRAY_OVERFLOW();
error MSG_VALUE_WRONG_AMOUNT();
error INSUFFICIENT_ETH_PAYMENT();
error WITHDRAW_TO_ZERO_ADDRESS();
error DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE();
error INSUFFICIENT_TOKEN_APPROVAL();
error NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET(uint256 outputValue);
error INCORRECT_STATE_HASH(bytes32 oldStateHash, bytes32 newStateHash);
error INCORRECT_DATA_START_INDEX(uint256 providedIndex, uint256 expectedIndex);
error INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH(
bytes32 providedDefiInteractionHash, bytes32 expectedDefiInteractionHash
);
error PUBLIC_INPUTS_HASH_VERIFICATION_FAILED(uint256, uint256);
error PROOF_VERIFICATION_FAILED();
error PENDING_CAP_SURPASSED();
error DAILY_CAP_SURPASSED();
/*----------------------------------------
EVENTS
----------------------------------------*/
event OffchainData(uint256 indexed rollupId, uint256 chunk, uint256 totalChunks, address sender);
event RollupProcessed(uint256 indexed rollupId, bytes32[] nextExpectedDefiHashes, address sender);
event DefiBridgeProcessed(
uint256 indexed encodedBridgeCallData,
uint256 indexed nonce,
uint256 totalInputValue,
uint256 totalOutputValueA,
uint256 totalOutputValueB,
bool result,
bytes errorReason
);
event AsyncDefiBridgeProcessed(
uint256 indexed encodedBridgeCallData, uint256 indexed nonce, uint256 totalInputValue
);
event Deposit(uint256 indexed assetId, address indexed depositorAddress, uint256 depositValue);
event AssetAdded(uint256 indexed assetId, address indexed assetAddress, uint256 assetGasLimit);
event BridgeAdded(uint256 indexed bridgeAddressId, address indexed bridgeAddress, uint256 bridgeGasLimit);
event RollupProviderUpdated(address indexed providerAddress, bool valid);
event VerifierUpdated(address indexed verifierAddress);
event AllowThirdPartyContractsUpdated(bool allowed);
event DefiBridgeProxyUpdated(address defiBridgeProxy);
event Paused(address account);
event Unpaused(address account);
event DelayBeforeEscapeHatchUpdated(uint32 delay);
event AssetCapUpdated(uint256 assetId, uint256 pendingCap, uint256 dailyCap);
event CappedUpdated(bool isCapped);
/*----------------------------------------
STRUCTS
----------------------------------------*/
// @dev ALLOW_ASYNC_REENTER lock is present to allow calling of `processAsyncDefiInteraction(...)` from within
// bridge's `convert(...)` method.
enum Lock {
UNLOCKED,
ALLOW_ASYNC_REENTER,
LOCKED
}
/**
* @dev RollupState struct contains the following data:
*
* | bit offset | num bits | description |
* | --- | --- | --- |
* | 0 | 160 | PLONK verifier contract address |
* | 160 | 32 | datasize: number of filled entries in note tree |
* | 192 | 16 | asyncDefiInteractionHashes.length : number of entries in asyncDefiInteractionHashes array |
* | 208 | 16 | defiInteractionHashes.length : number of entries in defiInteractionHashes array |
* | 224 | 8 | Lock enum used to guard against reentrancy attacks (minimum value to store in is uint8)
* | 232 | 8 | pause flag, true if contract is paused, false otherwise
* | 240 | 8 | capped flag, true if assets should check cap, false otherwise
*
* Note: (RollupState struct gets packed to 1 storage slot -> bit offset signifies location withing the 256 bit string)
*/
struct RollupState {
IVerifier verifier;
uint32 datasize;
uint16 numAsyncDefiInteractionHashes;
uint16 numDefiInteractionHashes;
Lock lock;
bool paused;
bool capped;
}
/**
* @dev Contains information that describes a specific call to a bridge
*/
struct FullBridgeCallData {
uint256 bridgeAddressId;
address bridgeAddress;
uint256 inputAssetIdA;
uint256 inputAssetIdB;
uint256 outputAssetIdA;
uint256 outputAssetIdB;
uint256 auxData;
bool firstInputVirtual;
bool secondInputVirtual;
bool firstOutputVirtual;
bool secondOutputVirtual;
bool secondInputInUse;
bool secondOutputInUse;
uint256 bridgeGasLimit;
}
/**
* @dev Represents an asynchronous DeFi bridge interaction that has not been resolved
* @param encodedBridgeCallData bit-string encoded bridge call data
* @param totalInputValue number of tokens/wei sent to the bridge
*/
struct PendingDefiBridgeInteraction {
uint256 encodedBridgeCallData;
uint256 totalInputValue;
}
/**
* @dev Container for the results of a DeFi interaction
* @param outputValueA amount of output asset A returned from the interaction
* @param outputValueB amount of output asset B returned from the interaction (0 if asset B unused)
* @param isAsync true if the interaction is asynchronous, false otherwise
* @param success true if the call succeeded, false otherwise
*/
struct BridgeResult {
uint256 outputValueA;
uint256 outputValueB;
bool isAsync;
bool success;
}
/**
* @dev Container for the inputs of a DeFi interaction
* @param totalInputValue number of tokens/wei sent to the bridge
* @param interactionNonce the unique id of the interaction
* @param auxData additional input specific to the type of interaction
*/
struct InteractionInputs {
uint256 totalInputValue;
uint256 interactionNonce;
uint64 auxData;
}
/**
* @dev Container for asset cap restrictions
* @dev Caps used to limit usefulness of using Aztec to "wash" larger hacks
* @param available The amount of tokens that can be deposited, bounded by `dailyCap * 10 ** decimals`.
* @param lastUpdatedTimestamp The timestamp of the last deposit with caps activated
* @param pendingCap The cap for each individual pending deposit measured in whole tokens
* @param dailyCap The cap for total amount that can be added to `available` in 24 hours, measured in whole tokens
* @param precision The number of decimals in the precision for specific asset.
*/
struct AssetCap {
uint128 available;
uint32 lastUpdatedTimestamp;
uint32 pendingCap;
uint32 dailyCap;
uint8 precision;
}
/*----------------------------------------
FUNCTION SELECTORS (PRECOMPUTED)
----------------------------------------*/
// DEFI_BRIDGE_PROXY_CONVERT_SELECTOR = function signature of:
// function convert(
// address,
// AztecTypes.AztecAsset memory inputAssetA,
// AztecTypes.AztecAsset memory inputAssetB,
// AztecTypes.AztecAsset memory outputAssetA,
// AztecTypes.AztecAsset memory outputAssetB,
// uint256 totalInputValue,
// uint256 interactionNonce,
// uint256 auxData,
// uint256 ethPaymentsSlot
// address rollupBeneficary)
// N.B. this is the selector of the 'convert' function of the DefiBridgeProxy contract.
// This has a different interface to the IDefiBridge.convert function
bytes4 private constant DEFI_BRIDGE_PROXY_CONVERT_SELECTOR = 0x4bd947a8;
bytes4 private constant INVALID_ADDRESS_NO_CODE_SELECTOR = 0x21409272; // bytes4(keccak256('INVALID_ADDRESS_NO_CODE()'));
bytes4 private constant ARRAY_OVERFLOW_SELECTOR = 0x58a4ab0e; // bytes4(keccak256('ARRAY_OVERFLOW()'));
/*----------------------------------------
CONSTANT STATE VARIABLES
----------------------------------------*/
uint256 private constant ETH_ASSET_ID = 0; // if assetId == ETH_ASSET_ID, treat as native ETH and not ERC20 token
// starting root hash of the DeFi interaction result Merkle tree
bytes32 private constant INIT_DEFI_ROOT = 0x2e4ab7889ab3139204945f9e722c7a8fdb84e66439d787bd066c3d896dba04ea;
bytes32 private constant DEFI_BRIDGE_PROCESSED_SIGHASH =
0x692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c;
bytes32 private constant ASYNC_BRIDGE_PROCESSED_SIGHASH =
0x38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d;
// We need to cap the amount of gas sent to the DeFi bridge contract for two reasons:
// 1. To provide consistency to rollup providers around costs,
// 2. to prevent griefing attacks where a bridge consumes all our gas.
uint256 private constant MIN_BRIDGE_GAS_LIMIT = 35000;
uint256 private constant MIN_ERC20_GAS_LIMIT = 55000;
uint256 private constant MAX_BRIDGE_GAS_LIMIT = 5000000;
uint256 private constant MAX_ERC20_GAS_LIMIT = 1500000;
// Bit offsets and bit masks used to extract values from `uint256 encodedBridgeCallData` to FullBridgeCallData struct
uint256 private constant INPUT_ASSET_ID_A_SHIFT = 32;
uint256 private constant INPUT_ASSET_ID_B_SHIFT = 62;
uint256 private constant OUTPUT_ASSET_ID_A_SHIFT = 92;
uint256 private constant OUTPUT_ASSET_ID_B_SHIFT = 122;
uint256 private constant BITCONFIG_SHIFT = 152;
uint256 private constant AUX_DATA_SHIFT = 184;
uint256 private constant VIRTUAL_ASSET_ID_FLAG_SHIFT = 29;
uint256 private constant VIRTUAL_ASSET_ID_FLAG = 0x2000_0000; // 2 ** 29
uint256 private constant MASK_THIRTY_TWO_BITS = 0xffff_ffff;
uint256 private constant MASK_THIRTY_BITS = 0x3fff_ffff;
uint256 private constant MASK_SIXTY_FOUR_BITS = 0xffff_ffff_ffff_ffff;
// Offsets and masks used to encode/decode the rollupState storage variable of RollupProcessor
uint256 private constant DATASIZE_BIT_OFFSET = 160;
uint256 private constant ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET = 192;
uint256 private constant DEFIINTERACTIONHASHES_BIT_OFFSET = 208;
uint256 private constant ARRAY_LENGTH_MASK = 0x3ff; // 1023
uint256 private constant DATASIZE_MASK = 0xffff_ffff;
// the value of hashing a 'zeroed' DeFi interaction result
bytes32 private constant DEFI_RESULT_ZERO_HASH = 0x2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b4;
// roles used in access control
bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE");
bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
bytes32 public constant LISTER_ROLE = keccak256("LISTER_ROLE");
bytes32 public constant RESUME_ROLE = keccak256("RESUME_ROLE");
// bounds used for escape hatch
uint256 public immutable escapeBlockLowerBound;
uint256 public immutable escapeBlockUpperBound;
/*----------------------------------------
STATE VARIABLES
----------------------------------------*/
RollupState internal rollupState;
// An array of addresses of supported ERC20 tokens
address[] internal supportedAssets;
// An array of addresses of supported bridges
// @dev `bridgeAddressId` is an index of the bridge's address in this array incremented by 1
address[] internal supportedBridges;
// A mapping from index to async interaction hash (emulates an array)
// @dev next index is stored in `RollupState.numAsyncDefiInteractionHashes`
mapping(uint256 => bytes32) public asyncDefiInteractionHashes;
// A mapping from index to interaction hash (emulates an array)
// @dev next index is stored in the `RollupState.numDefiInteractionHashes`
mapping(uint256 => bytes32) public defiInteractionHashes;
// A mapping from assetId to a mapping of userAddress to the user's public pending balance
mapping(uint256 => mapping(address => uint256)) public userPendingDeposits;
// A mapping from user's address to a mapping of proof hashes to a boolean which indicates approval
mapping(address => mapping(bytes32 => bool)) public depositProofApprovals;
// A hash of the latest rollup state
bytes32 public override(IRollupProcessor) rollupStateHash;
// An address of DefiBridgeProxy contract
address public override(IRollupProcessor) defiBridgeProxy;
// A flag indicating whether addresses without a LISTER role can list assets and bridges
// Note: will be set to true once Aztec Connect is no longer in BETA
bool public allowThirdPartyContracts;
// A mapping from an address to a boolean which indicates whether address is an approved rollup provider
// @dev A rollup provider is an address which is allowed to call `processRollup(...)` out of escape hatch window.
mapping(address => bool) public rollupProviders;
// A mapping from interactionNonce to PendingDefiBridgeInteraction struct
mapping(uint256 => PendingDefiBridgeInteraction) public pendingDefiInteractions;
// A mapping from interactionNonce to ETH amount which was received for that interaction.
// interaction
mapping(uint256 => uint256) public ethPayments;
// A mapping from an `assetId` to a gas limit
mapping(uint256 => uint256) public assetGasLimits;
// A mapping from a `bridgeAddressId` to a gas limit
mapping(uint256 => uint256) public bridgeGasLimits;
// A hash of hashes of pending DeFi interactions, the notes of which are expected to be added in the 'next' rollup
bytes32 public override(IRollupProcessor) prevDefiInteractionsHash;
// The timestamp of the last rollup that was performed by a rollup provider
uint32 public lastRollupTimeStamp;
// The delay in seconds from `lastRollupTimeStamp` until the escape hatch can be used.
uint32 public delayBeforeEscapeHatch;
mapping(uint256 => AssetCap) public caps;
/*----------------------------------------
MODIFIERS
----------------------------------------*/
/**
* @notice A modifier forbidding functions from being called by addresses without LISTER role when Aztec Connect
* is still in BETA (`allowThirdPartyContracts` variable set to false)
*/
modifier checkThirdPartyContractStatus() {
if (!hasRole(LISTER_ROLE, msg.sender) && !allowThirdPartyContracts) {
revert THIRD_PARTY_CONTRACTS_FLAG_NOT_SET();
}
_;
}
/**
* @notice A modifier reverting if this contract is paused
*/
modifier whenNotPaused() {
if (rollupState.paused) {
revert PAUSED();
}
_;
}
/**
* @notice A modifier reverting if this contract is NOT paused
*/
modifier whenPaused() {
if (!rollupState.paused) {
revert NOT_PAUSED();
}
_;
}
/**
* @notice A modifier reverting on any re-enter
*/
modifier noReenter() {
if (rollupState.lock != Lock.UNLOCKED) {
revert LOCKED_NO_REENTER();
}
rollupState.lock = Lock.LOCKED;
_;
rollupState.lock = Lock.UNLOCKED;
}
/**
* @notice A modifier reverting on any re-enter but allowing async to be called
*/
modifier allowAsyncReenter() {
if (rollupState.lock != Lock.UNLOCKED) {
revert LOCKED_NO_REENTER();
}
rollupState.lock = Lock.ALLOW_ASYNC_REENTER;
_;
rollupState.lock = Lock.UNLOCKED;
}
/**
* @notice A modifier reverting if re-entering after locking, but passes if unlocked or if async is re-enter is
* allowed
*/
modifier noReenterButAsync() {
Lock lock = rollupState.lock;
if (lock == Lock.ALLOW_ASYNC_REENTER) {
_;
} else if (lock == Lock.UNLOCKED) {
rollupState.lock = Lock.ALLOW_ASYNC_REENTER;
_;
rollupState.lock = Lock.UNLOCKED;
} else {
revert LOCKED_NO_REENTER();
}
}
/**
* @notice A modifier which reverts if a given `_assetId` represents a virtual asset
* @param _assetId 30-bit integer that describes the asset
* @dev If _assetId's 29th bit is set, it represents a virtual asset with no ERC20 equivalent
* Virtual assets are used by the bridges to track non-token data. E.g. to represent a loan.
* If an _assetId is *not* a virtual asset, its ERC20 address can be recovered from
* `supportedAssets[_assetId]`
*/
modifier validateAssetIdIsNotVirtual(uint256 _assetId) {
if (_assetId > 0x1fffffff) {
revert INVALID_ASSET_ID();
}
_;
}
/*----------------------------------------
CONSTRUCTORS & INITIALIZERS
----------------------------------------*/
/**
* @notice Constructor sets escape hatch window and ensure that the implementation cannot be initialized
* @param _escapeBlockLowerBound a block number which defines a start of the escape hatch window
* @param _escapeBlockUpperBound a block number which defines an end of the escape hatch window
*/
constructor(uint256 _escapeBlockLowerBound, uint256 _escapeBlockUpperBound) {
if (_escapeBlockLowerBound == 0 || _escapeBlockLowerBound >= _escapeBlockUpperBound) {
revert INVALID_ESCAPE_BOUNDS();
}
// Set storage in implementation.
// Disable initializers to ensure no-one can call initialize on implementation directly
// Pause to limit possibility for user error
_disableInitializers();
rollupState.paused = true;
// Set immutables (part of code) so will be used in proxy calls as well
escapeBlockLowerBound = _escapeBlockLowerBound;
escapeBlockUpperBound = _escapeBlockUpperBound;
}
/**
* @notice Initialiser function which emulates constructor behaviour for upgradeable contracts
*/
function initialize() external reinitializer(getImplementationVersion()) {
rollupState.capped = true;
lastRollupTimeStamp = uint32(block.timestamp);
// Set Eth asset caps. 6 Eth to cover 5 eth deposits + fee up to 1 eth.
caps[0] = AssetCap({
available: uint128(1000e18),
lastUpdatedTimestamp: uint32(block.timestamp),
pendingCap: 6,
dailyCap: 1000,
precision: 18
});
// Set Dai asset cap. 10100 Dai to cover 10K deposits + fee up to 100 dai.
caps[1] = AssetCap({
available: uint128(1e24),
lastUpdatedTimestamp: uint32(block.timestamp),
pendingCap: 10100,
dailyCap: 1e6,
precision: 18
});
emit AssetCapUpdated(0, 6, 1000);
emit AssetCapUpdated(1, 10100, 1e6);
}
/*----------------------------------------
MUTATING FUNCTIONS WITH ACCESS CONTROL
----------------------------------------*/
/**
* @notice A function which allow the holders of the EMERGENCY_ROLE role to pause the contract
*/
function pause() public override (IRollupProcessor) whenNotPaused onlyRole(EMERGENCY_ROLE) noReenter {
rollupState.paused = true;
emit Paused(msg.sender);
}
/**
* @dev Allow the holders of the RESUME_ROLE to unpause the contract.
*/
function unpause() public override (IRollupProcessor) whenPaused onlyRole(RESUME_ROLE) noReenter {
rollupState.paused = false;
emit Unpaused(msg.sender);
}
/**
* @notice A function which allows holders of OWNER_ROLE to set the capped flag
* @dev When going from uncapped to capped, will update `lastRollupTimeStamp`
* @param _isCapped a flag indicating whether caps are used or not
*/
function setCapped(bool _isCapped) external onlyRole(OWNER_ROLE) noReenter {
if (_isCapped == rollupState.capped) return;
if (_isCapped) {
lastRollupTimeStamp = uint32(block.timestamp);
}
rollupState.capped = _isCapped;
emit CappedUpdated(_isCapped);
}
/**
* @notice A function which allows holders of OWNER_ROLE to add and remove a rollup provider.
* @param _provider an address of the rollup provider
* @param _valid a flag indicating whether `_provider` is valid
*/
function setRollupProvider(address _provider, bool _valid)
external
override (IRollupProcessor)
onlyRole(OWNER_ROLE)
noReenter
{
rollupProviders[_provider] = _valid;
emit RollupProviderUpdated(_provider, _valid);
}
/**
* @notice A function which allows holders of the LISTER_ROLE to update asset caps
* @param _assetId The asset id to update the cap for
* @param _pendingCap The pending cap in whole tokens
* @param _dailyCap The daily "accrual" to available deposits in whole tokens
* @param _precision The precision (decimals) to multiply the caps with
*/
function setAssetCap(uint256 _assetId, uint32 _pendingCap, uint32 _dailyCap, uint8 _precision)
external
onlyRole(LISTER_ROLE)
noReenter
{
caps[_assetId] = AssetCap({
available: (uint256(_dailyCap) * 10 ** _precision).toU128(),
lastUpdatedTimestamp: uint32(block.timestamp),
pendingCap: _pendingCap,
dailyCap: _dailyCap,
precision: _precision
});
emit AssetCapUpdated(_assetId, _pendingCap, _dailyCap);
}
/**
* @notice A function which allows holders of the OWNER_ROLE to specify the delay before escapehatch is possible
* @param _delay the delay in seconds between last rollup by a provider, and escape hatch being possible
*/
function setDelayBeforeEscapeHatch(uint32 _delay) external onlyRole(OWNER_ROLE) noReenter {
delayBeforeEscapeHatch = _delay;
emit DelayBeforeEscapeHatchUpdated(_delay);
}
/**
* @notice A function which allows holders of OWNER_ROLE to set the address of the PLONK verification smart
* ( contract
* @param _verifier an address of the verification smart contract
*/
function setVerifier(address _verifier) public override (IRollupProcessor) onlyRole(OWNER_ROLE) noReenter {
if (_verifier.code.length == 0) {
revert INVALID_ADDRESS_NO_CODE();
}
rollupState.verifier = IVerifier(_verifier);
emit VerifierUpdated(_verifier);
}
/**
* @notice A function which allows holders of OWNER_ROLE to set `allowThirdPartyContracts` flag
* @param _allowThirdPartyContracts A flag indicating true if allowing third parties to register, false otherwise
*/
function setAllowThirdPartyContracts(bool _allowThirdPartyContracts)
external
override (IRollupProcessor)
onlyRole(OWNER_ROLE)
noReenter
{
allowThirdPartyContracts = _allowThirdPartyContracts;
emit AllowThirdPartyContractsUpdated(_allowThirdPartyContracts);
}
/**
* @notice A function which allows holders of OWNER_ROLE to set address of `DefiBridgeProxy` contract
* @param _defiBridgeProxy an address of `DefiBridgeProxy` contract
*/
function setDefiBridgeProxy(address _defiBridgeProxy)
public
override (IRollupProcessor)
onlyRole(OWNER_ROLE)
noReenter
{
if (_defiBridgeProxy.code.length == 0) {
revert INVALID_ADDRESS_NO_CODE();
}
defiBridgeProxy = _defiBridgeProxy;
emit DefiBridgeProxyUpdated(_defiBridgeProxy);
}
/**
* @notice Registers an ERC20 token as a supported asset
* @param _token address of the ERC20 token
* @param _gasLimit gas limit used when transferring the token (in withdraw or transferFee)
*/
function setSupportedAsset(address _token, uint256 _gasLimit)
external
override (IRollupProcessor)
whenNotPaused
checkThirdPartyContractStatus
noReenter
{
if (_token.code.length == 0) {
revert INVALID_ADDRESS_NO_CODE();
}
if (_gasLimit < MIN_ERC20_GAS_LIMIT || _gasLimit > MAX_ERC20_GAS_LIMIT) {
revert INVALID_ASSET_GAS();
}
supportedAssets.push(_token);
uint256 assetId = supportedAssets.length;
assetGasLimits[assetId] = _gasLimit;
emit AssetAdded(assetId, _token, assetGasLimits[assetId]);
}
/**
* @dev Appends a bridge contract to the supportedBridges
* @param _bridge address of the bridge contract
* @param _gasLimit gas limit forwarded to the DefiBridgeProxy to perform convert
*/
function setSupportedBridge(address _bridge, uint256 _gasLimit)
external
override (IRollupProcessor)
whenNotPaused
checkThirdPartyContractStatus
noReenter
{
if (_bridge.code.length == 0) {
revert INVALID_ADDRESS_NO_CODE();
}
if (_gasLimit < MIN_BRIDGE_GAS_LIMIT || _gasLimit > MAX_BRIDGE_GAS_LIMIT) {
revert INVALID_BRIDGE_GAS();
}
supportedBridges.push(_bridge);
uint256 bridgeAddressId = supportedBridges.length;
bridgeGasLimits[bridgeAddressId] = _gasLimit;
emit BridgeAdded(bridgeAddressId, _bridge, bridgeGasLimits[bridgeAddressId]);
}
/**
* @notice A function which processes a rollup
* @dev Rollup processing consists of decoding a rollup, verifying the corresponding proof and updating relevant
* state variables
* @dev The `encodedProofData` is unnamed param as we are reading it directly from calldata when decoding
* and creating the `proofData` in `Decoder::decodeProof()`.
* @dev For the rollup to be processed `msg.sender` has to be an authorised rollup provider or escape hatch has
* to be open
* @dev This function always transfers fees to the `rollupBeneficiary` encoded in the proof data
*
* @param - cryptographic proof data associated with a rollup
* @param _signatures a byte array of secp256k1 ECDSA signatures, authorising a transfer of tokens from
* the publicOwner for the particular inner proof in question
*
* Structure of each signature in the bytes array is:
* 0x00 - 0x20 : r
* 0x20 - 0x40 : s
* 0x40 - 0x60 : v (in form: 0x0000....0001b for example)
*/
function processRollup(bytes calldata, /* encodedProofData */ bytes calldata _signatures)
external
override (IRollupProcessor)
whenNotPaused
allowAsyncReenter
{
if (rollupProviders[msg.sender]) {
if (rollupState.capped) {
lastRollupTimeStamp = uint32(block.timestamp);
}
} else {
(bool isOpen,) = getEscapeHatchStatus();
if (!isOpen) {
revert INVALID_PROVIDER();
}
}
(bytes memory proofData, uint256 numTxs, uint256 publicInputsHash) = decodeProof();
address rollupBeneficiary = extractRollupBeneficiary(proofData);
processRollupProof(proofData, _signatures, numTxs, publicInputsHash, rollupBeneficiary);
transferFee(proofData, rollupBeneficiary);
}
/*----------------------------------------
PUBLIC/EXTERNAL MUTATING FUNCTIONS
----------------------------------------*/
/**
* @notice A function used by bridges to send ETH to the RollupProcessor during an interaction
* @param _interactionNonce an interaction nonce that used as an ID of this payment
*/
function receiveEthFromBridge(uint256 _interactionNonce) external payable override (IRollupProcessor) {
assembly {
// ethPayments[interactionNonce] += msg.value
mstore(0x00, _interactionNonce)
mstore(0x20, ethPayments.slot)
let slot := keccak256(0x00, 0x40)
// no need to check for overflows as this would require sending more than the blockchain's total supply of ETH!
sstore(slot, add(sload(slot), callvalue()))
}
}
/**
* @notice A function which approves a proofHash to spend the user's pending deposited funds
* @dev this function is one way and must be called by the owner of the funds
* @param _proofHash keccak256 hash of the inner proof public inputs
*/
function approveProof(bytes32 _proofHash) public override (IRollupProcessor) whenNotPaused {
// asm implementation to reduce compiled bytecode size
assembly {
// depositProofApprovals[msg.sender][_proofHash] = true;
mstore(0x00, caller())
mstore(0x20, depositProofApprovals.slot)
mstore(0x20, keccak256(0x00, 0x40))
mstore(0x00, _proofHash)
sstore(keccak256(0x00, 0x40), 1)
}
}
/**
* @notice A function which deposits funds to the contract
* @dev This is the first stage of a 2 stage deposit process. In the second stage funds are claimed by the user on
* L2.
* @param _assetId asset ID which was assigned during asset registration
* @param _amount token deposit amount
* @param _owner address that can spend the deposited funds
* @param _proofHash 32 byte transaction id that can spend the deposited funds
*/
function depositPendingFunds(uint256 _assetId, uint256 _amount, address _owner, bytes32 _proofHash)
external
payable
override (IRollupProcessor)
whenNotPaused
noReenter
{
// Perform sanity checks on user input
if (_assetId == ETH_ASSET_ID && msg.value != _amount) {
revert MSG_VALUE_WRONG_AMOUNT();
}
if (_assetId != ETH_ASSET_ID && msg.value != 0) {
revert DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE();
}
increasePendingDepositBalance(_assetId, _owner, _amount);
if (_proofHash != 0) approveProof(_proofHash);
emit Deposit(_assetId, _owner, _amount);
if (_assetId != ETH_ASSET_ID) {
address assetAddress = getSupportedAsset(_assetId);
// check user approved contract to transfer funds, so can throw helpful error to user
if (IERC20(assetAddress).allowance(msg.sender, address(this)) < _amount) {
revert INSUFFICIENT_TOKEN_APPROVAL();
}
TokenTransfers.safeTransferFrom(assetAddress, msg.sender, address(this), _amount);
}
}
/**
* @notice A function used to publish data that doesn't need to be accessible on-chain
* @dev This function can be called multiple times to work around maximum tx size limits
* @dev The data is expected to be reconstructed by the client
* @param _rollupId rollup id this data is related to
* @param _chunk the chunk number, from 0 to totalChunks-1.
* @param _totalChunks the total number of chunks.
* @param - the data
*/
function offchainData(uint256 _rollupId, uint256 _chunk, uint256 _totalChunks, bytes calldata /* offchainTxData */ )
external
override (IRollupProcessor)
whenNotPaused
{
emit OffchainData(_rollupId, _chunk, _totalChunks, msg.sender);
}
/**
* @notice A function which process async bridge interaction
* @param _interactionNonce unique id of the interaction
* @return true if successful, false otherwise
*/
function processAsyncDefiInteraction(uint256 _interactionNonce)
external
override (IRollupProcessor)
whenNotPaused
noReenterButAsync
returns (bool)
{
uint256 encodedBridgeCallData;
uint256 totalInputValue;
assembly {
mstore(0x00, _interactionNonce)
mstore(0x20, pendingDefiInteractions.slot)
let interactionPtr := keccak256(0x00, 0x40)
encodedBridgeCallData := sload(interactionPtr)
totalInputValue := sload(add(interactionPtr, 0x01))
}
if (encodedBridgeCallData == 0) {
revert INVALID_BRIDGE_CALL_DATA();
}
FullBridgeCallData memory fullBridgeCallData = getFullBridgeCallData(encodedBridgeCallData);
(
AztecTypes.AztecAsset memory inputAssetA,
AztecTypes.AztecAsset memory inputAssetB,
AztecTypes.AztecAsset memory outputAssetA,
AztecTypes.AztecAsset memory outputAssetB
) = getAztecAssetTypes(fullBridgeCallData, _interactionNonce);
// Extract the bridge address from the encodedBridgeCallData
IDefiBridge bridgeContract;
assembly {
mstore(0x00, supportedBridges.slot)
let bridgeSlot := keccak256(0x00, 0x20)
bridgeContract := and(encodedBridgeCallData, 0xffffffff)
bridgeContract := sload(add(bridgeSlot, sub(bridgeContract, 0x01)))
bridgeContract := and(bridgeContract, ADDRESS_MASK)
}
if (address(bridgeContract) == address(0)) {
revert INVALID_BRIDGE_ADDRESS();
}
// delete pendingDefiInteractions[interactionNonce]
// N.B. only need to delete 1st slot value `encodedBridgeCallData`. Deleting vars costs gas post-London
// setting encodedBridgeCallData to 0 is enough to cause future calls with this interaction nonce to fail
pendingDefiInteractions[_interactionNonce].encodedBridgeCallData = 0;
// Copy some variables to front of stack to get around stack too deep errors
InteractionInputs memory inputs =
InteractionInputs(totalInputValue, _interactionNonce, uint64(fullBridgeCallData.auxData));
(uint256 outputValueA, uint256 outputValueB, bool interactionCompleted) = bridgeContract.finalise(
inputAssetA, inputAssetB, outputAssetA, outputAssetB, inputs.interactionNonce, inputs.auxData
);
if (!interactionCompleted) {
pendingDefiInteractions[inputs.interactionNonce].encodedBridgeCallData = encodedBridgeCallData;
return false;
}
if (outputValueB > 0 && outputAssetB.assetType == AztecTypes.AztecAssetType.NOT_USED) {
revert NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET(outputValueB);
}
if (outputValueA == 0 && outputValueB == 0) {
// issue refund.
transferTokensAsync(address(bridgeContract), inputAssetA, inputs.totalInputValue, inputs.interactionNonce);
transferTokensAsync(address(bridgeContract), inputAssetB, inputs.totalInputValue, inputs.interactionNonce);
} else {
// transfer output tokens to rollup contract
transferTokensAsync(address(bridgeContract), outputAssetA, outputValueA, inputs.interactionNonce);
transferTokensAsync(address(bridgeContract), outputAssetB, outputValueB, inputs.interactionNonce);
}
// compute defiInteractionHash and push it onto the asyncDefiInteractionHashes array
bool result;
assembly {
// Load values from `input` (to get around stack too deep)
let inputValue := mload(inputs)
let nonce := mload(add(inputs, 0x20))
result := iszero(and(eq(outputValueA, 0), eq(outputValueB, 0)))
// Compute defi interaction hash
let mPtr := mload(0x40)
mstore(mPtr, encodedBridgeCallData)
mstore(add(mPtr, 0x20), nonce)
mstore(add(mPtr, 0x40), inputValue)
mstore(add(mPtr, 0x60), outputValueA)
mstore(add(mPtr, 0x80), outputValueB)
mstore(add(mPtr, 0xa0), result)
pop(staticcall(gas(), 0x2, mPtr, 0xc0, 0x00, 0x20))
let defiInteractionHash := mod(mload(0x00), CIRCUIT_MODULUS)
// Load sync and async array lengths from rollup state
let state := sload(rollupState.slot)
// asyncArrayLen = rollupState.numAsyncDefiInteractionHashes
let asyncArrayLen := and(ARRAY_LENGTH_MASK, shr(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, state))
// defiArrayLen = rollupState.numDefiInteractionHashes
let defiArrayLen := and(ARRAY_LENGTH_MASK, shr(DEFIINTERACTIONHASHES_BIT_OFFSET, state))
// check that size of asyncDefiInteractionHashes isn't such that
// adding 1 to it will make the next block's defiInteractionHashes length hit 512
if gt(add(add(1, asyncArrayLen), defiArrayLen), 512) {
mstore(0, ARRAY_OVERFLOW_SELECTOR)
revert(0, 0x4)
}
// asyncDefiInteractionHashes[asyncArrayLen] = defiInteractionHash
mstore(0x00, asyncArrayLen)
mstore(0x20, asyncDefiInteractionHashes.slot)
sstore(keccak256(0x00, 0x40), defiInteractionHash)
// increase asyncDefiInteractionHashes.length by 1
let oldState := and(not(shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
let newState := or(oldState, shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, add(asyncArrayLen, 0x01)))
sstore(rollupState.slot, newState)
}
emit DefiBridgeProcessed(
encodedBridgeCallData,
inputs.interactionNonce,
inputs.totalInputValue,
outputValueA,
outputValueB,
result,
""
);
return true;
}
/*----------------------------------------
INTERNAL/PRIVATE MUTATING FUNCTIONS
----------------------------------------*/
/**
* @notice A function which increasees pending deposit amount in the `userPendingDeposits` mapping
* @dev Implemented in assembly in order to reduce compiled bytecode size and improve gas costs
* @param _assetId asset ID which was assigned during asset registration
* @param _owner address that can spend the deposited funds
* @param _amount deposit token amount
*/
function increasePendingDepositBalance(uint256 _assetId, address _owner, uint256 _amount)
internal
validateAssetIdIsNotVirtual(_assetId)
{
uint256 pending = userPendingDeposits[_assetId][_owner];
if (rollupState.capped) {
AssetCap memory cap = caps[_assetId];
uint256 precision = 10 ** cap.precision;
if (cap.pendingCap == 0 || pending + _amount > uint256(cap.pendingCap) * precision) {
revert PENDING_CAP_SURPASSED();
}
if (cap.dailyCap == 0) {
revert DAILY_CAP_SURPASSED();
} else {
// Increase the available amount, capped by dailyCap
uint256 capVal = uint256(cap.dailyCap) * precision;
uint256 rate = capVal / 1 days;
cap.available += (rate * (block.timestamp - cap.lastUpdatedTimestamp)).toU128();
if (cap.available > capVal) {
cap.available = capVal.toU128();
}
if (_amount > cap.available) {
revert DAILY_CAP_SURPASSED();
}
// Update available and timestamp
cap.available -= _amount.toU128();
cap.lastUpdatedTimestamp = uint32(block.timestamp);
caps[_assetId] = cap;
}
}
userPendingDeposits[_assetId][_owner] = pending + _amount;
}
/**
* @notice A function which decreases pending deposit amount in the `userPendingDeposits` mapping
* @dev Implemented in assembly in order to reduce compiled bytecode size and improve gas costs
* @param _assetId asset ID which was assigned during asset registration
* @param _owner address that owns the pending deposit
* @param _amount amount of tokens to decrease pending by
*/
function decreasePendingDepositBalance(uint256 _assetId, address _owner, uint256 _amount)
internal
validateAssetIdIsNotVirtual(_assetId)
{
bool insufficientDeposit = false;
assembly {
// userPendingDeposit = userPendingDeposits[_assetId][_owner]
mstore(0x00, _assetId)
mstore(0x20, userPendingDeposits.slot)
mstore(0x20, keccak256(0x00, 0x40))
mstore(0x00, _owner)
let userPendingDepositSlot := keccak256(0x00, 0x40)
let userPendingDeposit := sload(userPendingDepositSlot)
insufficientDeposit := lt(userPendingDeposit, _amount)
let newDeposit := sub(userPendingDeposit, _amount)
sstore(userPendingDepositSlot, newDeposit)
}
if (insufficientDeposit) {
revert INSUFFICIENT_DEPOSIT();
}
}
/**
* @notice A function that processes a rollup proof
* @dev Processing a rollup proof consists of:
* 1) Verifying the proof's correctness,
* 2) using the provided proof data to update rollup state + merkle roots,
* 3) validate/enacting any deposits/withdrawals,
* 4) processing bridge calls.
* @param _proofData decoded rollup proof data
* @param _signatures ECDSA signatures from users authorizing deposit transactions
* @param _numTxs the number of transactions in the block
* @param _publicInputsHash the SHA256 hash of the proof's public inputs
* @param _rollupBeneficiary The address to be paid any subsidy for bridge calls and rollup fees
*/
function processRollupProof(
bytes memory _proofData,
bytes memory _signatures,
uint256 _numTxs,
uint256 _publicInputsHash,
address _rollupBeneficiary
) internal {
uint256 rollupId = verifyProofAndUpdateState(_proofData, _publicInputsHash);
processDepositsAndWithdrawals(_proofData, _numTxs, _signatures);
bytes32[] memory nextDefiHashes = processBridgeCalls(_proofData, _rollupBeneficiary);
emit RollupProcessed(rollupId, nextDefiHashes, msg.sender);
}
/**
* @notice A function which verifies zk proof and updates the contract's state variables
* @dev encodedProofData is read from calldata passed into the transaction and differs from `_proofData`
* @param _proofData decoded rollup proof data
* @param _publicInputsHash a hash of public inputs (computed by `Decoder.sol`)
* @return rollupId id of the rollup which is being processed
*/
function verifyProofAndUpdateState(bytes memory _proofData, uint256 _publicInputsHash)
internal
returns (uint256 rollupId)
{
// Verify the rollup proof.
//
// We manually call the verifier contract via assembly to save on gas costs and to reduce contract bytecode size
assembly {
/**
* Validate correctness of zk proof.
*
* 1st Item is to format verifier calldata.
*
*/
// The `encodedProofData` (in calldata) contains the concatenation of
// encoded 'broadcasted inputs' and the actual zk proof data.
// (The `boadcasted inputs` is converted into a 32-byte SHA256 hash, which is
// validated to equal the first public inputs of the zk proof. This is done in `Decoder.sol`).
// We need to identify the location in calldata that points to the start of the zk proof data.
// Step 1: compute size of zk proof data and its calldata pointer.
/**
* Data layout for `bytes encodedProofData`...
*
* 0x00 : 0x20 : length of array
* 0x20 : 0x20 + header : root rollup header data
* 0x20 + header : 0x24 + header : X, the length of encoded inner join-split public inputs
* 0x24 + header : 0x24 + header + X : (inner join-split public inputs)
* 0x24 + header + X : 0x28 + header + X : Y, the length of the zk proof data
* 0x28 + header + X : 0x28 + haeder + X + Y : zk proof data
*
* We need to recover the numeric value of `0x28 + header + X` and `Y`
*
*/
// Begin by getting length of encoded inner join-split public inputs.
// `calldataload(0x04)` points to start of bytes array. Add 0x24 to skip over length param and function signature.
// The calldata param 4 bytes *after* the header is the length of the pub inputs array. However it is a packed 4-byte param.
// To extract it, we subtract 24 bytes from the calldata pointer and mask off all but the 4 least significant bytes.
let encodedInnerDataSize :=
and(calldataload(add(add(calldataload(0x04), 0x24), sub(ROLLUP_HEADER_LENGTH, 0x18))), 0xffffffff)
// add 8 bytes to skip over the two packed params that follow the rollup header data
// broadcastedDataSize = inner join-split pubinput size + header size
let broadcastedDataSize := add(add(ROLLUP_HEADER_LENGTH, 8), encodedInnerDataSize)
// Compute zk proof data size by subtracting broadcastedDataSize from overall length of bytes encodedProofsData
let zkProofDataSize := sub(calldataload(add(calldataload(0x04), 0x04)), broadcastedDataSize)
// Compute calldata pointer to start of zk proof data by adding calldata offset to broadcastedDataSize
// (+0x24 skips over function signature and length param of bytes encodedProofData)
let zkProofDataPtr := add(broadcastedDataSize, add(calldataload(0x04), 0x24))
// Step 2: Format calldata for verifier contract call.
// Get free memory pointer - we copy calldata into memory starting here
let dataPtr := mload(0x40)
// 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 : publicInputsHash
// 0x44 - .... : proofData
mstore8(dataPtr, 0xac)
mstore8(add(dataPtr, 0x01), 0x31)
mstore8(add(dataPtr, 0x02), 0x8c)
mstore8(add(dataPtr, 0x03), 0x5d)
mstore(add(dataPtr, 0x04), 0x40)
mstore(add(dataPtr, 0x24), _publicInputsHash)
mstore(add(dataPtr, 0x44), zkProofDataSize) // length of zkProofData bytes array
calldatacopy(add(dataPtr, 0x64), zkProofDataPtr, zkProofDataSize) // copy the zk proof data into memory
// Step 3: Call our verifier contract. It 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
let verifierAddress := and(sload(rollupState.slot), ADDRESS_MASK)
if iszero(extcodesize(verifierAddress)) {
mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
revert(0, 0x4)
}
let proof_verified := staticcall(gas(), verifierAddress, dataPtr, add(zkProofDataSize, 0x64), 0x00, 0x00)
// Check the proof is valid!
if iszero(proof_verified) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
// Validate and update state hash
rollupId = validateAndUpdateMerkleRoots(_proofData);
}
/**
* @notice Extracts roots from public inputs and validate that they are inline with current contract `rollupState`
* @param _proofData decoded rollup proof data
* @return rollup id
* @dev To make the circuits happy, we want to only insert at the next subtree. The subtrees that we are using are
* 28 leafs in size. They could be smaller but we just want them to be of same size for circuit related
* reasons.
* When we have the case that the `storedDataSize % numDataLeaves == 0`, we are perfectly dividing. This
* means that the incoming rollup matches perfectly with a boundry of the next subtree.
* When this is not the case, we have to compute an offset that we then apply so that the full state can
* be build with a bunch of same-sized trees (when the rollup is not full we insert a tree with some zero
* leaves). This offset can be computed as `numDataLeaves - (storedDataSize % numDataLeaves)` and is,
* essentially, how big a "space" we should leave so that the currently inserted subtree ends exactly at
* the subtree boundry. The value is always >= 0. In the function below we won’t hit the zero case, because
* that would be cought by the "if-branch".
*
* Example: We have just had 32 rollups of size 28 (`storedDataSize = 896`). Now there is a small rollup with
* only 6 transactions. We are not perfectly dividing, hence we compute the offset as `6 - 896 % 6 = 4`.
* The start index is `896 + 4 = 900`. With the added leaves, the stored data size now becomes `906`.
* Now, comes another full rollup (28 txs). We compute `906 % 28 = 10`. The value is non-zero which means
* that we don’t perfectly divide and have to compute an offset `28 - 906 % 28 = 18`. The start index is
* `906 + 18 = 924`. Notice that `924 % 28 == 0`, so this will land us exactly at a location where everything
* in the past could have been subtrees of size 28.
*/
function validateAndUpdateMerkleRoots(bytes memory _proofData) internal returns (uint256) {
(uint256 rollupId, bytes32 oldStateHash, bytes32 newStateHash, uint32 numDataLeaves, uint32 dataStartIndex) =
computeRootHashes(_proofData);
if (oldStateHash != rollupStateHash) {
revert INCORRECT_STATE_HASH(oldStateHash, newStateHash);
}
unchecked {
uint32 storedDataSize = rollupState.datasize;
// Ensure we are inserting at the next subtree boundary.
if (storedDataSize % numDataLeaves == 0) {
if (dataStartIndex != storedDataSize) {
revert INCORRECT_DATA_START_INDEX(dataStartIndex, storedDataSize);
}
} else {
uint256 expected = storedDataSize + numDataLeaves - (storedDataSize % numDataLeaves);
if (dataStartIndex != expected) {
revert INCORRECT_DATA_START_INDEX(dataStartIndex, expected);
}
}
rollupStateHash = newStateHash;
rollupState.datasize = dataStartIndex + numDataLeaves;
}
return rollupId;
}
/**
* @notice A function which processes deposits and withdrawls
* @param _proofData decoded rollup proof data
* @param _numTxs number of transactions rolled up in the proof
* @param _signatures byte 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;
uint256 end;
assembly {
// add 0x20 to skip over 1st member of the bytes type (the length field).
// Also skip over the rollup header.
proofDataPtr := add(ROLLUP_HEADER_LENGTH, add(_proofData, 0x20))
// compute the position of proofDataPtr after we iterate through every transaction
end := add(proofDataPtr, mul(_numTxs, TX_PUBLIC_INPUT_LENGTH))
}
// 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 publicValue;
assembly {
publicValue := mload(add(proofDataPtr, 0xa0))
}
if (publicValue > 0) {
uint256 proofId;
uint256 assetId;
address publicOwner;
assembly {
proofId := mload(proofDataPtr)
assetId := mload(add(proofDataPtr, 0xe0))
publicOwner := mload(add(proofDataPtr, 0xc0))
}
if (proofId == 1) {
// validate user has approved deposit
bytes32 digest;
assembly {
// compute the tx id to check if user has approved tx
digest := keccak256(proofDataPtr, TX_PUBLIC_INPUT_LENGTH)
}
// check if there is an existing entry in depositProofApprovals
// if there is, no further work required.
// we don't need to clear `depositProofApprovals[publicOwner][digest]` because proofs cannot be re-used.
// A single proof describes the creation of 2 output notes and the addition of 2 input note nullifiers
// (both of these nullifiers can be categorised as "fake". They may not map to existing notes but are still inserted in the nullifier set)
// Replaying the proof will fail to satisfy the rollup circuit's non-membership check on the input nullifiers.
// We avoid resetting `depositProofApprovals` because that would cost additional gas post-London hard fork.
if (!depositProofApprovals[publicOwner][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 (96)
// 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 96-byte 'length' parameter into the `signature` bytes array
mstore(signature, 0x60)
}
bytes32 hashedMessage = RollupProcessorLibrary.getSignedMessageForTxId(digest);
RollupProcessorLibrary.validateShieldSignatureUnpacked(hashedMessage, signature, publicOwner);
// restore the memory we overwrote
assembly {
mstore(signature, temp)
sigIndex := add(sigIndex, 0x60)
}
}
decreasePendingDepositBalance(assetId, publicOwner, publicValue);
}
if (proofId == 2) {
withdraw(publicValue, publicOwner, assetId);
}
}
// don't check for overflow, would take > 2^200 iterations of this loop for that to happen!
unchecked {
proofDataPtr += TX_PUBLIC_INPUT_LENGTH;
}
}
}
/**
* @notice A function which pulls tokens from a bridge
* @dev Calls `transferFrom` if asset is of type ERC20. If asset is ETH we validate a payment has been made
* against the provided interaction nonce. This function is used by `processAsyncDefiInteraction`.
* @param _bridge address of bridge contract we're transferring tokens from
* @param _asset the AztecAsset being transferred
* @param _outputValue the expected value transferred
* @param _interactionNonce the defi interaction nonce of the interaction
*/
function transferTokensAsync(
address _bridge,
AztecTypes.AztecAsset memory _asset,
uint256 _outputValue,
uint256 _interactionNonce
) internal {
if (_outputValue == 0) {
return;
}
if (_asset.assetType == AztecTypes.AztecAssetType.ETH) {
if (_outputValue > ethPayments[_interactionNonce]) {
revert INSUFFICIENT_ETH_PAYMENT();
}
ethPayments[_interactionNonce] = 0;
} else if (_asset.assetType == AztecTypes.AztecAssetType.ERC20) {
address tokenAddress = _asset.erc20Address;
TokenTransfers.safeTransferFrom(tokenAddress, _bridge, address(this), _outputValue);
}
}
/**
* @notice A function which transfers fees to the `_feeReceiver`
* @dev Note: function will not revert if underlying transfers fails
* @param _proofData decoded rollup proof data
* @param _feeReceiver fee beneficiary as described by the rollup provider
*/
function transferFee(bytes memory _proofData, address _feeReceiver) internal {
for (uint256 i = 0; i < NUMBER_OF_ASSETS;) {
uint256 txFee = extractTotalTxFee(_proofData, i);
if (txFee > 0) {
uint256 assetId = extractFeeAssetId(_proofData, i);
if (assetId == ETH_ASSET_ID) {
// We explicitly do not throw if this call fails, as this opens up the possiblity of griefing
// attacks --> engineering a failed fee would invalidate an entire rollup block. As griefing could
// be done by consuming all gas in the `_feeReceiver` fallback only 50K gas is forwarded. We are
// forwarding a bit more gas than in the withdraw function because this code will only be hit
// at most once each rollup-block and we want to give the provider a bit more flexibility.
assembly {
pop(call(50000, _feeReceiver, txFee, 0, 0, 0, 0))
}
} else {
address assetAddress = getSupportedAsset(assetId);
TokenTransfers.transferToDoNotBubbleErrors(
assetAddress, _feeReceiver, txFee, assetGasLimits[assetId]
);
}
}
unchecked {
++i;
}
}
}
/**
* @notice Internal utility function which withdraws funds from the contract to a receiver address
* @param _withdrawValue - value being withdrawn from the contract
* @param _receiver - address receiving public ERC20 tokens
* @param _assetId - ID of the asset for which a withdrawal is being performed
* @dev The function doesn't throw if the inner call fails, as this opens up the possiblity of griefing attacks
* -> engineering a failed withdrawal would invalidate an entire rollup block.
* A griefing attack could be done by consuming all gas in the `_receiver` fallback and for this reason we
* only forward 30K gas. This still allows the recipient to handle accounting if recipient is a contract.
* The user should ensure their withdrawal will succeed or they will lose the funds.
*/
function withdraw(uint256 _withdrawValue, address _receiver, uint256 _assetId) internal {
if (_receiver == address(0)) {
revert WITHDRAW_TO_ZERO_ADDRESS();
}
if (_assetId == 0) {
assembly {
pop(call(30000, _receiver, _withdrawValue, 0, 0, 0, 0))
}
// payable(_receiver).call{gas: 30000, value: _withdrawValue}('');
} else {
address assetAddress = getSupportedAsset(_assetId);
TokenTransfers.transferToDoNotBubbleErrors(
assetAddress, _receiver, _withdrawValue, assetGasLimits[_assetId]
);
}
}
/*----------------------------------------
PUBLIC/EXTERNAL NON-MUTATING FUNCTIONS
----------------------------------------*/
/**
* @notice Get implementation's version number
* @return version version number of the implementation
*/
function getImplementationVersion() public view virtual returns (uint8 version) {
return 2;
}
/**
* @notice Get true if the contract is paused, false otherwise
* @return isPaused - True if paused, false otherwise
*/
function paused() external view override (IRollupProcessor) returns (bool isPaused) {
return rollupState.paused;
}
/**
* @notice Gets the number of filled entries in the data tree
* @return dataSize number of filled entries in the data tree (equivalent to the number of notes created on L2)
*/
function getDataSize() public view override (IRollupProcessor) returns (uint256 dataSize) {
return rollupState.datasize;
}
/**
* @notice Returns true if deposits are capped, false otherwise
* @return capped - True if deposits are capped, false otherwise
*/
function getCapped() public view override (IRollupProcessorV2) returns (bool capped) {
return rollupState.capped;
}
/**
* @notice Gets the number of pending defi interactions that have resolved but have not yet been added into the
* DeFi tree
* @return - the number of pending interactions
* @dev This value can never exceed 512. This limit is set in order to prevent griefing attacks - `processRollup`
* iterates through `asyncDefiInteractionHashes` and copies their values into `defiInteractionHashes`. Loop
* is bounded to < 512 so that tx does not exceed block gas limit.
*/
function getPendingDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
return rollupState.numAsyncDefiInteractionHashes + rollupState.numDefiInteractionHashes;
}
/**
* @notice Gets the address of the PLONK verification smart contract
* @return - address of the verification smart contract
*/
function verifier() public view override (IRollupProcessor) returns (address) {
return address(rollupState.verifier);
}
/**
* @notice Gets the number of supported bridges
* @return - the number of supported bridges
*/
function getSupportedBridgesLength() external view override (IRollupProcessor) returns (uint256) {
return supportedBridges.length;
}
/**
* @notice Gets the bridge contract address for a given bridgeAddressId
* @param _bridgeAddressId identifier used to denote a particular bridge
* @return - the address of the matching bridge contract
*/
function getSupportedBridge(uint256 _bridgeAddressId) public view override (IRollupProcessor) returns (address) {
return supportedBridges[_bridgeAddressId - 1];
}
/**
* @notice Gets the number of supported assets
* @return - the number of supported assets
*/
function getSupportedAssetsLength() external view override (IRollupProcessor) returns (uint256) {
return supportedAssets.length;
}
/**
* @notice Gets the ERC20 token address of a supported asset for a given `_assetId`
* @param _assetId identifier used to denote a particular asset
* @return - the address of the matching asset
*/
function getSupportedAsset(uint256 _assetId)
public
view
override (IRollupProcessor)
validateAssetIdIsNotVirtual(_assetId)
returns (address)
{
// If assetId == ETH_ASSET_ID (i.e. 0), this represents native ETH.
// ERC20 token asset id values start at 1
if (_assetId == ETH_ASSET_ID) {
return address(0x0);
}
address result = supportedAssets[_assetId - 1];
if (result == address(0)) {
revert INVALID_ASSET_ADDRESS();
}
return result;
}
/**
* @notice Gets the status of the escape hatch.
* @return True if escape hatch is open, false otherwise
* @return The number of blocks until the next opening/closing of escape hatch
*/
function getEscapeHatchStatus() public view override (IRollupProcessor) returns (bool, uint256) {
uint256 blockNum = block.number;
bool isOpen = blockNum % escapeBlockUpperBound >= escapeBlockLowerBound;
uint256 blocksRemaining = 0;
if (isOpen) {
if (block.timestamp < uint256(lastRollupTimeStamp) + delayBeforeEscapeHatch) {
isOpen = false;
}
// 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);
}
/**
* @notice Gets the number of defi interaction hashes
* @dev A defi interaction hash represents a defi interaction that has resolved, but whose
* result data has not yet been added into the Aztec Defi Merkle tree. This step is needed in order to convert
* L2 Defi claim notes into L2 value notes.
* @return - the number of pending defi interaction hashes
*/
function getDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
return rollupState.numDefiInteractionHashes;
}
/**
* @notice Gets the number of asynchronous defi interaction hashes
* @dev A defi interaction hash represents an asynchronous defi interaction that has resolved, but whose interaction
* result data has not yet been added into the Aztec Defi Merkle tree. This step is needed in order to convert
* L2 Defi claim notes into L2 value notes.
* @return - the number of pending async defi interaction hashes
*/
function getAsyncDefiInteractionHashesLength() public view override (IRollupProcessor) returns (uint256) {
return rollupState.numAsyncDefiInteractionHashes;
}
/*----------------------------------------
INTERNAL/PRIVATE NON-MUTATING FUNCTIONS
----------------------------------------*/
/**
* @notice A function which constructs a FullBridgeCallData struct based on values from `_encodedBridgeCallData`
* @param _encodedBridgeCallData a bit-array that contains data describing a specific bridge call
*
* Structure of the bit array is as follows (starting at the least significant bit):
* | bit range | parameter | description |
* | 0 - 32 | bridgeAddressId | The address ID. Bridge address = `supportedBridges[bridgeAddressId]` |
* | 32 - 62 | inputAssetIdA | First input asset ID. |
* | 62 - 92 | inputAssetIdB | Second input asset ID. Must be 0 if bridge does not have a 2nd input asset. |
* | 92 - 122 | outputAssetIdA | First output asset ID. |
* | 122 - 152 | outputAssetIdB | Second output asset ID. Must be 0 if bridge does not have a 2nd output asset. |
* | 152 - 184 | bitConfig | Bit-array that contains boolean bridge settings. |
* | 184 - 248 | auxData | 64 bits of custom data to be passed to the bridge contract. Structure of auxData
* is defined/checked by the bridge contract. |
*
* Structure of the `bitConfig` parameter is as follows
* | bit | parameter | description |
* | 0 | secondInputInUse | Does the bridge have a second input asset? |
* | 1 | secondOutputInUse | Does the bridge have a second output asset? |
*
* @dev Note: Virtual assets are assets that don't have an ERC20 token analogue and exist solely as notes within
* the Aztec network. They can be created/spent within bridge calls. They are used to enable bridges
* to track internally-defined data without having to mint a new token on-chain. An example use of
* a virtual asset would be a virtual loan asset that tracks an outstanding debt that must be repaid
* to recover a collateral deposited into the bridge.
*
* @return fullBridgeCallData a struct that contains information defining a specific bridge call
*/
function getFullBridgeCallData(uint256 _encodedBridgeCallData)
internal
view
returns (FullBridgeCallData memory fullBridgeCallData)
{
assembly {
mstore(fullBridgeCallData, and(_encodedBridgeCallData, MASK_THIRTY_TWO_BITS)) // bridgeAddressId
mstore(
add(fullBridgeCallData, 0x40),
and(shr(INPUT_ASSET_ID_A_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
) // inputAssetIdA
mstore(
add(fullBridgeCallData, 0x60),
and(shr(INPUT_ASSET_ID_B_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
) // inputAssetIdB
mstore(
add(fullBridgeCallData, 0x80),
and(shr(OUTPUT_ASSET_ID_A_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
) // outputAssetIdA
mstore(
add(fullBridgeCallData, 0xa0),
and(shr(OUTPUT_ASSET_ID_B_SHIFT, _encodedBridgeCallData), MASK_THIRTY_BITS)
) // outputAssetIdB
mstore(
add(fullBridgeCallData, 0xc0), and(shr(AUX_DATA_SHIFT, _encodedBridgeCallData), MASK_SIXTY_FOUR_BITS)
) // auxData
mstore(
add(fullBridgeCallData, 0xe0),
and(shr(add(INPUT_ASSET_ID_A_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
) // firstInputVirtual (30th bit of inputAssetIdA) == 1
mstore(
add(fullBridgeCallData, 0x100),
and(shr(add(INPUT_ASSET_ID_B_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
) // secondInputVirtual (30th bit of inputAssetIdB) == 1
mstore(
add(fullBridgeCallData, 0x120),
and(shr(add(OUTPUT_ASSET_ID_A_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
) // firstOutputVirtual (30th bit of outputAssetIdA) == 1
mstore(
add(fullBridgeCallData, 0x140),
and(shr(add(OUTPUT_ASSET_ID_B_SHIFT, VIRTUAL_ASSET_ID_FLAG_SHIFT), _encodedBridgeCallData), 1)
) // secondOutputVirtual (30th bit of outputAssetIdB) == 1
let bitConfig := and(shr(BITCONFIG_SHIFT, _encodedBridgeCallData), MASK_THIRTY_TWO_BITS)
// bitConfig = bit mask that contains bridge ID settings
// bit 0 = second input asset in use?
// bit 1 = second output asset in use?
mstore(add(fullBridgeCallData, 0x160), eq(and(bitConfig, 1), 1)) // secondInputInUse (bitConfig & 1) == 1
mstore(add(fullBridgeCallData, 0x180), eq(and(shr(1, bitConfig), 1), 1)) // secondOutputInUse ((bitConfig >> 1) & 1) == 1
}
fullBridgeCallData.bridgeAddress = supportedBridges[fullBridgeCallData.bridgeAddressId - 1];
fullBridgeCallData.bridgeGasLimit = bridgeGasLimits[fullBridgeCallData.bridgeAddressId];
// potential conflicting states that are explicitly ruled out by circuit constraints:
if (!fullBridgeCallData.secondInputInUse && fullBridgeCallData.inputAssetIdB > 0) {
revert INCONSISTENT_BRIDGE_CALL_DATA();
}
if (!fullBridgeCallData.secondOutputInUse && fullBridgeCallData.outputAssetIdB > 0) {
revert INCONSISTENT_BRIDGE_CALL_DATA();
}
if (
fullBridgeCallData.secondInputInUse
&& (fullBridgeCallData.inputAssetIdA == fullBridgeCallData.inputAssetIdB)
) {
revert BRIDGE_WITH_IDENTICAL_INPUT_ASSETS(fullBridgeCallData.inputAssetIdA);
}
// Outputs can both be virtual. In that case, their asset ids will both be 2 ** 29.
bool secondOutputReal = fullBridgeCallData.secondOutputInUse && !fullBridgeCallData.secondOutputVirtual;
if (secondOutputReal && fullBridgeCallData.outputAssetIdA == fullBridgeCallData.outputAssetIdB) {
revert BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS(fullBridgeCallData.outputAssetIdA);
}
}
/**
* @notice Gets the four input/output assets associated with a specific bridge call
* @param _fullBridgeCallData a struct that contains information defining a specific bridge call
* @param _interactionNonce interaction nonce of a corresponding bridge call
* @dev `_interactionNonce` param is here because it is used as an ID of output virtual asset
*
* @return inputAssetA the first input asset
* @return inputAssetB the second input asset
* @return outputAssetA the first output asset
* @return outputAssetB the second output asset
*/
function getAztecAssetTypes(FullBridgeCallData memory _fullBridgeCallData, uint256 _interactionNonce)
internal
view
returns (
AztecTypes.AztecAsset memory inputAssetA,
AztecTypes.AztecAsset memory inputAssetB,
AztecTypes.AztecAsset memory outputAssetA,
AztecTypes.AztecAsset memory outputAssetB
)
{
if (_fullBridgeCallData.firstInputVirtual) {
// asset id is a nonce of the interaction in which the virtual asset was created
inputAssetA.id = _fullBridgeCallData.inputAssetIdA - VIRTUAL_ASSET_ID_FLAG;
inputAssetA.erc20Address = address(0x0);
inputAssetA.assetType = AztecTypes.AztecAssetType.VIRTUAL;
} else {
inputAssetA.id = _fullBridgeCallData.inputAssetIdA;
inputAssetA.erc20Address = getSupportedAsset(_fullBridgeCallData.inputAssetIdA);
inputAssetA.assetType = inputAssetA.erc20Address == address(0x0)
? AztecTypes.AztecAssetType.ETH
: AztecTypes.AztecAssetType.ERC20;
}
if (_fullBridgeCallData.firstOutputVirtual) {
// use nonce as asset id.
outputAssetA.id = _interactionNonce;
outputAssetA.erc20Address = address(0x0);
outputAssetA.assetType = AztecTypes.AztecAssetType.VIRTUAL;
} else {
outputAssetA.id = _fullBridgeCallData.outputAssetIdA;
outputAssetA.erc20Address = getSupportedAsset(_fullBridgeCallData.outputAssetIdA);
outputAssetA.assetType = outputAssetA.erc20Address == address(0x0)
? AztecTypes.AztecAssetType.ETH
: AztecTypes.AztecAssetType.ERC20;
}
if (_fullBridgeCallData.secondInputVirtual) {
// asset id is a nonce of the interaction in which the virtual asset was created
inputAssetB.id = _fullBridgeCallData.inputAssetIdB - VIRTUAL_ASSET_ID_FLAG;
inputAssetB.erc20Address = address(0x0);
inputAssetB.assetType = AztecTypes.AztecAssetType.VIRTUAL;
} else if (_fullBridgeCallData.secondInputInUse) {
inputAssetB.id = _fullBridgeCallData.inputAssetIdB;
inputAssetB.erc20Address = getSupportedAsset(_fullBridgeCallData.inputAssetIdB);
inputAssetB.assetType = inputAssetB.erc20Address == address(0x0)
? AztecTypes.AztecAssetType.ETH
: AztecTypes.AztecAssetType.ERC20;
} else {
inputAssetB.id = 0;
inputAssetB.erc20Address = address(0x0);
inputAssetB.assetType = AztecTypes.AztecAssetType.NOT_USED;
}
if (_fullBridgeCallData.secondOutputVirtual) {
// use nonce as asset id.
outputAssetB.id = _interactionNonce;
outputAssetB.erc20Address = address(0x0);
outputAssetB.assetType = AztecTypes.AztecAssetType.VIRTUAL;
} else if (_fullBridgeCallData.secondOutputInUse) {
outputAssetB.id = _fullBridgeCallData.outputAssetIdB;
outputAssetB.erc20Address = getSupportedAsset(_fullBridgeCallData.outputAssetIdB);
outputAssetB.assetType = outputAssetB.erc20Address == address(0x0)
? AztecTypes.AztecAssetType.ETH
: AztecTypes.AztecAssetType.ERC20;
} else {
outputAssetB.id = 0;
outputAssetB.erc20Address = address(0x0);
outputAssetB.assetType = AztecTypes.AztecAssetType.NOT_USED;
}
}
/**
* @notice Gets the length of the defi interaction hashes array and the number of pending interactions
*
* @return defiInteractionHashesLength the complete length of the defi interaction array
* @return numPendingInteractions the current number of pending defi interactions
* @dev `numPendingInteractions` is capped at `NUMBER_OF_BRIDGE_CALLS`
*/
function getDefiHashesLengthsAndNumPendingInteractions()
internal
view
returns (uint256 defiInteractionHashesLength, uint256 numPendingInteractions)
{
assembly {
// retrieve the total length of the defi interactions array and also the number of pending interactions to a maximum of NUMBER_OF_BRIDGE_CALLS
let state := sload(rollupState.slot)
{
defiInteractionHashesLength := and(ARRAY_LENGTH_MASK, shr(DEFIINTERACTIONHASHES_BIT_OFFSET, state))
numPendingInteractions := defiInteractionHashesLength
if gt(numPendingInteractions, NUMBER_OF_BRIDGE_CALLS) {
numPendingInteractions := NUMBER_OF_BRIDGE_CALLS
}
}
}
}
/**
* @notice Gets the set of hashes that comprise the current pending interactions and nextExpectedHash
*
* @return hashes the set of valid (i.e. non-zero) hashes that comprise the pending interactions
* @return nextExpectedHash the hash of all hashes (including zero hashes) that comprise the pending interactions
*/
function getPendingAndNextExpectedHashes()
internal
view
returns (bytes32[] memory hashes, bytes32 nextExpectedHash)
{
/**
* ----------------------------------------
* Compute nextExpectedHash
* -----------------------------------------
*
* The `defiInteractionHashes` mapping emulates an array that represents the
* set of defi interactions from previous blocks that have been resolved.
*
* We need to take the interaction result data from each of the above defi interactions,
* and add that data into the Aztec L2 merkle tree that contains defi interaction results
* (the "Defi Tree". Its merkle root is one of the inputs to the storage variable `rollupStateHash`)
*
* It is the rollup provider's responsibility to perform these additions.
* In the current block being processed, the rollup provider must take these pending interaction results,
* create commitments to each result and insert each commitment into the next empty leaf of the defi tree.
*
* The following code validates that this has happened! This is how:
*
* Part 1: What are we checking?
*
* The rollup circuit will receive, as a private input from the rollup provider, the pending defi interaction
* results
* (`encodedBridgeCallData`, `totalInputValue`, `totalOutputValueA`, `totalOutputValueB`, `result`)
* The rollup circuit will compute the SHA256 hash of each interaction result (the defiInteractionHash)
* Finally the SHA256 hash of `NUMBER_OF_BRIDGE_CALLS` of these defiInteractionHash values is computed.
* (if there are fewer than `NUMBER_OF_BRIDGE_CALLS` pending defi interaction results, the SHA256 hash of
* an empty defi interaction result is used instead. i.e. all variable values are set to 0)
* The computed SHA256 hash, the `pendingDefiInteractionHash`, is one of the broadcasted values that forms
* the `publicInputsHash` public input to the rollup circuit.
* When verifying a rollup proof, this smart contract will compute `publicInputsHash` from the input calldata.
* The PLONK Verifier smart contract will then validate that our computed value for `publicInputHash` matches
* the value used when generating the rollup proof.
*
* TLDR of the above: our proof data contains a variable called `pendingDefiInteractionHash`, which is
* the CLAIMED VALUE of SHA256 hashing the SHA256 hashes of the defi interactions that have resolved but whose
* data has not yet been added into the defi tree.
*
* Part 2: How do we check `pendingDefiInteractionHash` is correct???
*
* This contract will call `DefiBridgeProxy.convert` (via delegatecall) on every new defi interaction present
* in the block. The return values from the bridge proxy contract are used to construct a defi interaction
* result. Its hash is then computed and stored in `defiInteractionHashes`.
*
* N.B. It's very important that DefiBridgeProxy does not call selfdestruct, or makes a delegatecall out to
* a contract that can selfdestruct :o
*
* Similarly, when async defi interactions resolve, the interaction result is stored in
* `asyncDefiInteractionHashes`. At the end of the processBridgeCalls function, the contents of the async array
* is copied into `defiInteractionHashes` (i.e. async interaction results are delayed by 1 rollup block.
* This is to prevent griefing attacks where the rollup state changes between the time taken for a rollup tx
* to be constructed and the rollup tx to be mined)
*
* We use the contents of `defiInteractionHashes` to reconstruct `pendingDefiInteractionHash`, and validate it
* matches the value present in calldata and therefore the value used in the rollup circuit when this block's
* rollup proof was constructed. This validates that all of the required defi interaction results were added
* into the defi tree by the rollup provider (the circuit logic enforces this, we just need to check the rollup
* provider used the correct inputs)
*/
(uint256 defiInteractionHashesLength, uint256 numPendingInteractions) =
getDefiHashesLengthsAndNumPendingInteractions();
uint256 offset = defiInteractionHashesLength - numPendingInteractions;
assembly {
// allocate the output array of hashes
hashes := mload(0x40)
let hashData := add(hashes, 0x20)
// update the free memory pointer to point past the end of our array
// our array will consume 32 bytes for the length field plus NUMBER_OF_BRIDGE_BYTES for all of the hashes
mstore(0x40, add(hashes, add(NUMBER_OF_BRIDGE_BYTES, 0x20)))
// set the length of hashes to only include the non-zero hash values
// although this function will write all of the hashes into our allocated memory, we only want to return the non-zero hashes
mstore(hashes, numPendingInteractions)
// Prepare the reusable part of the defi interaction hashes slot computation
mstore(0x20, defiInteractionHashes.slot)
let i := 0
// Iterate over numPendingInteractions (will be between 0 and NUMBER_OF_BRIDGE_CALLS)
// Load defiInteractionHashes[offset + i] and store in memory
// in order to compute SHA2 hash (nextExpectedHash)
for {} lt(i, numPendingInteractions) { i := add(i, 0x01) } {
// hashData[i] = defiInteractionHashes[offset + i]
mstore(0x00, add(offset, i))
mstore(add(hashData, mul(i, 0x20)), sload(keccak256(0x00, 0x40)))
}
// If numPendingInteractions < NUMBER_OF_BRIDGE_CALLS, continue iterating up to NUMBER_OF_BRIDGE_CALLS, this time
// inserting the "zero hash", the result of sha256(emptyDefiInteractionResult)
for {} lt(i, NUMBER_OF_BRIDGE_CALLS) { i := add(i, 0x01) } {
// hashData[i] = DEFI_RESULT_ZERO_HASH
mstore(add(hashData, mul(i, 0x20)), DEFI_RESULT_ZERO_HASH)
}
pop(staticcall(gas(), 0x2, hashData, NUMBER_OF_BRIDGE_BYTES, 0x00, 0x20))
nextExpectedHash := mod(mload(0x00), CIRCUIT_MODULUS)
}
}
/**
* @notice A function that processes bridge calls.
* @dev 1. pop NUMBER_OF_BRIDGE_CALLS (if available) interaction hashes off of `defiInteractionHashes`,
* validate their hash (calculated at the end of the previous rollup and stored as
* nextExpectedDefiInteractionsHash) equals `numPendingInteractions` (this validates that rollup block
* has added these interaction results into the L2 data tree)
* 2. iterate over rollup block's new defi interactions (up to NUMBER_OF_BRIDGE_CALLS). Trigger interactions
* by calling DefiBridgeProxy contract. Record results in either `defiInteractionHashes` (for synchrohnous
* txns) or, for async txns, the `pendingDefiInteractions` mapping
* 3. copy the contents of `asyncInteractionHashes` into `defiInteractionHashes` && clear
* `asyncInteractionHashes`
* 4. calculate the next value of nextExpectedDefiInteractionsHash from the new set of defiInteractionHashes
* @param _proofData decoded rollup proof data
* @param _rollupBeneficiary the address that should be paid any subsidy for processing a bridge call
* @return nextExpectedHashes the set of non-zero hashes that comprise the current pending defi interactions
*/
function processBridgeCalls(bytes memory _proofData, address _rollupBeneficiary)
internal
returns (bytes32[] memory nextExpectedHashes)
{
uint256 defiInteractionHashesLength;
// Verify that nextExpectedDefiInteractionsHash equals the value given in the rollup
// Then remove the set of pending hashes
{
// Extract the claimed value of previousDefiInteractionHash present in the proof data
bytes32 providedDefiInteractionsHash = extractPrevDefiInteractionHash(_proofData);
// Validate the stored interactionHash matches the value used when making the rollup proof!
if (providedDefiInteractionsHash != prevDefiInteractionsHash) {
revert INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH(providedDefiInteractionsHash, prevDefiInteractionsHash);
}
uint256 numPendingInteractions;
(defiInteractionHashesLength, numPendingInteractions) = getDefiHashesLengthsAndNumPendingInteractions();
// numPendingInteraction equals the number of interactions expected to be in the given rollup
// this is the length of the defiInteractionHashes array, capped at the NUM_BRIDGE_CALLS as per the following
// numPendingInteractions = min(defiInteractionsHashesLength, numberOfBridgeCalls)
// Reduce DefiInteractionHashes.length by numPendingInteractions
defiInteractionHashesLength -= numPendingInteractions;
assembly {
// Update DefiInteractionHashes.length in storage
let state := sload(rollupState.slot)
let oldState := and(not(shl(DEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
let newState := or(oldState, shl(DEFIINTERACTIONHASHES_BIT_OFFSET, defiInteractionHashesLength))
sstore(rollupState.slot, newState)
}
}
uint256 interactionNonce = getRollupId(_proofData) * NUMBER_OF_BRIDGE_CALLS;
// ### Process bridge calls
uint256 proofDataPtr;
assembly {
proofDataPtr := add(_proofData, BRIDGE_CALL_DATAS_OFFSET)
}
BridgeResult memory bridgeResult;
assembly {
bridgeResult := mload(0x40)
mstore(0x40, add(bridgeResult, 0x80))
}
for (uint256 i = 0; i < NUMBER_OF_BRIDGE_CALLS;) {
uint256 encodedBridgeCallData;
assembly {
encodedBridgeCallData := mload(proofDataPtr)
}
if (encodedBridgeCallData == 0) {
// no more bridges to call
break;
}
uint256 totalInputValue;
assembly {
totalInputValue := mload(add(proofDataPtr, mul(0x20, NUMBER_OF_BRIDGE_CALLS)))
}
if (totalInputValue == 0) {
revert ZERO_TOTAL_INPUT_VALUE();
}
FullBridgeCallData memory fullBridgeCallData = getFullBridgeCallData(encodedBridgeCallData);
(
AztecTypes.AztecAsset memory inputAssetA,
AztecTypes.AztecAsset memory inputAssetB,
AztecTypes.AztecAsset memory outputAssetA,
AztecTypes.AztecAsset memory outputAssetB
) = getAztecAssetTypes(fullBridgeCallData, interactionNonce);
assembly {
// call the following function of DefiBridgeProxy via delegatecall...
// function convert(
// address bridgeAddress,
// AztecTypes.AztecAsset calldata inputAssetA,
// AztecTypes.AztecAsset calldata inputAssetB,
// AztecTypes.AztecAsset calldata outputAssetA,
// AztecTypes.AztecAsset calldata outputAssetB,
// uint256 totalInputValue,
// uint256 interactionNonce,
// uint256 auxInputData,
// uint256 ethPaymentsSlot,
// address rollupBeneficary
// )
// Construct the calldata we send to DefiBridgeProxy
// mPtr = memory pointer. Set to free memory location (0x40)
let mPtr := mload(0x40)
// first 4 bytes is the function signature
mstore(mPtr, DEFI_BRIDGE_PROXY_CONVERT_SELECTOR)
mPtr := add(mPtr, 0x04)
let bridgeAddress := mload(add(fullBridgeCallData, 0x20))
mstore(mPtr, bridgeAddress)
mstore(add(mPtr, 0x20), mload(inputAssetA))
mstore(add(mPtr, 0x40), mload(add(inputAssetA, 0x20)))
mstore(add(mPtr, 0x60), mload(add(inputAssetA, 0x40)))
mstore(add(mPtr, 0x80), mload(inputAssetB))
mstore(add(mPtr, 0xa0), mload(add(inputAssetB, 0x20)))
mstore(add(mPtr, 0xc0), mload(add(inputAssetB, 0x40)))
mstore(add(mPtr, 0xe0), mload(outputAssetA))
mstore(add(mPtr, 0x100), mload(add(outputAssetA, 0x20)))
mstore(add(mPtr, 0x120), mload(add(outputAssetA, 0x40)))
mstore(add(mPtr, 0x140), mload(outputAssetB))
mstore(add(mPtr, 0x160), mload(add(outputAssetB, 0x20)))
mstore(add(mPtr, 0x180), mload(add(outputAssetB, 0x40)))
mstore(add(mPtr, 0x1a0), totalInputValue)
mstore(add(mPtr, 0x1c0), interactionNonce)
let auxData := mload(add(fullBridgeCallData, 0xc0))
mstore(add(mPtr, 0x1e0), auxData)
mstore(add(mPtr, 0x200), ethPayments.slot)
mstore(add(mPtr, 0x220), _rollupBeneficiary)
// Call the bridge proxy via delegatecall!
// We want the proxy to share state with the rollup processor, as the proxy is the entity
// sending/recovering tokens from the bridge contracts. We wrap this logic in a delegatecall so that
// if the call fails (i.e. the bridge interaction fails), we can unwind bridge-interaction specific
// state changes without reverting the entire transaction.
let bridgeProxy := sload(defiBridgeProxy.slot)
if iszero(extcodesize(bridgeProxy)) {
mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
revert(0, 0x4)
}
let success :=
delegatecall(
mload(add(fullBridgeCallData, 0x1a0)), // fullBridgeCallData.bridgeGasLimit
bridgeProxy,
sub(mPtr, 0x04),
0x244,
0,
0
)
returndatacopy(mPtr, 0, returndatasize())
switch success
case 1 {
mstore(bridgeResult, mload(mPtr)) // outputValueA
mstore(add(bridgeResult, 0x20), mload(add(mPtr, 0x20))) // outputValueB
mstore(add(bridgeResult, 0x40), mload(add(mPtr, 0x40))) // isAsync
mstore(add(bridgeResult, 0x60), 1) // success
}
default {
// If the call failed, mark this interaction as failed. No tokens have been exchanged, users can
// use the "claim" circuit to recover the initial tokens they sent to the bridge
mstore(bridgeResult, 0) // outputValueA
mstore(add(bridgeResult, 0x20), 0) // outputValueB
mstore(add(bridgeResult, 0x40), 0) // isAsync
mstore(add(bridgeResult, 0x60), 0) // success
}
}
if (!fullBridgeCallData.secondOutputInUse) {
bridgeResult.outputValueB = 0;
}
// emit events and update state
assembly {
// if interaction is Async, update pendingDefiInteractions
// if interaction is synchronous, compute the interaction hash and add to defiInteractionHashes
switch mload(add(bridgeResult, 0x40))
// switch isAsync
case 1 {
let mPtr := mload(0x40)
// emit AsyncDefiBridgeProcessed(indexed encodedBridgeCallData, indexed interactionNonce, totalInputValue)
{
mstore(mPtr, totalInputValue)
log3(mPtr, 0x20, ASYNC_BRIDGE_PROCESSED_SIGHASH, encodedBridgeCallData, interactionNonce)
}
// pendingDefiInteractions[interactionNonce] = PendingDefiBridgeInteraction(encodedBridgeCallData, totalInputValue)
mstore(0x00, interactionNonce)
mstore(0x20, pendingDefiInteractions.slot)
let pendingDefiInteractionsSlotBase := keccak256(0x00, 0x40)
sstore(pendingDefiInteractionsSlotBase, encodedBridgeCallData)
sstore(add(pendingDefiInteractionsSlotBase, 0x01), totalInputValue)
}
default {
let mPtr := mload(0x40)
// prepare the data required to publish the DefiBridgeProcessed event, we will only publish it if
// isAsync == false
// async interactions that have failed, have their isAsync property modified to false above
// emit DefiBridgeProcessed(indexed encodedBridgeCallData, indexed interactionNonce, totalInputValue, outputValueA, outputValueB, success)
{
mstore(mPtr, totalInputValue)
mstore(add(mPtr, 0x20), mload(bridgeResult)) // outputValueA
mstore(add(mPtr, 0x40), mload(add(bridgeResult, 0x20))) // outputValueB
mstore(add(mPtr, 0x60), mload(add(bridgeResult, 0x60))) // success
mstore(add(mPtr, 0x80), 0xa0) // position in event data block of `bytes` object
if mload(add(bridgeResult, 0x60)) {
mstore(add(mPtr, 0xa0), 0)
log3(mPtr, 0xc0, DEFI_BRIDGE_PROCESSED_SIGHASH, encodedBridgeCallData, interactionNonce)
}
if iszero(mload(add(bridgeResult, 0x60))) {
mstore(add(mPtr, 0xa0), returndatasize())
let size := returndatasize()
let remainder := mul(iszero(iszero(size)), sub(32, mod(size, 32)))
returndatacopy(add(mPtr, 0xc0), 0, size)
mstore(add(mPtr, add(0xc0, size)), 0)
log3(
mPtr,
add(0xc0, add(size, remainder)),
DEFI_BRIDGE_PROCESSED_SIGHASH,
encodedBridgeCallData,
interactionNonce
)
}
}
// compute defiInteractionnHash
mstore(mPtr, encodedBridgeCallData)
mstore(add(mPtr, 0x20), interactionNonce)
mstore(add(mPtr, 0x40), totalInputValue)
mstore(add(mPtr, 0x60), mload(bridgeResult)) // outputValueA
mstore(add(mPtr, 0x80), mload(add(bridgeResult, 0x20))) // outputValueB
mstore(add(mPtr, 0xa0), mload(add(bridgeResult, 0x60))) // success
pop(staticcall(gas(), 0x2, mPtr, 0xc0, 0x00, 0x20))
let defiInteractionHash := mod(mload(0x00), CIRCUIT_MODULUS)
// defiInteractionHashes[defiInteractionHashesLength] = defiInteractionHash;
mstore(0x00, defiInteractionHashesLength)
mstore(0x20, defiInteractionHashes.slot)
sstore(keccak256(0x00, 0x40), defiInteractionHash)
// Increase the length of defiInteractionHashes by 1
defiInteractionHashesLength := add(defiInteractionHashesLength, 0x01)
}
// advance interactionNonce and proofDataPtr
interactionNonce := add(interactionNonce, 0x01)
proofDataPtr := add(proofDataPtr, 0x20)
}
unchecked {
++i;
}
}
assembly {
/**
* Cleanup
*
* 1. Copy asyncDefiInteractionHashes into defiInteractionHashes
* 2. Update defiInteractionHashes.length
* 2. Clear asyncDefiInteractionHashes.length
*/
let state := sload(rollupState.slot)
let asyncDefiInteractionHashesLength :=
and(ARRAY_LENGTH_MASK, shr(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, state))
// Validate we are not overflowing our 1024 array size
let arrayOverflow :=
gt(add(asyncDefiInteractionHashesLength, defiInteractionHashesLength), ARRAY_LENGTH_MASK)
// Throw an error if defiInteractionHashesLength > ARRAY_LENGTH_MASK (i.e. is >= 1024)
// should never hit this! If block `i` generates synchronous txns,
// block 'i + 1' must process them.
// Only way this array size hits 1024 is if we produce a glut of async interaction results
// between blocks. HOWEVER we ensure that async interaction callbacks fail if they would increase
// defiInteractionHashes length to be >= 512
// Still, can't hurt to check...
if arrayOverflow {
mstore(0, ARRAY_OVERFLOW_SELECTOR)
revert(0, 0x4)
}
// Now, copy async hashes into defiInteractionHashes
// Cache the free memory pointer
let freePtr := mload(0x40)
// Prepare the reusable parts of slot computation
mstore(0x20, defiInteractionHashes.slot)
mstore(0x60, asyncDefiInteractionHashes.slot)
for { let i := 0 } lt(i, asyncDefiInteractionHashesLength) { i := add(i, 1) } {
// defiInteractionHashesLength[defiInteractionHashesLength + i] = asyncDefiInteractionHashes[i]
mstore(0x00, add(defiInteractionHashesLength, i))
mstore(0x40, i)
sstore(keccak256(0x00, 0x40), sload(keccak256(0x40, 0x40)))
}
// Restore the free memory pointer
mstore(0x40, freePtr)
// clear defiInteractionHashesLength in state
state := and(not(shl(DEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
// write new defiInteractionHashesLength in state
state :=
or(
shl(
DEFIINTERACTIONHASHES_BIT_OFFSET, add(asyncDefiInteractionHashesLength, defiInteractionHashesLength)
),
state
)
// clear asyncDefiInteractionHashesLength in state
state := and(not(shl(ASYNCDEFIINTERACTIONHASHES_BIT_OFFSET, ARRAY_LENGTH_MASK)), state)
// write new state
sstore(rollupState.slot, state)
}
// now we want to extract the next set of pending defi interaction hashes and calculate their hash to store
// for the next rollup
(bytes32[] memory hashes, bytes32 nextExpectedHash) = getPendingAndNextExpectedHashes();
nextExpectedHashes = hashes;
prevDefiInteractionsHash = nextExpectedHash;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Internal function that returns the initialized version. Returns `_initialized`
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Internal function that returns the initialized version. Returns `_initializing`
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
// @dev For documentation of the functions within this interface see RollupProcessor contract
interface IRollupProcessor {
/*----------------------------------------
MUTATING FUNCTIONS
----------------------------------------*/
function pause() external;
function unpause() external;
function setRollupProvider(address _provider, bool _valid) external;
function setVerifier(address _verifier) external;
function setAllowThirdPartyContracts(bool _allowThirdPartyContracts) external;
function setDefiBridgeProxy(address _defiBridgeProxy) external;
function setSupportedAsset(address _token, uint256 _gasLimit) external;
function setSupportedBridge(address _bridge, uint256 _gasLimit) external;
function processRollup(bytes calldata _encodedProofData, bytes calldata _signatures) external;
function receiveEthFromBridge(uint256 _interactionNonce) external payable;
function approveProof(bytes32 _proofHash) external;
function depositPendingFunds(uint256 _assetId, uint256 _amount, address _owner, bytes32 _proofHash)
external
payable;
function offchainData(uint256 _rollupId, uint256 _chunk, uint256 _totalChunks, bytes calldata _offchainTxData)
external;
function processAsyncDefiInteraction(uint256 _interactionNonce) external returns (bool);
/*----------------------------------------
NON-MUTATING FUNCTIONS
----------------------------------------*/
function rollupStateHash() external view returns (bytes32);
function userPendingDeposits(uint256 _assetId, address _user) external view returns (uint256);
function defiBridgeProxy() external view returns (address);
function prevDefiInteractionsHash() external view returns (bytes32);
function paused() external view returns (bool);
function verifier() external view returns (address);
function getDataSize() external view returns (uint256);
function getPendingDefiInteractionHashesLength() external view returns (uint256);
function getDefiInteractionHashesLength() external view returns (uint256);
function getAsyncDefiInteractionHashesLength() external view returns (uint256);
function getSupportedBridge(uint256 _bridgeAddressId) external view returns (address);
function getSupportedBridgesLength() external view returns (uint256);
function getSupportedAssetsLength() external view returns (uint256);
function getSupportedAsset(uint256 _assetId) external view returns (address);
function getEscapeHatchStatus() external view returns (bool, uint256);
function assetGasLimits(uint256 _bridgeAddressId) external view returns (uint256);
function bridgeGasLimits(uint256 _bridgeAddressId) external view returns (uint256);
function allowThirdPartyContracts() external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
import {IRollupProcessor} from "./IRollupProcessor.sol";
// @dev For documentation of the functions within this interface see RollupProcessorV2 contract
interface IRollupProcessorV2 is IRollupProcessor {
function getCapped() external view returns (bool);
function defiInteractionHashes(uint256) external view returns (bytes32);
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
library AztecTypes {
enum AztecAssetType {
NOT_USED,
ETH,
ERC20,
VIRTUAL
}
struct AztecAsset {
uint256 id;
address erc20Address;
AztecAssetType assetType;
}
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
library RollupProcessorLibrary {
error SIGNATURE_ADDRESS_IS_ZERO();
error SIGNATURE_RECOVERY_FAILED();
error INVALID_SIGNATURE();
/**
* 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);
if (signer == address(0x0)) {
revert SIGNATURE_ADDRESS_IS_ZERO();
}
// 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)))
}
if (!result) {
revert SIGNATURE_RECOVERY_FAILED();
}
if (recoveredSigner != signer) {
revert 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 96-byte array.
* i.e. the `v` parameter occupies a full 32 bytes of memory, not 1 byte
* @param hashedMessage - Hashed data being signed over. This function only works if the message has been pre formated to EIP https://eips.ethereum.org/EIPS/eip-191
* @param signature - ECDSA signature over the secp256k1 elliptic curve.
* @param signer - Address that signs the signature.
*/
function validateShieldSignatureUnpacked(bytes32 hashedMessage, bytes memory signature, address signer)
internal
view
{
bool result;
address recoveredSigner = address(0x0);
if (signer == address(0x0)) {
revert SIGNATURE_ADDRESS_IS_ZERO();
}
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, hashedMessage)
// 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(hashedMessage, 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)))
}
if (!result) {
revert SIGNATURE_RECOVERY_FAILED();
}
if (recoveredSigner != signer) {
revert 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 96-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);
if (signer == address(0x0)) {
revert SIGNATURE_ADDRESS_IS_ZERO();
}
// 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)))
}
if (!result) {
revert SIGNATURE_RECOVERY_FAILED();
}
if (recoveredSigner != signer) {
revert INVALID_SIGNATURE();
}
}
/**
* Convert a bytes32 into an ASCII encoded hex string
* @param input bytes32 variable
* @return result hex-encoded string
*/
function toHexString(bytes32 input) public pure returns (string memory result) {
if (uint256(input) == 0x00) {
assembly {
result := mload(0x40)
mstore(result, 0x40)
mstore(add(result, 0x20), 0x3030303030303030303030303030303030303030303030303030303030303030)
mstore(add(result, 0x40), 0x3030303030303030303030303030303030303030303030303030303030303030)
mstore(0x40, add(result, 0x60))
}
return result;
}
assembly {
result := mload(0x40)
let table := add(result, 0x60)
// Store lookup table that maps an integer from 0 to 99 into a 2-byte ASCII equivalent
// Store lookup table that maps an integer from 0 to ff into a 2-byte ASCII equivalent
mstore(add(table, 0x1e), 0x3030303130323033303430353036303730383039306130623063306430653066)
mstore(add(table, 0x3e), 0x3130313131323133313431353136313731383139316131623163316431653166)
mstore(add(table, 0x5e), 0x3230323132323233323432353236323732383239326132623263326432653266)
mstore(add(table, 0x7e), 0x3330333133323333333433353336333733383339336133623363336433653366)
mstore(add(table, 0x9e), 0x3430343134323433343434353436343734383439346134623463346434653466)
mstore(add(table, 0xbe), 0x3530353135323533353435353536353735383539356135623563356435653566)
mstore(add(table, 0xde), 0x3630363136323633363436353636363736383639366136623663366436653666)
mstore(add(table, 0xfe), 0x3730373137323733373437353736373737383739376137623763376437653766)
mstore(add(table, 0x11e), 0x3830383138323833383438353836383738383839386138623863386438653866)
mstore(add(table, 0x13e), 0x3930393139323933393439353936393739383939396139623963396439653966)
mstore(add(table, 0x15e), 0x6130613161326133613461356136613761386139616161626163616461656166)
mstore(add(table, 0x17e), 0x6230623162326233623462356236623762386239626162626263626462656266)
mstore(add(table, 0x19e), 0x6330633163326333633463356336633763386339636163626363636463656366)
mstore(add(table, 0x1be), 0x6430643164326433643464356436643764386439646164626463646464656466)
mstore(add(table, 0x1de), 0x6530653165326533653465356536653765386539656165626563656465656566)
mstore(add(table, 0x1fe), 0x6630663166326633663466356636663766386639666166626663666466656666)
/**
* Convert `input` into ASCII.
*
* Slice 2 base-10 digits off of the input, use to index the ASCII lookup table.
*
* We start from the least significant digits, write results into mem backwards,
* this prevents us from overwriting memory despite the fact that each mload
* only contains 2 byteso f useful data.
*
*/
let base := input
function slice(v, tableptr) {
mstore(0x1e, mload(add(tableptr, shl(1, and(v, 0xff)))))
mstore(0x1c, mload(add(tableptr, shl(1, and(shr(8, v), 0xff)))))
mstore(0x1a, mload(add(tableptr, shl(1, and(shr(16, v), 0xff)))))
mstore(0x18, mload(add(tableptr, shl(1, and(shr(24, v), 0xff)))))
mstore(0x16, mload(add(tableptr, shl(1, and(shr(32, v), 0xff)))))
mstore(0x14, mload(add(tableptr, shl(1, and(shr(40, v), 0xff)))))
mstore(0x12, mload(add(tableptr, shl(1, and(shr(48, v), 0xff)))))
mstore(0x10, mload(add(tableptr, shl(1, and(shr(56, v), 0xff)))))
mstore(0x0e, mload(add(tableptr, shl(1, and(shr(64, v), 0xff)))))
mstore(0x0c, mload(add(tableptr, shl(1, and(shr(72, v), 0xff)))))
mstore(0x0a, mload(add(tableptr, shl(1, and(shr(80, v), 0xff)))))
mstore(0x08, mload(add(tableptr, shl(1, and(shr(88, v), 0xff)))))
mstore(0x06, mload(add(tableptr, shl(1, and(shr(96, v), 0xff)))))
mstore(0x04, mload(add(tableptr, shl(1, and(shr(104, v), 0xff)))))
mstore(0x02, mload(add(tableptr, shl(1, and(shr(112, v), 0xff)))))
mstore(0x00, mload(add(tableptr, shl(1, and(shr(120, v), 0xff)))))
}
mstore(result, 0x40)
slice(base, table)
mstore(add(result, 0x40), mload(0x1e))
base := shr(128, base)
slice(base, table)
mstore(add(result, 0x20), mload(0x1e))
mstore(0x40, add(result, 0x60))
}
}
function getSignedMessageForTxId(bytes32 txId) internal pure returns (bytes32 hashedMessage) {
// we know this string length is 64 bytes
string memory txIdHexString = toHexString(txId);
assembly {
let mPtr := mload(0x40)
mstore(add(mPtr, 32), "\x19Ethereum Signed Message:\n210")
mstore(add(mPtr, 61), "Signing this message will allow ")
mstore(add(mPtr, 93), "your pending funds to be spent i")
mstore(add(mPtr, 125), "n Aztec transaction:\n\n0x")
mstore(add(mPtr, 149), mload(add(txIdHexString, 0x20)))
mstore(add(mPtr, 181), mload(add(txIdHexString, 0x40)))
mstore(add(mPtr, 213), "\n\nIMPORTANT: Only sign the messa")
mstore(add(mPtr, 245), "ge if you trust the client")
hashedMessage := keccak256(add(mPtr, 32), 239)
}
}
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
/**
* ----------------------------------------
* PROOF DATA SPECIFICATION
* ----------------------------------------
* Our input "proof data" is represented as a single byte array - we use custom encoding to encode the
* data associated with a rollup block. The encoded structure is as follows (excluding the length param of the bytes type):
*
* | byte range | num bytes | name | description |
* | --- | --- | --- | --- |
* | 0x00 - 0x20 | 32 | rollupId | Unique rollup block identifier. Equivalent to block number |
* | 0x20 - 0x40 | 32 | rollupSize | Max number of transactions in the block |
* | 0x40 - 0x60 | 32 | dataStartIndex | Position of the next empty slot in the Aztec data tree |
* | 0x60 - 0x80 | 32 | oldDataRoot | Root of the data tree prior to rollup block's state updates |
* | 0x80 - 0xa0 | 32 | newDataRoot | Root of the data tree after rollup block's state updates |
* | 0xa0 - 0xc0 | 32 | oldNullRoot | Root of the nullifier tree prior to rollup block's state updates |
* | 0xc0 - 0xe0 | 32 | newNullRoot | Root of the nullifier tree after rollup block's state updates |
* | 0xe0 - 0x100 | 32 | oldDataRootsRoot | Root of the tree of data tree roots prior to rollup block's state updates |
* | 0x100 - 0x120 | 32 | newDataRootsRoot | Root of the tree of data tree roots after rollup block's state updates |
* | 0x120 - 0x140 | 32 | oldDefiRoot | Root of the defi tree prior to rollup block's state updates |
* | 0x140 - 0x160 | 32 | newDefiRoot | Root of the defi tree after rollup block's state updates |
* | 0x160 - 0x560 | 1024 | encodedBridgeCallDatas[NUMBER_OF_BRIDGE_CALLS] | Size-32 array of encodedBridgeCallDatas for bridges being called in this block. If encodedBridgeCallData == 0, no bridge is called |
* | 0x560 - 0x960 | 1024 | depositSums[NUMBER_OF_BRIDGE_CALLS] | Size-32 array of deposit values being sent to bridges which are called in this block |
* | 0x960 - 0xb60 | 512 | assetIds[NUMBER_OF_ASSETS] | Size-16 array of assetIds which correspond to assets being used to pay fees in this block |
* | 0xb60 - 0xd60 | 512 | txFees[NUMBER_OF_ASSETS] | Size-16 array of transaction fees paid to the rollup beneficiary, denominated in each assetId |
* | 0xd60 - 0x1160 | 1024 | interactionNotes[NUMBER_OF_BRIDGE_CALLS] | Size-32 array of defi interaction result commitments that must be inserted into the defi tree at this rollup block |
* | 0x1160 - 0x1180 | 32 | prevDefiInteractionHash | A SHA256 hash of the data used to create each interaction result commitment. Used to validate correctness of interactionNotes |
* | 0x1180 - 0x11a0 | 32 | rollupBeneficiary | The address that the fees from this rollup block should be sent to. Prevents a rollup proof being taken from the transaction pool and having its fees redirected |
* | 0x11a0 - 0x11c0 | 32 | numRollupTxs | Number of "inner rollup" proofs used to create the block proof. "inner rollup" circuits process 3-28 user txns, the outer rollup circuit processes 1-28 inner rollup proofs. |
* | 0x11c0 - 0x11c4 | 4 | numRealTxs | Number of transactions in the rollup excluding right-padded padding proofs |
* | 0x11c4 - 0x11c8 | 4 | encodedInnerTxData.length | Number of bytes of encodedInnerTxData |
* | 0x11c8 - end | encodedInnerTxData.length | encodedInnerTxData | Encoded inner transaction data. Contains encoded form of the broadcasted data associated with each tx in the rollup block |
*
*/
/**
* --------------------------------------------
* DETERMINING THE NUMBER OF REAL TRANSACTIONS
* --------------------------------------------
* The `rollupSize` parameter describes the MAX number of txns in a block.
* However the block may not be full.
* Incomplete blocks will be padded with "padding" transactions that represent empty txns.
*
* The amount of end padding is not explicitly defined in `proofData`. It is derived.
* The encodedInnerTxData does not include tx data for the txns associated with this end padding.
* (it does include any padding transactions that are not part of the end padding, which can sometimes happen)
* When decoded, the transaction data for each transaction is a fixed size (256 bytes)
* Number of real transactions = rollupSize - (decoded tx data size / 256)
*
* The decoded transaction data associated with padding transactions is 256 zero bytes.
*
*/
/**
* @title Decoder
* @dev contains functions for decoding/extracting the encoded proof data passed in as calldata,
* as well as computing the SHA256 hash of the decoded data (publicInputsHash).
* The publicInputsHash is used to ensure the data passed in as calldata matches the data used within the rollup circuit
*/
contract Decoder {
/*----------------------------------------
CONSTANTS
----------------------------------------*/
uint256 internal constant NUMBER_OF_ASSETS = 16; // max number of assets in a block
uint256 internal constant NUMBER_OF_BRIDGE_CALLS = 32; // max number of bridge calls in a block
uint256 internal constant NUMBER_OF_BRIDGE_BYTES = 1024; // NUMBER_OF_BRIDGE_CALLS * 32
uint256 internal constant NUMBER_OF_PUBLIC_INPUTS_PER_TX = 8; // number of ZK-SNARK "public inputs" per join-split/account/claim transaction
uint256 internal constant TX_PUBLIC_INPUT_LENGTH = 256; // byte-length of NUMBER_OF_PUBLIC_INPUTS_PER_TX. NUMBER_OF_PUBLIC_INPUTS_PER_TX * 32;
uint256 internal constant ROLLUP_NUM_HEADER_INPUTS = 142; // 58; // number of ZK-SNARK "public inputs" that make up the rollup header 14 + (NUMBER_OF_BRIDGE_CALLS * 3) + (NUMBER_OF_ASSETS * 2);
uint256 internal constant ROLLUP_HEADER_LENGTH = 4544; // 1856; // ROLLUP_NUM_HEADER_INPUTS * 32;
// ENCODED_PROOF_DATA_LENGTH_OFFSET = byte offset into the rollup header such that `numRealTransactions` occupies
// the least significant 4 bytes of the 32-byte word being pointed to.
// i.e. ROLLUP_HEADER_LENGTH - 28
uint256 internal constant NUM_REAL_TRANSACTIONS_OFFSET = 4516;
// ENCODED_PROOF_DATA_LENGTH_OFFSET = byte offset into the rollup header such that `encodedInnerProofData.length` occupies
// the least significant 4 bytes of the 32-byte word being pointed to.
// i.e. ROLLUP_HEADER_LENGTH - 24
uint256 internal constant ENCODED_PROOF_DATA_LENGTH_OFFSET = 4520;
// offset we add to `proofData` to point to the encodedBridgeCallDatas
uint256 internal constant BRIDGE_CALL_DATAS_OFFSET = 0x180;
// offset we add to `proofData` to point to prevDefiInteractionhash
uint256 internal constant PREVIOUS_DEFI_INTERACTION_HASH_OFFSET = 4480; // ROLLUP_HEADER_LENGTH - 0x40
// offset we add to `proofData` to point to rollupBeneficiary
uint256 internal constant ROLLUP_BENEFICIARY_OFFSET = 4512; // ROLLUP_HEADER_LENGTH - 0x20
// CIRCUIT_MODULUS = group order of the BN254 elliptic curve. All arithmetic gates in our ZK-SNARK circuits are evaluated modulo this prime.
// Is used when computing the public inputs hash - our SHA256 hash outputs are reduced modulo CIRCUIT_MODULUS
uint256 internal constant CIRCUIT_MODULUS =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
// SHA256 hashes
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_1 =
0x22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af0;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_2 =
0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_4 =
0x2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_8 =
0x240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a9;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_16 =
0x1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca4;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_32 =
0x0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d44;
uint256 internal constant PADDING_ROLLUP_HASH_SIZE_64 =
0x1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd;
uint256 internal constant ADDRESS_MASK = 0x00_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
/*----------------------------------------
ERROR TAGS
----------------------------------------*/
error ENCODING_BYTE_INVALID();
error INVALID_ROLLUP_TOPOLOGY();
/*----------------------------------------
DECODING FUNCTIONS
----------------------------------------*/
/**
* In `bytes proofData`, transaction data is appended after the rollup header data
* Each transaction is described by 8 'public inputs' used to create a user transaction's ZK-SNARK proof
* (i.e. there are 8 public inputs for each of the "join-split", "account" and "claim" circuits)
* The public inputs are represented in calldata according to the following specification:
*
* | public input idx | calldata size (bytes) | variable description |
* | 0 | 1 | proofId - transaction type identifier |
* | 1 | 32 | encrypted form of 1st output note |
* | 2 | 32 | encrypted form of 2nd output note |
* | 3 | 32 | nullifier of 1st input note |
* | 4 | 32 | nullifier of 2nd input note |
* | 5 | 32 | amount being deposited or withdrawn |
* | 6 | 20 | address of depositor or withdraw destination |
* | 7 | 4 | assetId used in transaction |
*
* The following table maps proofId values to transaction types
*
*
* | proofId | tx type | description |
* | --- | --- | --- |
* | 0 | padding | empty transaction. Rollup blocks have a fixed number of txns. If number of real txns is less than block size, padding txns make up the difference |
* | 1 | deposit | deposit Eth/tokens into Aztec in exchange for encrypted Aztec notes |
* | 2 | withdraw | exchange encrypted Aztec notes for Eth/tokens sent to a public address |
* | 3 | send | private send |
* | 4 | account | creates an Aztec account |
* | 5 | defiDeposit | deposit Eth/tokens into a L1 smart contract via a Defi bridge contract |
* | 6 | defiClaim | convert proceeds of defiDeposit tx back into encrypted Aztec notes |
*
* Most of the above transaction types do not use the full set of 8 public inputs (i.e. some are zero).
* To save on calldata costs, we encode each transaction into the smallest payload possible.
* In `decodeProof`, the encoded transaction data is decoded and written into memory
*
* As part of the decoding algorithms we must convert the 20-byte `publicOwner` and 4-byte `assetId` fields
* into 32-byte EVM words
*
* The following functions perform transaction-specific decoding. The `proofId` field is decoded prior to calling these functions
*/
/**
* @notice Decodes a padding tx
* @param _inPtr location in calldata of the encoded transaction
* @return - a location in calldata of the next encoded transaction
*
* @dev Encoded padding tx consists of 1 byte, the `proofId`
* The `proofId` has been written into memory before we called this function so there is nothing to copy
* Advance the calldatapointer by 1 byte to move to the next transaction
*/
function paddingTx(uint256 _inPtr, uint256) internal pure returns (uint256) {
unchecked {
return (_inPtr + 0x1);
}
}
/**
* @notice Decodes a deposit or a withdraw tx
* @param _inPtr location in calldata of the encoded transaction
* @param _outPtr location in memory to write the decoded transaction to
* @return - location in calldata of the next encoded transaction
*
* @dev The deposit tx uses all 8 public inputs. All calldata is copied into memory.
*/
function depositOrWithdrawTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
// Copy deposit calldata into memory
assembly {
// start copying into `outPtr + 0x20`, as `outPtr` points to `proofId`, which has already been written into memory
calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0xa0) // noteCommitment{1, 2}, nullifier{1,2}, publicValue; 32*5 bytes
calldatacopy(add(_outPtr, 0xcc), add(_inPtr, 0xc0), 0x14) // convert 20-byte `publicOwner` calldata variable into 32-byte EVM word
calldatacopy(add(_outPtr, 0xfc), add(_inPtr, 0xd4), 0x4) // convert 4-byte `assetId` variable into 32-byte EVM word
}
// advance calldata ptr by 185 bytes
unchecked {
return (_inPtr + 0xb9);
}
}
/**
* @notice Decodes a send-type tx
* @param _inPtr location in calldata of the encoded transaction
* @param _outPtr location in memory to write the decoded transaction to
* @return - location in calldata of the next encoded transaction
*
* @dev The send tx has 0-values for `publicValue`, `publicOwner` and `assetId`
* No need to copy anything into memory for these fields as memory defaults to 0
*/
function sendTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
assembly {
calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
}
unchecked {
return (_inPtr + 0x81);
}
}
/**
* @notice Decodes an account creation tx
* @param _inPtr location in calldata of the encoded transaction
* @param _outPtr location in memory to write the decoded transaction to
* @return - location in calldata of the next encoded transaction
*
* @dev The account tx has 0-values for `nullifier2`, `publicValue`, `publicOwner` and `assetId`
* No need to copy anything into memory for these fields as memory defaults to 0
*/
function accountTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
assembly {
calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
}
unchecked {
return (_inPtr + 0x81);
}
}
/**
* @notice Decodes a defi deposit or claim tx
* @param _inPtr location in calldata of the encoded transaction
* @param _outPtr location in memory to write the decoded transaction to
* @return - location in calldata of the next encoded transaction
*
* @dev The defi deposit/claim tx has 0-values for `publicValue`, `publicOwner` and `assetId`
* No need to copy anything into memory for these fields as memory defaults to 0
*/
function defiDepositOrClaimTx(uint256 _inPtr, uint256 _outPtr) internal pure returns (uint256) {
assembly {
calldatacopy(add(_outPtr, 0x20), add(_inPtr, 0x20), 0x80) // noteCommitment{1, 2}, nullifier{1,2}; 32*4 bytes
}
unchecked {
return (_inPtr + 0x81);
}
}
/**
* @notice Throws an error and reverts.
* @dev If we hit this, there is a transaction whose proofId is invalid (i.e. not 0 to 7).
*/
function invalidTx(uint256, uint256) internal pure returns (uint256) {
revert ENCODING_BYTE_INVALID();
}
/**
* @notice Decodes the rollup block's proof data
* @dev This function converts the proof data into a representation we can work with in memory
* In particular, encoded transaction calldata is decoded and written into memory
* The rollup header is copied from calldata into memory as well
* @return proofData a memory pointer to the decoded proof data
* @return numTxs number of transactions in the rollup, excluding end-padding transactions
* @return publicInputsHash sha256 hash of the public inputs
*
* @dev The `publicInputsHash` is a sha256 hash of the public inputs associated with each transaction in the rollup.
* It is used to validate the correctness of the data being fed into the rollup circuit.
*
* (There is a bit of nomenclature abuse here. Processing a public input in the verifier algorithm costs 150 gas,
* which adds up very quickly. Instead of this, we sha256 hash what used to be the "public" inputs and only set
* the hash to be public. We then make the old "public" inputs private in the rollup circuit, and validate their
* correctness by checking that their sha256 hash matches what we compute in the decodeProof function!
*/
function decodeProof() internal view returns (bytes memory proofData, uint256 numTxs, uint256 publicInputsHash) {
// declare some variables that will be set inside asm blocks
uint256 dataSize; // size of our decoded transaction data, in bytes
uint256 outPtr; // memory pointer to where we will write our decoded transaction data
uint256 inPtr; // calldata pointer into our proof data
uint256 rollupSize; // max number of transactions in the rollup block
uint256 decodedTxDataStart;
{
uint256 tailInPtr; // calldata pointer to the end of our proof data
/**
* Let's build a function table!
*
* To decode our tx data, we need to iterate over every encoded transaction and call its
* associated decoding function. If we did this via a `switch` statement this would be VERY expensive,
* due to the large number of JUMPI instructions that would be called.
*
* Instead, we use function pointers.
* The `proofId` field in our encoded proof data is an integer from 0-6,
* we can use `proofId` to index a table of function pointers for our respective decoding functions.
* This is much faster as there is no conditional branching!
*/
function(uint256, uint256) pure returns (uint256) callfunc; // we're going to use `callfunc` as a function pointer
// `functionTable` is a pointer to a table in memory, containing function pointers
// Step 1: reserve memory for functionTable
uint256 functionTable;
assembly {
functionTable := mload(0x40)
mstore(0x40, add(functionTable, 0x100)) // reserve 256 bytes for function pointers
}
{
// Step 2: copy function pointers into local variables so that inline asm code can access them
function(uint256, uint256) pure returns (uint256) t0 = paddingTx;
function(uint256, uint256) pure returns (uint256) t1 = depositOrWithdrawTx;
function(uint256, uint256) pure returns (uint256) t3 = sendTx;
function(uint256, uint256) pure returns (uint256) t4 = accountTx;
function(uint256, uint256) pure returns (uint256) t5 = defiDepositOrClaimTx;
function(uint256, uint256) pure returns (uint256) t7 = invalidTx;
// Step 3: write function pointers into the table!
assembly {
mstore(functionTable, t0)
mstore(add(functionTable, 0x20), t1)
mstore(add(functionTable, 0x40), t1)
mstore(add(functionTable, 0x60), t3)
mstore(add(functionTable, 0x80), t4)
mstore(add(functionTable, 0xa0), t5)
mstore(add(functionTable, 0xc0), t5)
mstore(add(functionTable, 0xe0), t7) // a proofId of 7 is not a valid transaction type, set to invalidTx
}
}
uint256 decodedTransactionDataSize;
assembly {
// Add encoded proof data size to dataSize, minus the 4 bytes of encodedInnerProofData.length.
// Set inPtr to point to the length parameter of `bytes calldata proofData`
inPtr := add(calldataload(0x04), 0x4) // `proofData = first input parameter. Calldata offset to proofData will be at 0x04. Add 0x04 to account for function signature.
// Advance inPtr to point to the start of `proofData`
inPtr := add(inPtr, 0x20)
numTxs := and(calldataload(add(inPtr, NUM_REAL_TRANSACTIONS_OFFSET)), 0xffffffff)
// Get encoded inner proof data size.
// Add ENCODED_PROOF_DATA_LENGTH_OFFSET to inPtr to point to the correct variable in our header block,
// mask off all but 4 least significant bytes as this is a packed 32-bit variable.
let encodedInnerDataSize := and(calldataload(add(inPtr, ENCODED_PROOF_DATA_LENGTH_OFFSET)), 0xffffffff)
// Load up the rollup size from `proofData`
rollupSize := calldataload(add(inPtr, 0x20))
// Compute the number of bytes our decoded proof data will take up.
// i.e. num total txns in the rollup (including padding) * number of public inputs per transaction
let decodedInnerDataSize := mul(rollupSize, TX_PUBLIC_INPUT_LENGTH)
// We want `dataSize` to equal: rollup header length + decoded tx length (excluding padding blocks)
let numInnerRollups := calldataload(add(inPtr, sub(ROLLUP_HEADER_LENGTH, 0x20)))
let numTxsPerRollup := div(rollupSize, numInnerRollups)
let numFilledBlocks := div(numTxs, numTxsPerRollup)
numFilledBlocks := add(numFilledBlocks, iszero(eq(mul(numFilledBlocks, numTxsPerRollup), numTxs)))
decodedTransactionDataSize := mul(mul(numFilledBlocks, numTxsPerRollup), TX_PUBLIC_INPUT_LENGTH)
dataSize := add(ROLLUP_HEADER_LENGTH, decodedTransactionDataSize)
// Allocate memory for `proofData`.
proofData := mload(0x40)
// Set free mem ptr to `dataSize` + 0x20 (to account for the 0x20 bytes for the length param of proofData)
// This allocates memory whose size is equal to the rollup header size, plus the data required for
// each transaction's decoded tx data (256 bytes * number of non-padding blocks).
// Only reserve memory for blocks that contain non-padding proofs. These "padding" blocks don't need to be
// stored in memory as we don't need their data for any computations.
mstore(0x40, add(proofData, add(dataSize, 0x20)))
// Set `outPtr` to point to the `proofData` length parameter
outPtr := proofData
// Write `dataSize` into `proofData.length`
mstore(outPtr, dataSize)
// Advance `outPtr` to point to start of `proofData`
outPtr := add(outPtr, 0x20)
// Copy rollup header data to `proofData`.
calldatacopy(outPtr, inPtr, ROLLUP_HEADER_LENGTH)
// Advance `outPtr` to point to the end of the header data (i.e. the start of the decoded inner transaction data)
outPtr := add(outPtr, ROLLUP_HEADER_LENGTH)
// Advance `inPtr` to point to the start of our encoded inner transaction data.
// Add (ROLLUP_HEADER_LENGTH + 0x08) to skip over the packed (numRealTransactions, encodedProofData.length) parameters
inPtr := add(inPtr, add(ROLLUP_HEADER_LENGTH, 0x08))
// Set `tailInPtr` to point to the end of our encoded transaction data
tailInPtr := add(inPtr, encodedInnerDataSize)
// Set `decodedTxDataStart` pointer
decodedTxDataStart := outPtr
}
/**
* Start of decoding algorithm
*
* Iterate over every encoded transaction, load out the first byte (`proofId`) and use it to
* jump to the relevant transaction's decoding function
*/
assembly {
// Subtract 31 bytes off of `inPtr`, so that the first byte of the encoded transaction data
// is located at the least significant byte of calldataload(inPtr)
// also adjust `tailInPtr` as we compare `inPtr` against `tailInPtr`
inPtr := sub(inPtr, 0x1f)
tailInPtr := sub(tailInPtr, 0x1f)
}
unchecked {
for (; tailInPtr > inPtr;) {
assembly {
// For each tx, the encoding byte determines how we decode the tx calldata
// The encoding byte can take values from 0 to 7; we want to turn these into offsets that can index our function table.
// 1. Access encoding byte via `calldataload(inPtr)`. The least significant byte is our encoding byte. Mask off all but the 3 least sig bits
// 2. Shift left by 5 bits. This is equivalent to multiplying the encoding byte by 32.
// 3. The result will be 1 of 8 offset values (0x00, 0x20, ..., 0xe0) which we can use to retrieve the relevant function pointer from `functionTable`
let encoding := and(calldataload(inPtr), 7)
// Store `proofId` at `outPtr`.
mstore(outPtr, encoding) // proofId
// Use `proofId` to extract the relevant function pointer from `functionTable`
callfunc := mload(add(functionTable, shl(5, encoding)))
}
// Call the decoding function. Return value will be next required value of inPtr
inPtr = callfunc(inPtr, outPtr);
// advance outPtr by the size of a decoded transaction
outPtr += TX_PUBLIC_INPUT_LENGTH;
}
}
}
/**
* Compute the public inputs hash
*
* We need to take our decoded proof data and compute its SHA256 hash.
* This hash is fed into our rollup proof as a public input.
* If the hash does not match the SHA256 hash computed within the rollup circuit
* on the equivalent parameters, the proof will reject.
* This check ensures that the transaction data present in calldata are equal to
* the transaction data values present in the rollup ZK-SNARK circuit.
*
* One complication is the structure of the SHA256 hash.
* We slice transactions into chunks equal to the number of transactions in the "inner rollup" circuit
* (a rollup circuit verifies multiple "inner rollup" circuits, which each verify 3-28 private user transactions.
* This tree structure helps parallelise proof construction)
* We then SHA256 hash each transaction *chunk*
* Finally we SHA256 hash the above SHA256 hashes to get our public input hash!
*
* We do the above instead of a straight hash of all of the transaction data,
* because it's faster to parallelise proof construction if the majority of the SHA256 hashes are computed in
* the "inner rollup" circuit and not the main rollup circuit.
*/
// Step 1: compute the hashes that constitute the inner proofs data
bool invalidRollupTopology;
assembly {
// We need to figure out how many rollup proofs are in this tx and how many user transactions are in each rollup
let numRollupTxs := mload(add(proofData, ROLLUP_HEADER_LENGTH))
let numJoinSplitsPerRollup := div(rollupSize, numRollupTxs)
let rollupDataSize := mul(mul(numJoinSplitsPerRollup, NUMBER_OF_PUBLIC_INPUTS_PER_TX), 32)
// Compute the number of inner rollups that don't contain padding proofs
let numNotEmptyInnerRollups := div(numTxs, numJoinSplitsPerRollup)
numNotEmptyInnerRollups :=
add(numNotEmptyInnerRollups, iszero(eq(mul(numNotEmptyInnerRollups, numJoinSplitsPerRollup), numTxs)))
// Compute the number of inner rollups that only contain padding proofs!
// For these "empty" inner rollups, we don't need to compute their public inputs hash directly,
// we can use a precomputed value
let numEmptyInnerRollups := sub(numRollupTxs, numNotEmptyInnerRollups)
let proofdataHashPtr := mload(0x40)
// Copy the header data into the `proofdataHash`
// Header start is at calldataload(0x04) + 0x24 (+0x04 to skip over func signature, +0x20 to skip over byte array length param)
calldatacopy(proofdataHashPtr, add(calldataload(0x04), 0x24), ROLLUP_HEADER_LENGTH)
// Update pointer
proofdataHashPtr := add(proofdataHashPtr, ROLLUP_HEADER_LENGTH)
// Compute the endpoint for the `proofdataHashPtr` (used as a loop boundary condition)
let endPtr := add(proofdataHashPtr, mul(numNotEmptyInnerRollups, 0x20))
// Iterate over the public inputs of each inner rollup proof and compute their SHA256 hash
// better solution here is ... iterate over number of non-padding rollup blocks
// and hash those
// for padding rollup blocks...just append the zero hash
for {} lt(proofdataHashPtr, endPtr) { proofdataHashPtr := add(proofdataHashPtr, 0x20) } {
// address(0x02) is the SHA256 precompile address
if iszero(staticcall(gas(), 0x02, decodedTxDataStart, rollupDataSize, 0x00, 0x20)) {
revert(0x00, 0x00)
}
mstore(proofdataHashPtr, mod(mload(0x00), CIRCUIT_MODULUS))
decodedTxDataStart := add(decodedTxDataStart, rollupDataSize)
}
// If there are empty inner rollups, we can use a precomputed hash
// of their public inputs instead of computing it directly.
if iszero(iszero(numEmptyInnerRollups)) {
let zeroHash
switch numJoinSplitsPerRollup
case 32 { zeroHash := PADDING_ROLLUP_HASH_SIZE_32 }
case 16 { zeroHash := PADDING_ROLLUP_HASH_SIZE_16 }
case 64 { zeroHash := PADDING_ROLLUP_HASH_SIZE_64 }
case 1 { zeroHash := PADDING_ROLLUP_HASH_SIZE_1 }
case 2 { zeroHash := PADDING_ROLLUP_HASH_SIZE_2 }
case 4 { zeroHash := PADDING_ROLLUP_HASH_SIZE_4 }
case 8 { zeroHash := PADDING_ROLLUP_HASH_SIZE_8 }
default { invalidRollupTopology := true }
endPtr := add(endPtr, mul(numEmptyInnerRollups, 0x20))
for {} lt(proofdataHashPtr, endPtr) { proofdataHashPtr := add(proofdataHashPtr, 0x20) } {
mstore(proofdataHashPtr, zeroHash)
}
}
// Compute SHA256 hash of header data + inner public input hashes
let startPtr := mload(0x40)
if iszero(staticcall(gas(), 0x02, startPtr, sub(proofdataHashPtr, startPtr), 0x00, 0x20)) {
revert(0x00, 0x00)
}
publicInputsHash := mod(mload(0x00), CIRCUIT_MODULUS)
}
if (invalidRollupTopology) {
revert INVALID_ROLLUP_TOPOLOGY();
}
}
/**
* @notice Extracts the `rollupId` param from the decoded proof data
* @dev This represents the rollupId of the next valid rollup block
* @param _proofData the decoded proof data
* @return nextRollupId the expected id of the next rollup block
*/
function getRollupId(bytes memory _proofData) internal pure returns (uint256 nextRollupId) {
assembly {
nextRollupId := mload(add(_proofData, 0x20))
}
}
/**
* @notice Decodes the input merkle roots of `proofData` and computes rollupId && sha3 hash of roots && dataStartIndex
* @dev The rollup's state is uniquely defined by the following variables:
* * The next empty location in the data root tree (rollupId + 1)
* * The next empty location in the data tree (dataStartIndex + rollupSize)
* * The root of the data tree
* * The root of the nullifier set
* * The root of the data root tree (tree containing all previous roots of the data tree)
* * The root of the defi tree
* Instead of storing all of these variables in storage (expensive!), we store a keccak256 hash of them.
* To validate the correctness of a block's state transition, we must perform the following:
* * Use proof broadcasted inputs to reconstruct the "old" state hash
* * Use proof broadcasted inputs to reconstruct the "new" state hash
* * Validate that the old state hash matches what is in storage
* * Set the old state hash to the new state hash
* N.B. we still store `dataSize` as a separate storage var as `proofData does not contain all
* neccessary information to reconstruct its old value.
* @param _proofData cryptographic proofData associated with a rollup
* @return rollupId
* @return oldStateHash
* @return newStateHash
* @return numDataLeaves
* @return dataStartIndex
*/
function computeRootHashes(bytes memory _proofData)
internal
pure
returns (
uint256 rollupId,
bytes32 oldStateHash,
bytes32 newStateHash,
uint32 numDataLeaves,
uint32 dataStartIndex
)
{
assembly {
let dataStart := add(_proofData, 0x20) // jump over first word, it's length of data
numDataLeaves := shl(1, mload(add(dataStart, 0x20))) // rollupSize * 2 (2 notes per tx)
dataStartIndex := mload(add(dataStart, 0x40))
// validate numDataLeaves && dataStartIndex are uint32s
if or(gt(numDataLeaves, 0xffffffff), gt(dataStartIndex, 0xffffffff)) { revert(0, 0) }
rollupId := mload(dataStart)
let mPtr := mload(0x40)
mstore(mPtr, rollupId) // old nextRollupId
mstore(add(mPtr, 0x20), mload(add(dataStart, 0x60))) // oldDataRoot
mstore(add(mPtr, 0x40), mload(add(dataStart, 0xa0))) // oldNullRoot
mstore(add(mPtr, 0x60), mload(add(dataStart, 0xe0))) // oldRootRoot
mstore(add(mPtr, 0x80), mload(add(dataStart, 0x120))) // oldDefiRoot
oldStateHash := keccak256(mPtr, 0xa0)
mstore(mPtr, add(rollupId, 0x01)) // new nextRollupId
mstore(add(mPtr, 0x20), mload(add(dataStart, 0x80))) // newDataRoot
mstore(add(mPtr, 0x40), mload(add(dataStart, 0xc0))) // newNullRoot
mstore(add(mPtr, 0x60), mload(add(dataStart, 0x100))) // newRootRoot
mstore(add(mPtr, 0x80), mload(add(dataStart, 0x140))) // newDefiRoot
newStateHash := keccak256(mPtr, 0xa0)
}
}
/**
* @notice Extract the `prevDefiInteractionHash` from the proofData's rollup header
* @param _proofData decoded rollup proof data
* @return prevDefiInteractionHash the defiInteractionHash of the previous rollup block
*/
function extractPrevDefiInteractionHash(bytes memory _proofData)
internal
pure
returns (bytes32 prevDefiInteractionHash)
{
assembly {
prevDefiInteractionHash := mload(add(_proofData, PREVIOUS_DEFI_INTERACTION_HASH_OFFSET))
}
}
/**
* @notice Extracts the address we pay the rollup fee to from the proofData's rollup header
* @dev Rollup beneficiary address is included as part of the ZK-SNARK circuit data, so that the rollup provider
* can explicitly define who should get the fee when they are generating the ZK-SNARK proof (instead of
* simply sending the fee to msg.sender).
* This prevents front-running attacks where an attacker can take somebody else's rollup proof from out of
* the tx pool and replay it, stealing the fee.
* @param _proofData byte array of our input proof data
* @return rollupBeneficiary the address we pay this rollup block's fee to
*/
function extractRollupBeneficiary(bytes memory _proofData) internal pure returns (address rollupBeneficiary) {
assembly {
rollupBeneficiary := mload(add(_proofData, ROLLUP_BENEFICIARY_OFFSET))
// Validate `rollupBeneficiary` is an address
if gt(rollupBeneficiary, ADDRESS_MASK) { revert(0, 0) }
}
}
/**
* @notice Extracts an `assetId` in which a fee is going to be paid from a rollup block
* @dev The rollup block contains up to 16 different assets, which can be recovered from the rollup header data.
* @param _proofData byte array of our input proof data
* @param _idx index of the asset we want (assetId = header.assetIds[_idx])
* @return assetId 30-bit identifier of an asset. The ERC20 token address is obtained via the mapping `supportedAssets[assetId]`,
*/
function extractFeeAssetId(bytes memory _proofData, uint256 _idx) internal pure returns (uint256 assetId) {
assembly {
assetId :=
mload(
add(add(add(_proofData, BRIDGE_CALL_DATAS_OFFSET), mul(0x40, NUMBER_OF_BRIDGE_CALLS)), mul(0x20, _idx))
)
// Validate `assetId` is a uint32!
if gt(assetId, 0xffffffff) { revert(0, 0) }
}
}
/**
* @notice Extracts the transaction fee for a given asset which is to be paid to the rollup beneficiary
* @dev The total fee is the sum of the individual fees paid by each transaction in the rollup block.
* This sum is computed directly in the rollup circuit, and is present in the rollup header data.
* @param _proofData byte array of decoded rollup proof data
* @param _idx The index of the asset the fee is denominated in
* @return totalTxFee total rollup block transaction fee for a given asset
*/
function extractTotalTxFee(bytes memory _proofData, uint256 _idx) internal pure returns (uint256 totalTxFee) {
assembly {
totalTxFee := mload(add(add(add(_proofData, 0x380), mul(0x40, NUMBER_OF_BRIDGE_CALLS)), mul(0x20, _idx)))
}
}
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol";
interface IDefiBridge {
/**
* @notice A function which converts input assets to output assets.
* @param _inputAssetA A struct detailing the first input asset
* @param _inputAssetB A struct detailing the second input asset
* @param _outputAssetA A struct detailing the first output asset
* @param _outputAssetB A struct detailing the second output asset
* @param _totalInputValue An amount of input assets transferred to the bridge (Note: "total" is in the name
* because the value can represent summed/aggregated token amounts of users actions on L2)
* @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call.
* @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.)
* @return outputValueA An amount of `_outputAssetA` returned from this interaction.
* @return outputValueB An amount of `_outputAssetB` returned from this interaction.
* @return isAsync A flag indicating if the interaction is async.
* @dev This function is called from the RollupProcessor contract via the DefiBridgeProxy. Before this function is
* called _RollupProcessor_ contract will have sent you all the assets defined by the input params. This
* function is expected to convert input assets to output assets (e.g. on Uniswap) and return the amounts
* of output assets to be received by the _RollupProcessor_. If output assets are ERC20 tokens the bridge has
* to set _RollupProcessor_ as a spender before the interaction is finished. If some of the output assets is ETH
* it has to be sent to _RollupProcessor_ via the `receiveEthFromBridge(uint256 _interactionNonce)` method
* before the `convert(...)` function call finishes.
* @dev If there are two input assets, equal amounts of both assets will be transferred to the bridge before this
* method is called.
* @dev **BOTH** output assets could be virtual but since their `assetId` is currently assigned as
* `_interactionNonce` it would simply mean that more of the same virtual asset is minted.
* @dev If this interaction is async the function has to return `(0, 0, true)`. Async interaction will be finalised at
* a later time and its output assets will be returned in a `IDefiBridge.finalise(...)` call.
*
*/
function convert(
AztecTypes.AztecAsset calldata _inputAssetA,
AztecTypes.AztecAsset calldata _inputAssetB,
AztecTypes.AztecAsset calldata _outputAssetA,
AztecTypes.AztecAsset calldata _outputAssetB,
uint256 _totalInputValue,
uint256 _interactionNonce,
uint64 _auxData,
address _rollupBeneficiary
) external payable returns (uint256 outputValueA, uint256 outputValueB, bool isAsync);
/**
* @notice A function that finalises asynchronous interaction.
* @param _inputAssetA A struct detailing the first input asset
* @param _inputAssetB A struct detailing the second input asset
* @param _outputAssetA A struct detailing the first output asset
* @param _outputAssetB A struct detailing the second output asset
* @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call.
* @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.)
* @return outputValueA An amount of `_outputAssetA` returned from this interaction.
* @return outputValueB An amount of `_outputAssetB` returned from this interaction.
* @return interactionComplete A flag indicating whether an async interaction was successfully completed/finalised.
* @dev This function should use the `BridgeBase.onlyRollup()` modifier to ensure it can only be called from
* the `RollupProcessor.processAsyncDefiInteraction(uint256 _interactionNonce)` method.
*
*/
function finalise(
AztecTypes.AztecAsset calldata _inputAssetA,
AztecTypes.AztecAsset calldata _inputAssetB,
AztecTypes.AztecAsset calldata _outputAssetA,
AztecTypes.AztecAsset calldata _outputAssetB,
uint256 _interactionNonce,
uint64 _auxData
) external payable returns (uint256 outputValueA, uint256 outputValueB, bool interactionComplete);
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
interface IVerifier {
function verify(bytes memory _serializedProof, uint256 _publicInputsHash) external returns (bool);
function getVerificationKeyHash() external pure returns (bytes32);
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec.
pragma solidity >=0.8.4;
library SafeCast {
error SAFE_CAST_OVERFLOW();
function toU128(uint256 a) internal pure returns (uint128) {
if (a > type(uint128).max) revert SAFE_CAST_OVERFLOW();
return uint128(a);
}
}// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
/**
* @title TokenTransfers
* @dev Provides functions to safely call `transfer` and `transferFrom` methods on ERC20 tokens,
* as well as the ability to call `transfer` and `transferFrom` without bubbling up errors
*/
library TokenTransfers {
error INVALID_ADDRESS_NO_CODE();
bytes4 private constant INVALID_ADDRESS_NO_CODE_SELECTOR = 0x21409272; // bytes4(keccak256('INVALID_ADDRESS_NO_CODE()'));
bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb; // bytes4(keccak256('transfer(address,uint256)'));
bytes4 private constant TRANSFER_FROM_SELECTOR = 0x23b872dd; // bytes4(keccak256('transferFrom(address,address,uint256)'));
/**
* @dev Safely call ERC20.transfer, handles tokens that do not throw on transfer failure or do not return transfer result
* @param tokenAddress Where does the token live?
* @param to Who are we sending tokens to?
* @param amount How many tokens are we transferring?
*/
function safeTransferTo(address tokenAddress, address to, uint256 amount) internal {
// The ERC20 token standard states that:
// 1. failed transfers must throw
// 2. the result of the transfer (success/fail) is returned as a boolean
// Some token contracts don't implement the spec correctly and will do one of the following:
// 1. Contract does not throw if transfer fails, instead returns false
// 2. Contract throws if transfer fails, but does not return any boolean value
// We can check for these by evaluating the following:
// | call succeeds? (c) | return value (v) | returndatasize == 0 (r)| interpreted result |
// | --- | --- | --- | --- |
// | false | false | false | transfer fails |
// | false | false | true | transfer fails |
// | false | true | false | transfer fails |
// | false | true | true | transfer fails |
// | true | false | false | transfer fails |
// | true | false | true | transfer succeeds |
// | true | true | false | transfer succeeds |
// | true | true | true | transfer succeeds |
//
// i.e. failure state = !(c && (r || v))
assembly {
let ptr := mload(0x40)
mstore(ptr, TRANSFER_SELECTOR)
mstore(add(ptr, 0x4), to)
mstore(add(ptr, 0x24), amount)
if iszero(extcodesize(tokenAddress)) {
mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
revert(0, 0x4)
}
let call_success := call(gas(), tokenAddress, 0, ptr, 0x44, 0x00, 0x20)
let result_success := or(iszero(returndatasize()), and(mload(0), 1))
if iszero(and(call_success, result_success)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
/**
* @dev Safely call ERC20.transferFrom, handles tokens that do not throw on transfer failure or do not return transfer result
* @param tokenAddress Where does the token live?
* @param source Who are we transferring tokens from
* @param target Who are we transferring tokens to?
* @param amount How many tokens are being transferred?
*/
function safeTransferFrom(address tokenAddress, address source, address target, uint256 amount) internal {
assembly {
// call tokenAddress.transferFrom(source, target, value)
let mPtr := mload(0x40)
mstore(mPtr, TRANSFER_FROM_SELECTOR)
mstore(add(mPtr, 0x04), source)
mstore(add(mPtr, 0x24), target)
mstore(add(mPtr, 0x44), amount)
if iszero(extcodesize(tokenAddress)) {
mstore(0, INVALID_ADDRESS_NO_CODE_SELECTOR)
revert(0, 0x4)
}
let call_success := call(gas(), tokenAddress, 0, mPtr, 0x64, 0x00, 0x20)
let result_success := or(iszero(returndatasize()), and(mload(0), 1))
if iszero(and(call_success, result_success)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
/**
* @dev Calls ERC(tokenAddress).transfer(to, amount). Errors are ignored! Use with caution!
* @param tokenAddress Where does the token live?
* @param to Who are we sending to?
* @param amount How many tokens are being transferred?
* @param gasToSend Amount of gas to send the contract. If value is 0, function uses gas() instead
*/
function transferToDoNotBubbleErrors(address tokenAddress, address to, uint256 amount, uint256 gasToSend)
internal
{
assembly {
let callGas := gas()
if gasToSend { callGas := gasToSend }
let ptr := mload(0x40)
mstore(ptr, TRANSFER_SELECTOR)
mstore(add(ptr, 0x4), to)
mstore(add(ptr, 0x24), amount)
pop(call(callGas, tokenAddress, 0, ptr, 0x44, 0x00, 0x00))
}
}
/**
* @dev Calls ERC(tokenAddress).transferFrom(source, target, amount). Errors are ignored! Use with caution!
* @param tokenAddress Where does the token live?
* @param source Who are we transferring tokens from
* @param target Who are we transferring tokens to?
* @param amount How many tokens are being transferred?
* @param gasToSend Amount of gas to send the contract. If value is 0, function uses gas() instead
*/
function transferFromDoNotBubbleErrors(
address tokenAddress,
address source,
address target,
uint256 amount,
uint256 gasToSend
) internal {
assembly {
let callGas := gas()
if gasToSend { callGas := gasToSend }
let mPtr := mload(0x40)
mstore(mPtr, TRANSFER_FROM_SELECTOR)
mstore(add(mPtr, 0x04), source)
mstore(add(mPtr, 0x24), target)
mstore(add(mPtr, 0x44), amount)
pop(call(callGas, tokenAddress, 0, mPtr, 0x64, 0x00, 0x00))
}
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@uniswap/v2-core/=lib/v2-core/",
"@uniswap/v2-periphery/=lib/v2-periphery/",
"core/=src/core/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"mocks/=src/test/mocks/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"periphery/=src/periphery/",
"rollup-encoder/=lib/rollup-encoder/src/",
"v2-core/=lib/v2-core/contracts/",
"v2-periphery/=lib/v2-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 2000
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_escapeBlockLowerBound","type":"uint256"},{"internalType":"uint256","name":"_escapeBlockUpperBound","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ARRAY_OVERFLOW","type":"error"},{"inputs":[{"internalType":"uint256","name":"inputAssetId","type":"uint256"}],"name":"BRIDGE_WITH_IDENTICAL_INPUT_ASSETS","type":"error"},{"inputs":[{"internalType":"uint256","name":"outputAssetId","type":"uint256"}],"name":"BRIDGE_WITH_IDENTICAL_OUTPUT_ASSETS","type":"error"},{"inputs":[],"name":"DAILY_CAP_SURPASSED","type":"error"},{"inputs":[],"name":"DEPOSIT_TOKENS_WRONG_PAYMENT_TYPE","type":"error"},{"inputs":[],"name":"ENCODING_BYTE_INVALID","type":"error"},{"inputs":[],"name":"INCONSISTENT_BRIDGE_CALL_DATA","type":"error"},{"inputs":[{"internalType":"uint256","name":"providedIndex","type":"uint256"},{"internalType":"uint256","name":"expectedIndex","type":"uint256"}],"name":"INCORRECT_DATA_START_INDEX","type":"error"},{"inputs":[{"internalType":"bytes32","name":"providedDefiInteractionHash","type":"bytes32"},{"internalType":"bytes32","name":"expectedDefiInteractionHash","type":"bytes32"}],"name":"INCORRECT_PREVIOUS_DEFI_INTERACTION_HASH","type":"error"},{"inputs":[{"internalType":"bytes32","name":"oldStateHash","type":"bytes32"},{"internalType":"bytes32","name":"newStateHash","type":"bytes32"}],"name":"INCORRECT_STATE_HASH","type":"error"},{"inputs":[],"name":"INSUFFICIENT_DEPOSIT","type":"error"},{"inputs":[],"name":"INSUFFICIENT_ETH_PAYMENT","type":"error"},{"inputs":[],"name":"INSUFFICIENT_TOKEN_APPROVAL","type":"error"},{"inputs":[],"name":"INVALID_ADDRESS_NO_CODE","type":"error"},{"inputs":[],"name":"INVALID_ASSET_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_ASSET_GAS","type":"error"},{"inputs":[],"name":"INVALID_ASSET_ID","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_CALL_DATA","type":"error"},{"inputs":[],"name":"INVALID_BRIDGE_GAS","type":"error"},{"inputs":[],"name":"INVALID_ESCAPE_BOUNDS","type":"error"},{"inputs":[],"name":"INVALID_PROVIDER","type":"error"},{"inputs":[],"name":"INVALID_ROLLUP_TOPOLOGY","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"LOCKED_NO_REENTER","type":"error"},{"inputs":[],"name":"MSG_VALUE_WRONG_AMOUNT","type":"error"},{"inputs":[{"internalType":"uint256","name":"outputValue","type":"uint256"}],"name":"NONZERO_OUTPUT_VALUE_ON_NOT_USED_ASSET","type":"error"},{"inputs":[],"name":"NOT_PAUSED","type":"error"},{"inputs":[],"name":"PAUSED","type":"error"},{"inputs":[],"name":"PENDING_CAP_SURPASSED","type":"error"},{"inputs":[],"name":"PROOF_VERIFICATION_FAILED","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"PUBLIC_INPUTS_HASH_VERIFICATION_FAILED","type":"error"},{"inputs":[],"name":"SAFE_CAST_OVERFLOW","type":"error"},{"inputs":[],"name":"SIGNATURE_ADDRESS_IS_ZERO","type":"error"},{"inputs":[],"name":"SIGNATURE_RECOVERY_FAILED","type":"error"},{"inputs":[],"name":"THIRD_PARTY_CONTRACTS_FLAG_NOT_SET","type":"error"},{"inputs":[],"name":"WITHDRAW_TO_ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"ZERO_TOTAL_INPUT_VALUE","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowThirdPartyContractsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetGasLimit","type":"uint256"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dailyCap","type":"uint256"}],"name":"AssetCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInputValue","type":"uint256"}],"name":"AsyncDefiBridgeProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"bridgeAddressId","type":"uint256"},{"indexed":true,"internalType":"address","name":"bridgeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgeGasLimit","type":"uint256"}],"name":"BridgeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isCapped","type":"bool"}],"name":"CappedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalInputValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalOutputValueA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalOutputValueB","type":"uint256"},{"indexed":false,"internalType":"bool","name":"result","type":"bool"},{"indexed":false,"internalType":"bytes","name":"errorReason","type":"bytes"}],"name":"DefiBridgeProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"defiBridgeProxy","type":"address"}],"name":"DefiBridgeProxyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"delay","type":"uint32"}],"name":"DelayBeforeEscapeHatchUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositValue","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chunk","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalChunks","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"OffchainData","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rollupId","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"nextExpectedDefiHashes","type":"bytes32[]"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"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"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LISTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESUME_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowThirdPartyContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"approveProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"assetGasLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"asyncDefiInteractionHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bridgeGasLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"caps","outputs":[{"internalType":"uint128","name":"available","type":"uint128"},{"internalType":"uint32","name":"lastUpdatedTimestamp","type":"uint32"},{"internalType":"uint32","name":"pendingCap","type":"uint32"},{"internalType":"uint32","name":"dailyCap","type":"uint32"},{"internalType":"uint8","name":"precision","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defiBridgeProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"defiInteractionHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delayBeforeEscapeHatch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bytes32","name":"_proofHash","type":"bytes32"}],"name":"depositPendingFunds","outputs":[],"stateMutability":"payable","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":"uint256","name":"","type":"uint256"}],"name":"ethPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAsyncDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCapped","outputs":[{"internalType":"bool","name":"capped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDataSize","outputs":[{"internalType":"uint256","name":"dataSize","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEscapeHatchStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementationVersion","outputs":[{"internalType":"uint8","name":"version","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingDefiInteractionHashesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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":"getSupportedAssetsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bridgeAddressId","type":"uint256"}],"name":"getSupportedBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedBridgesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRollupTimeStamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rollupId","type":"uint256"},{"internalType":"uint256","name":"_chunk","type":"uint256"},{"internalType":"uint256","name":"_totalChunks","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"offchainData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingDefiInteractions","outputs":[{"internalType":"uint256","name":"encodedBridgeCallData","type":"uint256"},{"internalType":"uint256","name":"totalInputValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevDefiInteractionsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interactionNonce","type":"uint256"}],"name":"processAsyncDefiInteraction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"processRollup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interactionNonce","type":"uint256"}],"name":"receiveEthFromBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rollupProviders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupStateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowThirdPartyContracts","type":"bool"}],"name":"setAllowThirdPartyContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetId","type":"uint256"},{"internalType":"uint32","name":"_pendingCap","type":"uint32"},{"internalType":"uint32","name":"_dailyCap","type":"uint32"},{"internalType":"uint8","name":"_precision","type":"uint8"}],"name":"setAssetCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isCapped","type":"bool"}],"name":"setCapped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_defiBridgeProxy","type":"address"}],"name":"setDefiBridgeProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_delay","type":"uint32"}],"name":"setDelayBeforeEscapeHatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_provider","type":"address"},{"internalType":"bool","name":"_valid","type":"bool"}],"name":"setRollupProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setSupportedAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setSupportedBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifier","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","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":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b506040516200610d3803806200610d83398101604081905262000034916200014e565b811580620000425750808210155b15620000615760405163b37657e760e01b815260040160405180910390fd5b6200006b6200008d565b6002805460ff60e81b1916600160e81b17905560809190915260a05262000173565b600054610100900460ff1615620000fa5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146200014c576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b600080604083850312156200016257600080fd5b505080516020909101519092909150565b60805160a051615f4a620001c360003960008181610b7801528181612acf01528181612b2e01528181612b590152612b8901526000818161098201528181612aab0152612bb40152615f4a6000f3fe6080604052600436106103975760003560e01c80638666c0a9116101dc578063c37c656d11610102578063dcefed85116100a0578063e58378bb1161006f578063e58378bb14610c72578063f21c69bb14610ca6578063f81cccbe14610cd3578063fb0ce18514610cf357600080fd5b8063dcefed8514610bd1578063deb26b9414610bfe578063e0d16c3214610c32578063e393635514610c5257600080fd5b8063cd12bf62116100dc578063cd12bf6214610b19578063d547741f14610b46578063d8ba363714610b66578063db1533aa14610b9a57600080fd5b8063c37c656d14610a21578063c4a7a35f14610ad4578063caa3455314610af957600080fd5b8063a2b096e41161017a578063b3a07b9811610149578063b3a07b98146109a4578063bc327e40146109c4578063be71f8a4146109e0578063c0fd22b714610a0c57600080fd5b8063a2b096e41461090e578063a33dc5e71461092e578063a8d1eae71461095b578063b045009c1461097057600080fd5b806391dfe78f116101b657806391dfe78f14610899578063999e3614146108b95780639b60ae2b146108da578063a217fddf146108f957600080fd5b80638666c0a9146107ea5780638afceb391461080a57806391d148541461085357600080fd5b806336ce0a92116102c1578063781e04321161025f5780637ff48afb1161022e5780637ff48afb1461078d5780638129fc1c146107a05780638188f468146107b55780638456cb59146107d557600080fd5b8063781e0432146106fa5780637ba3e7ae146107355780637baf71181461074b5780637d036b271461076b57600080fd5b80635ad1def31161029b5780635ad1def31461066b5780635c975abb1461069b57806360a8b18a146106ba5780636a0214a9146106da57600080fd5b806336ce0a92146105fe5780633f4ba83a146106365780635437988d1461064b57600080fd5b806320825443116103395780632b7ac3f3116103085780632b7ac3f31461056c5780632de03aa11461058a5780632f2ff15d146105be57806336568abe146105de57600080fd5b806320825443146104b557806320a23dd3146104d557806320df435914610507578063248a9ca31461053b57600080fd5b80630ceee68c116103755780630ceee68c146104215780630d698f6f1461045957806312a536231461047b5780631ab9c6031461049f57600080fd5b806301ffc9a71461039c57806302f6ccd4146103d157806303561119146103f4575b600080fd5b3480156103a857600080fd5b506103bc6103b736600461575f565b610d13565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610dac565b6040519081526020016103c8565b34801561040057600080fd5b506103e661040f3660046157a1565b600e6020526000908152604090205481565b34801561042d57600080fd5b50600a54610441906001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b34801561046557600080fd5b506104796104743660046157c8565b610df0565b005b6104796104893660046157a1565b6000908152600d60205260409020805434019055565b3480156104ab57600080fd5b506103e660095481565b3480156104c157600080fd5b506104796104d036600461582e565b610f39565b3480156104e157600080fd5b506011546104f29063ffffffff1681565b60405163ffffffff90911681526020016103c8565b34801561051357600080fd5b506103e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681565b34801561054757600080fd5b506103e66105563660046157a1565b6000908152600160208190526040909120015490565b34801561057857600080fd5b506002546001600160a01b0316610441565b34801561059657600080fd5b506103e67f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b3480156105ca57600080fd5b506104796105d93660046158a6565b610fad565b3480156105ea57600080fd5b506104796105f93660046158a6565b610fd8565b34801561060a57600080fd5b506103e66106193660046158a6565b600760209081526000928352604080842090915290825290205481565b34801561064257600080fd5b50610479611069565b34801561065757600080fd5b506104796106663660046158d2565b611186565b34801561067757600080fd5b506103bc6106863660046158d2565b600b6020526000908152604090205460ff1681565b3480156106a757600080fd5b50600254600160e81b900460ff166103bc565b3480156106c657600080fd5b506104416106d53660046157a1565b611297565b3480156106e657600080fd5b506104796106f5366004615901565b611343565b34801561070657600080fd5b506103bc61071536600461591c565b600860209081526000928352604080842090915290825290205460ff1681565b34801561074157600080fd5b506103e660105481565b34801561075757600080fd5b50600254600160c01b900461ffff166103e6565b34801561077757600080fd5b50600254600160a01b900463ffffffff166103e6565b61047961079b366004615946565b61142b565b3480156107ac57600080fd5b50610479611693565b3480156107c157600080fd5b506103bc6107d03660046157a1565b611ae9565b3480156107e157600080fd5b5061047961238f565b3480156107f657600080fd5b5061047961080536600461591c565b61249a565b34801561081657600080fd5b5061083e6108253660046157a1565b600c602052600090815260409020805460019091015482565b604080519283526020830191909152016103c8565b34801561085f57600080fd5b506103bc61086e3660046158a6565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108a557600080fd5b506104796108b4366004615983565b6126c4565b3480156108c557600080fd5b50600a546103bc90600160a01b900460ff1681565b3480156108e657600080fd5b50600254600160f01b900460ff166103bc565b34801561090557600080fd5b506103e6600081565b34801561091a57600080fd5b506104796109293660046157c8565b6127ad565b34801561093a57600080fd5b506103e66109493660046157a1565b60066020526000908152604090205481565b34801561096757600080fd5b506004546103e6565b34801561097c57600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000000081565b3480156109b057600080fd5b506104796109bf3660046159ba565b612891565b3480156109d057600080fd5b50604051600281526020016103c8565b3480156109ec57600080fd5b506109f5612aa4565b6040805192151583526020830191909152016103c8565b348015610a1857600080fd5b506003546103e6565b348015610a2d57600080fd5b50610a93610a3c3660046157a1565b6012602052600090815260409020546001600160801b0381169063ffffffff7001000000000000000000000000000000008204811691600160a01b8104821691600160c01b8204169060ff600160e01b9091041685565b604080516001600160801b03909616865263ffffffff94851660208701529284169285019290925291909116606083015260ff16608082015260a0016103c8565b348015610ae057600080fd5b506011546104f290640100000000900463ffffffff1681565b348015610b0557600080fd5b50610479610b143660046158d2565b612be5565b348015610b2557600080fd5b506103e6610b343660046157a1565b60056020526000908152604090205481565b348015610b5257600080fd5b50610479610b613660046158a6565b612ce3565b348015610b7257600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000000081565b348015610ba657600080fd5b506002547a010000000000000000000000000000000000000000000000000000900461ffff166103e6565b348015610bdd57600080fd5b506103e6610bec3660046157a1565b600d6020526000908152604090205481565b348015610c0a57600080fd5b506103e67ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c81565b348015610c3e57600080fd5b50610441610c4d3660046157a1565b612d09565b348015610c5e57600080fd5b50610479610c6d3660046157a1565b612d43565b348015610c7e57600080fd5b506103e67fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e81565b348015610cb257600080fd5b506103e6610cc13660046157a1565b600f6020526000908152604090205481565b348015610cdf57600080fd5b50610479610cee366004615a0f565b612d8e565b348015610cff57600080fd5b50610479610d0e36600461591c565b612f23565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610da657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600254600090610de79061ffff7a0100000000000000000000000000000000000000000000000000008204811691600160c01b900416615a91565b61ffff16905090565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e610e1a8161312e565b600060028054600160e01b900460ff1690811115610e3a57610e3a615ab7565b14610e5857604051631e7b117d60e01b815260040160405180910390fd5b60028054819060ff60e01b1916600160e01b820217905550600254600160f01b900460ff1615158215151415610e8d57610f1a565b8115610ea9576011805463ffffffff19164263ffffffff161790555b60028054831515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517f99895cad53cbbff374fbe3c76182ad42a6cb1c0c7306d3b6651786e7154ccbe690610f1190841515815260200190565b60405180910390a15b600280546000919060ff60e01b1916600160e01b835b02179055505050565b600254600160e81b900460ff1615610f6457604051632a6ab56360e21b815260040160405180910390fd5b60408051858152602081018590523381830152905186917fb92710e3fad9222f817fcd828bd1ce3612ad0cd1c8bd5f3a3f4b8d85c4444621919081900360600190a25050505050565b60008281526001602081905260409091200154610fc98161312e565b610fd3838361313b565b505050565b6001600160a01b038116331461105b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61106582826131c2565b5050565b600254600160e81b900460ff166110ac576040517f395fbd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c76110d68161312e565b600060028054600160e01b900460ff16908111156110f6576110f6615ab7565b1461111457604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e11b1790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1506002805460ff60e01b19169055565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6111b08161312e565b600060028054600160e01b900460ff16908111156111d0576111d0615ab7565b146111ee57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b611229576040516310a0493960e11b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a2600280546000919060ff60e01b1916600160e01b83610f30565b600081631fffffff8111156112bf57604051630104ef3360e21b815260040160405180910390fd5b826112cd576000915061133d565b600060036112dc600186615acd565b815481106112ec576112ec615ae4565b6000918252602090912001546001600160a01b031690508061133a576040517ffc3be2bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91505b50919050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e61136d8161312e565b600060028054600160e01b900460ff169081111561138d5761138d615ab7565b146113ab57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055601180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8516908102919091179091556040519081527f536948e5a71b8ffbb707a6903b99b812c8c291a711ed188e54d36505127d1c3590602001610f11565b600254600160e81b900460ff161561145657604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff169081111561147657611476615ab7565b1461149457604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055831580156114b55750823414155b156114ec576040517ff2be5ced00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83158015906114fa57503415155b15611531576040517fd08ba85b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153c848385613245565b801561154b5761154b81612d43565b816001600160a01b0316847feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b98560405161158791815260200190565b60405180910390a383156116725760006115a085611297565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290915084906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c9190615afa565b1015611664576040517f7bf8af0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611670813330876135f6565b505b600280546000919060ff60e01b1916600160e01b835b021790555050505050565b6002600054610100900460ff161580156116b4575060005460ff8083169116105b6117265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611052565b806000806101000a81548160ff021916908360ff1602179055506001600060016101000a81548160ff02191690831515021790555060016002600001601e6101000a81548160ff02191690831515021790555042601160006101000a81548163ffffffff021916908363ffffffff1602179055506040518060a00160405280683635c9adc5dea000006001600160801b031681526020014263ffffffff168152602001600663ffffffff1681526020016103e863ffffffff168152602001601260ff168152506012600080815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050506040518060a0016040528069d3c21bcecceda10000006001600160801b031681526020014263ffffffff16815260200161277463ffffffff168152602001620f424063ffffffff168152602001601260ff16815250601260006001815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050507f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e600060066103e8604051611a3c939291909283526020830191909152604082015260600190565b60405180910390a160408051600181526127746020820152620f42408183015290517f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e9181900360600190a1600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600254600090600160e81b900460ff1615611b1757604051632a6ab56360e21b815260040160405180910390fd5b600254600160e01b900460ff166001816002811115611b3857611b38615ab7565b1415611f3c576000838152600c60205260409020805460019091015481611b8b576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b9683613675565b9050600080600080611ba8858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b031680611c21576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b8152600401611cad96959493929190615b58565b6060604051808303816000875af1158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615bb2565b92509250925080611d26575050506020908101516000908152600c90915260408120989098555095975061133d95505050505050565b600082118015611d4b5750600086604001516003811115611d4957611d49615ab7565b145b15611d85576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b82158015611d91575081155b15611dc357611daa858a86600001518760200151613bcb565b611dbe858986600001518760200151613bcb565b611de3565b611dd38588858760200151613bcb565b611de38587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff166102008183600101011115611e8357632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e505050505050505050505050505061133d565b6000816002811115611f5057611f50615ab7565b1415612376576002805460ff60e01b1916600160e01b1790556000838152600c6020526040902080546001919091015481611fb7576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc283613675565b9050600080600080611fd4858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b03168061204d576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b81526004016120d996959493929190615b58565b6060604051808303816000875af11580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190615bb2565b92509250925080612152575050506020908101516000908152600c90915260408120989098555095975061236495505050505050565b600082118015612177575060008660400151600381111561217557612175615ab7565b145b156121b1576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b821580156121bd575081155b156121ef576121d6858a86600001518760200151613bcb565b6121ea858986600001518760200151613bcb565b61220f565b6121ff8588858760200151613bcb565b61220f8587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff1661020081836001010111156122af57632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e50505050505050505050505050505b6002805460ff60e01b1916905561133d565b604051631e7b117d60e01b815260040160405180910390fd5b600254600160e81b900460ff16156123ba57604051632a6ab56360e21b815260040160405180910390fd5b7fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266123e48161312e565b600060028054600160e01b900460ff169081111561240457612404615ab7565b1461242257604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0102000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161116e565b600254600160e81b900460ff16156124c557604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff1615801561250e5750600a54600160a01b900460ff16155b15612545576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff169081111561256557612565615ab7565b1461258357604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b6125be576040516310a0493960e11b815260040160405180910390fd5b6188b88110806125d05750624c4b4081115b15612607576040517f037bbe6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546001810182557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600f6020908152604091829020859055905184815291929183917f0e62be7fe47a9095143143f8ee61bab3ade27b661223fed33e16122ffe1f284d91015b60405180910390a350600280546000919060ff60e01b1916600160e01b83610f30565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6126ee8161312e565b600060028054600160e01b900460ff169081111561270e5761270e615ab7565b1461272c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0383166000818152600b6020908152604091829020805460ff1916861515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a250506002805460ff60e01b1916905550565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6127d78161312e565b600060028054600160e01b900460ff16908111156127f7576127f7615ab7565b1461281557604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055600a8054831515600160a01b81027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179091556040519081527fad6b1fc8881be24fc1ad35119b136f0026a4496e6251980e325ddcf86dab394390602001610f11565b7ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c6128bb8161312e565b600060028054600160e01b900460ff16908111156128db576128db615ab7565b146128f957604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556040805160a081019091528061293b61292685600a615ccf565b6129369063ffffffff8816615cde565b613c86565b6001600160801b03908116825263ffffffff4281166020808501919091528882166040808601829052898416606080880182905260ff8b81166080998a015260008f8152601287528490208a5181548c8901518d8801518e8701519e909d0151909416600160e01b0260ff60e01b199d8b16600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9d8c16600160a01b029d909d167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff95909b167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1990921692909b169190911717919091169690961797909717979097169490941790925582518a815290810191909152908101929092527f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e910160405180910390a150506002805460ff60e01b19169055505050565b60008043817f0000000000000000000000000000000000000000000000000000000000000000612af47f000000000000000000000000000000000000000000000000000000000000000084615d13565b1015905060008115612b8457601154612b1d9063ffffffff640100000000820481169116615d27565b421015612b2957600091505b612b537f000000000000000000000000000000000000000000000000000000000000000084615d13565b612b7d907f0000000000000000000000000000000000000000000000000000000000000000615acd565b9050612bdb565b612bae7f000000000000000000000000000000000000000000000000000000000000000084615d13565b612bd8907f0000000000000000000000000000000000000000000000000000000000000000615acd565b90505b9094909350915050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e612c0f8161312e565b600060028054600160e01b900460ff1690811115612c2f57612c2f615ab7565b14612c4d57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b612c88576040516310a0493960e11b815260040160405180910390fd5b600a805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527fc4fc5cbf094d63a6fb20dc7cb9b0236e7dba8c04667182ec259a00a74f95901890602001610f11565b60008281526001602081905260409091200154612cff8161312e565b610fd383836131c2565b60006004612d18600184615acd565b81548110612d2857612d28615ae4565b6000918252602090912001546001600160a01b031692915050565b600254600160e81b900460ff1615612d6e57604051632a6ab56360e21b815260040160405180910390fd5b336000526008602052604060002060205280600052600160406000205550565b600254600160e81b900460ff1615612db957604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612dd957612dd9615ab7565b14612df757604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e01b179055336000908152600b602052604090205460ff1615612e4f57600254600160f01b900460ff1615612e4a576011805463ffffffff19164263ffffffff161790555b612e95565b6000612e59612aa4565b50905080612e93576040517f83633aab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b6000806000612ea2613ccd565b9250925092506000612eb384614069565b9050612efa8487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250879150869050614088565b612f0484826140f2565b5050600280546000935090915060ff60e01b1916600160e01b83611688565b600254600160e81b900460ff1615612f4e57604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff16158015612f975750600a54600160a01b900460ff16155b15612fce576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612fee57612fee615ab7565b1461300c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b613047576040516310a0493960e11b815260040160405180910390fd5b61d6d881108061305957506216e36081115b15613090576040517f11e80d6c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546001810182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600e6020908152604091829020859055905184815291929183917f85ac039d1da307b778050ca29271ac915424bac011342c9452960f6679b18ff091016126a1565b6131388133614177565b50565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff166110655760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16156110655760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b82631fffffff81111561326b57604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083206001600160a01b0387168452909152902054600254600160f01b900460ff16156135be576000858152601260209081526040808320815160a08101835290546001600160801b038116825263ffffffff7001000000000000000000000000000000008204811694830194909452600160a01b8104841692820192909252600160c01b8204909216606083015260ff600160e01b909104166080820181905290919061332890600a615ccf565b9050816040015163ffffffff1660001480613360575080826040015163ffffffff166133549190615cde565b61335e8685615d27565b115b15613397576040517ffb1837c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015163ffffffff166133d8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081836060015163ffffffff166133f09190615cde565b905060006134016201518083615d3f565b9050613426846020015163ffffffff164261341c9190615acd565b6129369083615cde565b84518590613435908390615d53565b6001600160801b0390811690915285511683101590506134645761345882613c86565b6001600160801b031684525b83516001600160801b03168711156134a8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134b187613c86565b845185906134c0908390615d75565b6001600160801b0390811690915263ffffffff428116602080890191825260008e81526012909152604090819020895181549351928b015160608c015160808d015160ff16600160e01b0260ff60e01b19918816600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff938916600160a01b02939093167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff969098167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff199097169390981692909217949094179290921693909317919091171691909117905550505050505b6135c88382615d27565b60009586526007602090815260408088206001600160a01b0390971688529590529390942092909255505050565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152836004820152826024820152816044820152843b613645576310a0493960e11b60005260046000fd5b602060006064836000895af190506001600051163d151780821661366d573d6000803e3d6000fd5b505050505050565b604080516101c081018252600060208083018290526101a083019190915263ffffffff8416808352633fffffff9185901c821693830193909352603e84901c81166060830152605c84901c81166080830152607a84901c1660a082015267ffffffffffffffff60b884901c1660c08201526001603d84901c811660e0830152605b84901c8116610100830152607984901c8116610120830152609784901c8116610140830152609884901c81168114610160830152609984901c81168114610180830152909160049161374791615acd565b8154811061375757613757615ae4565b60009182526020808320909101546001600160a01b03168382015282518252600f905260409020546101a082015261016081015115801561379c575060008160600151115b156137d3576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061018001511580156137ea575060008160a00151115b15613821576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101600151801561383a575080606001518160400151145b156138795780604001516040517f760558e800000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b600081610180015180156138905750816101400151155b90508080156138a657508160a001518260800151145b1561133d5781608001516040517ff23e3f9500000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b61390660408051606081018252600080825260208201819052909182015290565b61392760408051606081018252600080825260208201819052909182015290565b61394860408051606081018252600080825260208201819052909182015290565b61396960408051606081018252600080825260208201819052909182015290565b8560e001511561399c57632000000086604001516139879190615acd565b845260006020850152600360408501526139fa565b6040860180518552516139ae90611297565b6001600160a01b031660208501819052156139ca5760026139cd565b60015b846040019060038111156139e3576139e3615ab7565b908160038111156139f6576139f6615ab7565b9052505b85610120015115613a1b578482526000602083015260036040830152613a79565b608086018051835251613a2d90611297565b6001600160a01b03166020830181905215613a49576002613a4c565b60015b82604001906003811115613a6257613a62615ab7565b90816003811115613a7557613a75615ab7565b9052505b85610100015115613ac35763200000008660600151613a989190615acd565b8352600060208401526040830160035b90816003811115613abb57613abb615ab7565b905250613b27565b85610160015115613b1557606086018051845251613ae090611297565b6001600160a01b03166020840181905215613afc576002613aff565b60015b83604001906003811115613aa857613aa8615ab7565b60008084526020840181905260408401525b85610140015115613b5e57848152600060208201526040810160035b90816003811115613b5657613b56615ab7565b905250613bc2565b85610180015115613bb05760a086018051825251613b7b90611297565b6001600160a01b03166020820181905215613b97576002613b9a565b60015b81604001906003811115613b4357613b43615ab7565b60008082526020820181905260408201525b92959194509250565b81613bd557613c80565b600183604001516003811115613bed57613bed615ab7565b1415613c4f576000818152600d6020526040902054821115613c3b576040517fcbbf6eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600d6020526040812055613c80565b600283604001516003811115613c6757613c67615ab7565b1415613c80576020830151613c7e818630866135f6565b505b50505050565b60006001600160801b03821115613cc9576040517f7a781de100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b6040805161010080820183526141ec82526141f360208084018290528385019190915261421e606084018190526080840181905260a0840181905260c084015261423360e084015283516111c46004359081013560448201359081046111c883013563ffffffff908116828104808402821415019092029096028481016111e0019098526111c08881018086529498919760009795968a0195602486019589948594615755949391926111cc013590911690888a376111c098909801976111a9888101988a97509091010193505b86841115613dd15760078735168089528060051b830151935050613dc387898563ffffffff16565b965061010088019750613d9b565b505050506111c088810151604051600092828604808c048082028d1415019384900393909261010084029260043560240182376111c08101905060208202810191505b81811015613e635760206000848960025afa613e2f57600080fd5b6000517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006815295820195602001613e14565b8415613fe057600092508360208114613eaf5760108114613ed75760408114613eff5760018114613f275760028114613f4f5760048114613f775760088114613f9f5760019650613fc3565b7f0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d449350613fc3565b7f1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca49350613fc3565b7f1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd9350613fc3565b7f22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af09350613fc3565b7f076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f365609350613fc3565b7f2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee9350613fc3565b7f240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a993505b5060208502820191505b81811015613fe057828152602001613fcd565b6040519450602060008683038760025afa613ffa57600080fd5b50505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051069650801561405e576040517f3259ec1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050909192565b6111a08101516001600160a01b0381111561408357600080fd5b919050565b60006140948684614267565b90506140a1868587614338565b60006140ad8784614400565b9050817f14054a15b39bfd65ec00fc6d15c7e5f9cbc1dc6f452cbefa359b4da61ad89fb682336040516140e1929190615d9d565b60405180910390a250505050505050565b60005b6010811015610fd3576000614111848360200201610b80015190565b9050801561416e576000614125858461493e565b90508061413e57600080600080858861c350f15061416c565b600061414982611297565b905061416a818685600e60008781526020019081526020016000205461495a565b505b505b506001016140f5565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16611065576141aa816149aa565b6141b58360206149bc565b6040516020016141c6929190615e1d565b60408051601f198184030181529082905262461bcd60e51b825261105291600401615e9e565b5060010190565b600060a0602084016020840137601460c0840160cc840137600460d4840160fc840137505060b90190565b60006080602084016020840137505060810190565b60006040517fd0426f7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160009063ffffffff600480356111cc810135929092168083016111ec01939290910135037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee38019060ac815360316001820153608c6002820153605d600382015360406004820152846024820152816044820152818360648301376001600160a01b03600254169250823b614309576310a0493960e11b60005260046000fd5b6000806064840183865afa9250505080614327573d6000803e3d6000fd5b5061433183614be5565b9392505050565b60006111e08085019061010085028601015b8082101561366d5760a082015180156143f357825160e084015160c085015160018314156143db5761010086206001600160a01b038216600090815260086020908152604080832084845290915290205460ff166143ce5788880180516060825260006143b684614d98565b90506143c3818487614eb1565b509052606097909701965b6143d9838387614ffd565b505b82600214156143ef576143ef84828461507e565b5050505b610100830192505061434a565b606060008061441185611180015190565b9050601054811461445c576010546040517f88011dd6000000000000000000000000000000000000000000000000000000008152611052918391600401918252602082015260400190565b6000614466615101565b90935090506144758184615acd565b600280547ffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffffffff1660d083901b1790556020878101519194506000935091506144bc9190615cde565b6040805160808082018352600080835260208301819052828401819052606090920182905282519081019092529192506101808701915b6020811015614870578251806145095750614870565b61040084015180614546576040517fb246041300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061455183613675565b9050600080600080614563858c6138e5565b93509350935093506040517f4bd947a800000000000000000000000000000000000000000000000000000000815260048101905060208601518082525084516020820152602085015160408201526040850151606082015283516080820152602084015160a0820152604084015160c0820152825160e082015260208301516101008201526040830151610120820152815161014082015260208201516101608201526040820151610180820152866101a08201528b6101c082015260c0860151806101e083015250600d6102008201528e610220820152600a54803b614655576310a0493960e11b60005260046000fd5b60008061024460048503846101a08c0151f490503d6000833e80600181146146955760008c52600060208d0152600060408d0152600060608d01526146b5565b82518c52602083015160208d0152604083015160408d0152600160608d01525b5050508461018001516146ca57600060208a01525b60408901516001811461480a576040518781528a51602082015260208b0151604082015260608b0151606082015260a0608082015260608b01511561473857600060a08201528c897f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c60c084a35b60608b0151614792573d60a08201523d602081066020038115150281600060c085013e60008260c0018401528e8b7f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c83850160c00186a350505b8881528c60208201528760408201528a51606082015260208b0151608082015260608b015160a08201526020600060c08360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051068d6000526006602052806040600020555060018d019c50614851565b6040518781528c897f38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d602084a3508b600052600c6020526040600020888155876001820155505b5060018b019a5060208a019950876001019750505050505050506144f3565b506002548060c01c6103ff166103ff86820111801561489a57632c52558760e11b60005260046000fd5b506040516006602052600560605260005b828110156148cf5787810160009081526040828152808020549120556001016148ab565b506040527ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff90860160d01b167ffffffffffc00fc00ffffffffffffffffffffffffffffffffffffffffffffffff9091161760025560008061492e615123565b6010559998505050505050505050565b602081028201610980015163ffffffff811115610da657600080fd5b5a81156149645750805b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815284600482015283602482015260008060448360008a87f150505050505050565b6060610da66001600160a01b03831660145b606060006149cb836002615cde565b6149d6906002615d27565b67ffffffffffffffff8111156149ee576149ee615ed1565b6040519080825280601f01601f191660200182016040528015614a18576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110614a4f57614a4f615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110614ab257614ab2615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000614aee846002615cde565b614af9906001615d27565b90505b6001811115614b96577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614b3a57614b3a615ae4565b1a60f81b828281518110614b5057614b50615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93614b8f81615ee7565b9050614afc565b5083156143315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611052565b600080600080600080614bf7876151ff565b945094509450945094506009548414614c46576040517f34fddf400000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401611052565b60025463ffffffff600160a01b90910481169083168181614c6957614c69615cfd565b0663ffffffff1660001415614cd2578063ffffffff168263ffffffff1614614ccd576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff808416600483015282166024820152604401611052565b614d4c565b60008363ffffffff168263ffffffff1681614cef57614cef615cfd565b068483010363ffffffff169050808363ffffffff1614614d4a576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260248101829052604401611052565b505b506009929092556002805463ffffffff9390920192909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161790555092915050565b600080614da4836152a8565b90506040517f19457468657265756d205369676e6564204d6573736167653a0a32313000000060208201527f5369676e696e672074686973206d6573736167652077696c6c20616c6c6f7720603d8201527f796f75722070656e64696e672066756e647320746f206265207370656e742069605d8201527f6e20417a746563207472616e73616374696f6e3a0a0a30780000000000000000607d82015260208201516095820152604082015160b58201527f0a0a494d504f5254414e543a204f6e6c79207369676e20746865206d6573736160d58201527f676520696620796f752074727573742074686520636c69656e7400000000000060f582015260ef602082012092505050919050565b6000806001600160a01b038316614ef4576040517fd57e351000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351858552606085015160408601518060608801526020870151604088015281602088015260208760808960015afa601c8314601b84141760608514167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a183101616945050508451861460008114614f6b57614f70565b855192505b508452801519919091169081614fb2576040517f8a3e28aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316816001600160a01b031614613c7e576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82631fffffff81111561502357604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083209091528482529020805483810390915582118015613c7e576040517f8e8af4f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166150be576040517f6df19fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806150d5576000806000808686617530f150505050565b60006150e082611297565b9050613c80818486600e60008781526020019081526020016000205461495a565b6002546103ff60d082901c16908190602082111561511e57602091505b509091565b60606000806000615132615101565b909250905060006151438284615acd565b90506040519450602085016020610400018601604052828652600660205260005b83811015615188578281016000908152604090205460208202830152600101615164565b5b60208110156151c2577f2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b460208202830152600101615189565b50602060006104008360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016000510693505050509091565b604081015160608201516000918291829160011b906020860163ffffffff808411908311171561522e57600080fd5b805195506040518681526060820151602082015260a0820151604082015260e08201516060820152610120820151608082015260a0812095506001870181526080820151602082015260c082015160408201526101008201516060820152610140820151608082015260a081209450505091939590929450565b606081615310576040519050604081527f303030303030303030303030303030303030303030303030303030303030303060208201527f3030303030303030303030303030303030303030303030303030303030303030604082015260608101604052919050565b506040517f3030303130323033303430353036303730383039306130623063306430653066607e8201527f3130313131323133313431353136313731383139316131623163316431653166609e8201527f323032313232323332343235323632373238323932613262326332643265326660be8201527f333033313332333333343335333633373338333933613362336333643365336660de8201527f343034313432343334343435343634373438343934613462346334643465346660fe8201527f353035313532353335343535353635373538353935613562356335643565356661011e8201527f363036313632363336343635363636373638363936613662366336643665366661013e8201527f373037313732373337343735373637373738373937613762376337643765376661015e8201527f383038313832383338343835383638373838383938613862386338643865386661017e8201527f393039313932393339343935393639373938393939613962396339643965396661019e8201527f61306131613261336134613561366137613861396161616261636164616561666101be8201527f62306231623262336234623562366237623862396261626262636264626562666101de8201527f63306331633263336334633563366337633863396361636263636364636563666101fe8201527f643064316432643364346435643664376438643964616462646364646465646661021e8201527f653065316532653365346535653665376538653965616562656365646565656661023e8201527f663066316632663366346635663666376638663966616662666366646665666661025e820152606081018260408352600181901b6101fe908116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c8116830151600252607782901c16820151600052601e51604084015260801c61573f82826101fe600182901b8116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c811683015160025260779190911c160151600052565b5050601e51602082015260608101604052919050565b61575d615efe565b565b60006020828403121561577157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461433157600080fd5b6000602082840312156157b357600080fd5b5035919050565b801515811461313857600080fd5b6000602082840312156157da57600080fd5b8135614331816157ba565b60008083601f8401126157f757600080fd5b50813567ffffffffffffffff81111561580f57600080fd5b60208301915083602082850101111561582757600080fd5b9250929050565b60008060008060006080868803121561584657600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561587257600080fd5b61587e888289016157e5565b969995985093965092949392505050565b80356001600160a01b038116811461408357600080fd5b600080604083850312156158b957600080fd5b823591506158c96020840161588f565b90509250929050565b6000602082840312156158e457600080fd5b6143318261588f565b803563ffffffff8116811461408357600080fd5b60006020828403121561591357600080fd5b614331826158ed565b6000806040838503121561592f57600080fd5b6159388361588f565b946020939093013593505050565b6000806000806080858703121561595c57600080fd5b84359350602085013592506159736040860161588f565b9396929550929360600135925050565b6000806040838503121561599657600080fd5b61599f8361588f565b915060208301356159af816157ba565b809150509250929050565b600080600080608085870312156159d057600080fd5b843593506159e0602086016158ed565b92506159ee604086016158ed565b9150606085013560ff81168114615a0457600080fd5b939692955090935050565b60008060008060408587031215615a2557600080fd5b843567ffffffffffffffff80821115615a3d57600080fd5b615a49888389016157e5565b90965094506020870135915080821115615a6257600080fd5b50615a6f878288016157e5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600061ffff808316818516808303821115615aae57615aae615a7b565b01949350505050565b634e487b7160e01b600052602160045260246000fd5b600082821015615adf57615adf615a7b565b500390565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615b0c57600080fd5b5051919050565b805182526001600160a01b036020820151166020830152604081015160048110615b4d57634e487b7160e01b600052602160045260246000fd5b806040840152505050565b6101c08101615b678289615b13565b615b746060830188615b13565b615b8160c0830187615b13565b615b8f610120830186615b13565b8361018083015267ffffffffffffffff83166101a0830152979650505050505050565b600080600060608486031215615bc757600080fd5b83519250602084015191506040840151615be0816157ba565b809150509250925092565b600181815b80851115615c26578160001904821115615c0c57615c0c615a7b565b80851615615c1957918102915b93841c9390800290615bf0565b509250929050565b600082615c3d57506001610da6565b81615c4a57506000610da6565b8160018114615c605760028114615c6a57615c86565b6001915050610da6565b60ff841115615c7b57615c7b615a7b565b50506001821b610da6565b5060208310610133831016604e8410600b8410161715615ca9575081810a610da6565b615cb38383615beb565b8060001904821115615cc757615cc7615a7b565b029392505050565b600061433160ff841683615c2e565b6000816000190483118215151615615cf857615cf8615a7b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615d2257615d22615cfd565b500690565b60008219821115615d3a57615d3a615a7b565b500190565b600082615d4e57615d4e615cfd565b500490565b60006001600160801b03808316818516808303821115615aae57615aae615a7b565b60006001600160801b0383811690831681811015615d9557615d95615a7b565b039392505050565b604080825283519082018190526000906020906060840190828701845b82811015615dd657815184529284019290840190600101615dba565b5050506001600160a01b039490941692019190915250919050565b60005b83811015615e0c578181015183820152602001615df4565b83811115613c805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615e55816017850160208801615df1565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615e92816028840160208801615df1565b01602801949350505050565b6020815260008251806020840152615ebd816040850160208701615df1565b601f01601f19169190910160400192915050565b634e487b7160e01b600052604160045260246000fd5b600081615ef657615ef6615a7b565b506000190190565b634e487b7160e01b600052605160045260246000fdfea26469706673582212204986047a3c1dc740c0f7b2da538464da5d8465856c4b6d0dec03c81aa8d6df1564736f6c634300080a003300000000000000000000000000000000000000000000000000000000000008700000000000000000000000000000000000000000000000000000000000000960
Deployed Bytecode
0x6080604052600436106103975760003560e01c80638666c0a9116101dc578063c37c656d11610102578063dcefed85116100a0578063e58378bb1161006f578063e58378bb14610c72578063f21c69bb14610ca6578063f81cccbe14610cd3578063fb0ce18514610cf357600080fd5b8063dcefed8514610bd1578063deb26b9414610bfe578063e0d16c3214610c32578063e393635514610c5257600080fd5b8063cd12bf62116100dc578063cd12bf6214610b19578063d547741f14610b46578063d8ba363714610b66578063db1533aa14610b9a57600080fd5b8063c37c656d14610a21578063c4a7a35f14610ad4578063caa3455314610af957600080fd5b8063a2b096e41161017a578063b3a07b9811610149578063b3a07b98146109a4578063bc327e40146109c4578063be71f8a4146109e0578063c0fd22b714610a0c57600080fd5b8063a2b096e41461090e578063a33dc5e71461092e578063a8d1eae71461095b578063b045009c1461097057600080fd5b806391dfe78f116101b657806391dfe78f14610899578063999e3614146108b95780639b60ae2b146108da578063a217fddf146108f957600080fd5b80638666c0a9146107ea5780638afceb391461080a57806391d148541461085357600080fd5b806336ce0a92116102c1578063781e04321161025f5780637ff48afb1161022e5780637ff48afb1461078d5780638129fc1c146107a05780638188f468146107b55780638456cb59146107d557600080fd5b8063781e0432146106fa5780637ba3e7ae146107355780637baf71181461074b5780637d036b271461076b57600080fd5b80635ad1def31161029b5780635ad1def31461066b5780635c975abb1461069b57806360a8b18a146106ba5780636a0214a9146106da57600080fd5b806336ce0a92146105fe5780633f4ba83a146106365780635437988d1461064b57600080fd5b806320825443116103395780632b7ac3f3116103085780632b7ac3f31461056c5780632de03aa11461058a5780632f2ff15d146105be57806336568abe146105de57600080fd5b806320825443146104b557806320a23dd3146104d557806320df435914610507578063248a9ca31461053b57600080fd5b80630ceee68c116103755780630ceee68c146104215780630d698f6f1461045957806312a536231461047b5780631ab9c6031461049f57600080fd5b806301ffc9a71461039c57806302f6ccd4146103d157806303561119146103f4575b600080fd5b3480156103a857600080fd5b506103bc6103b736600461575f565b610d13565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610dac565b6040519081526020016103c8565b34801561040057600080fd5b506103e661040f3660046157a1565b600e6020526000908152604090205481565b34801561042d57600080fd5b50600a54610441906001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b34801561046557600080fd5b506104796104743660046157c8565b610df0565b005b6104796104893660046157a1565b6000908152600d60205260409020805434019055565b3480156104ab57600080fd5b506103e660095481565b3480156104c157600080fd5b506104796104d036600461582e565b610f39565b3480156104e157600080fd5b506011546104f29063ffffffff1681565b60405163ffffffff90911681526020016103c8565b34801561051357600080fd5b506103e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681565b34801561054757600080fd5b506103e66105563660046157a1565b6000908152600160208190526040909120015490565b34801561057857600080fd5b506002546001600160a01b0316610441565b34801561059657600080fd5b506103e67f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b3480156105ca57600080fd5b506104796105d93660046158a6565b610fad565b3480156105ea57600080fd5b506104796105f93660046158a6565b610fd8565b34801561060a57600080fd5b506103e66106193660046158a6565b600760209081526000928352604080842090915290825290205481565b34801561064257600080fd5b50610479611069565b34801561065757600080fd5b506104796106663660046158d2565b611186565b34801561067757600080fd5b506103bc6106863660046158d2565b600b6020526000908152604090205460ff1681565b3480156106a757600080fd5b50600254600160e81b900460ff166103bc565b3480156106c657600080fd5b506104416106d53660046157a1565b611297565b3480156106e657600080fd5b506104796106f5366004615901565b611343565b34801561070657600080fd5b506103bc61071536600461591c565b600860209081526000928352604080842090915290825290205460ff1681565b34801561074157600080fd5b506103e660105481565b34801561075757600080fd5b50600254600160c01b900461ffff166103e6565b34801561077757600080fd5b50600254600160a01b900463ffffffff166103e6565b61047961079b366004615946565b61142b565b3480156107ac57600080fd5b50610479611693565b3480156107c157600080fd5b506103bc6107d03660046157a1565b611ae9565b3480156107e157600080fd5b5061047961238f565b3480156107f657600080fd5b5061047961080536600461591c565b61249a565b34801561081657600080fd5b5061083e6108253660046157a1565b600c602052600090815260409020805460019091015482565b604080519283526020830191909152016103c8565b34801561085f57600080fd5b506103bc61086e3660046158a6565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108a557600080fd5b506104796108b4366004615983565b6126c4565b3480156108c557600080fd5b50600a546103bc90600160a01b900460ff1681565b3480156108e657600080fd5b50600254600160f01b900460ff166103bc565b34801561090557600080fd5b506103e6600081565b34801561091a57600080fd5b506104796109293660046157c8565b6127ad565b34801561093a57600080fd5b506103e66109493660046157a1565b60066020526000908152604090205481565b34801561096757600080fd5b506004546103e6565b34801561097c57600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000087081565b3480156109b057600080fd5b506104796109bf3660046159ba565b612891565b3480156109d057600080fd5b50604051600281526020016103c8565b3480156109ec57600080fd5b506109f5612aa4565b6040805192151583526020830191909152016103c8565b348015610a1857600080fd5b506003546103e6565b348015610a2d57600080fd5b50610a93610a3c3660046157a1565b6012602052600090815260409020546001600160801b0381169063ffffffff7001000000000000000000000000000000008204811691600160a01b8104821691600160c01b8204169060ff600160e01b9091041685565b604080516001600160801b03909616865263ffffffff94851660208701529284169285019290925291909116606083015260ff16608082015260a0016103c8565b348015610ae057600080fd5b506011546104f290640100000000900463ffffffff1681565b348015610b0557600080fd5b50610479610b143660046158d2565b612be5565b348015610b2557600080fd5b506103e6610b343660046157a1565b60056020526000908152604090205481565b348015610b5257600080fd5b50610479610b613660046158a6565b612ce3565b348015610b7257600080fd5b506103e67f000000000000000000000000000000000000000000000000000000000000096081565b348015610ba657600080fd5b506002547a010000000000000000000000000000000000000000000000000000900461ffff166103e6565b348015610bdd57600080fd5b506103e6610bec3660046157a1565b600d6020526000908152604090205481565b348015610c0a57600080fd5b506103e67ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c81565b348015610c3e57600080fd5b50610441610c4d3660046157a1565b612d09565b348015610c5e57600080fd5b50610479610c6d3660046157a1565b612d43565b348015610c7e57600080fd5b506103e67fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e81565b348015610cb257600080fd5b506103e6610cc13660046157a1565b600f6020526000908152604090205481565b348015610cdf57600080fd5b50610479610cee366004615a0f565b612d8e565b348015610cff57600080fd5b50610479610d0e36600461591c565b612f23565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610da657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b600254600090610de79061ffff7a0100000000000000000000000000000000000000000000000000008204811691600160c01b900416615a91565b61ffff16905090565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e610e1a8161312e565b600060028054600160e01b900460ff1690811115610e3a57610e3a615ab7565b14610e5857604051631e7b117d60e01b815260040160405180910390fd5b60028054819060ff60e01b1916600160e01b820217905550600254600160f01b900460ff1615158215151415610e8d57610f1a565b8115610ea9576011805463ffffffff19164263ffffffff161790555b60028054831515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517f99895cad53cbbff374fbe3c76182ad42a6cb1c0c7306d3b6651786e7154ccbe690610f1190841515815260200190565b60405180910390a15b600280546000919060ff60e01b1916600160e01b835b02179055505050565b600254600160e81b900460ff1615610f6457604051632a6ab56360e21b815260040160405180910390fd5b60408051858152602081018590523381830152905186917fb92710e3fad9222f817fcd828bd1ce3612ad0cd1c8bd5f3a3f4b8d85c4444621919081900360600190a25050505050565b60008281526001602081905260409091200154610fc98161312e565b610fd3838361313b565b505050565b6001600160a01b038116331461105b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61106582826131c2565b5050565b600254600160e81b900460ff166110ac576040517f395fbd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c76110d68161312e565b600060028054600160e01b900460ff16908111156110f6576110f6615ab7565b1461111457604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e11b1790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1506002805460ff60e01b19169055565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6111b08161312e565b600060028054600160e01b900460ff16908111156111d0576111d0615ab7565b146111ee57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b611229576040516310a0493960e11b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040517fd24015cc99cc1700cafca3042840a1d8ac1e3964fd2e0e37ea29c654056ee32790600090a2600280546000919060ff60e01b1916600160e01b83610f30565b600081631fffffff8111156112bf57604051630104ef3360e21b815260040160405180910390fd5b826112cd576000915061133d565b600060036112dc600186615acd565b815481106112ec576112ec615ae4565b6000918252602090912001546001600160a01b031690508061133a576040517ffc3be2bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91505b50919050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e61136d8161312e565b600060028054600160e01b900460ff169081111561138d5761138d615ab7565b146113ab57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055601180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8516908102919091179091556040519081527f536948e5a71b8ffbb707a6903b99b812c8c291a711ed188e54d36505127d1c3590602001610f11565b600254600160e81b900460ff161561145657604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff169081111561147657611476615ab7565b1461149457604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055831580156114b55750823414155b156114ec576040517ff2be5ced00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83158015906114fa57503415155b15611531576040517fd08ba85b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153c848385613245565b801561154b5761154b81612d43565b816001600160a01b0316847feaa18152488ce5959073c9c79c88ca90b3d96c00de1f118cfaad664c3dab06b98560405161158791815260200190565b60405180910390a383156116725760006115a085611297565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290915084906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c9190615afa565b1015611664576040517f7bf8af0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611670813330876135f6565b505b600280546000919060ff60e01b1916600160e01b835b021790555050505050565b6002600054610100900460ff161580156116b4575060005460ff8083169116105b6117265760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611052565b806000806101000a81548160ff021916908360ff1602179055506001600060016101000a81548160ff02191690831515021790555060016002600001601e6101000a81548160ff02191690831515021790555042601160006101000a81548163ffffffff021916908363ffffffff1602179055506040518060a00160405280683635c9adc5dea000006001600160801b031681526020014263ffffffff168152602001600663ffffffff1681526020016103e863ffffffff168152602001601260ff168152506012600080815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050506040518060a0016040528069d3c21bcecceda10000006001600160801b031681526020014263ffffffff16815260200161277463ffffffff168152602001620f424063ffffffff168152602001601260ff16815250601260006001815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548160ff021916908360ff1602179055509050507f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e600060066103e8604051611a3c939291909283526020830191909152604082015260600190565b60405180910390a160408051600181526127746020820152620f42408183015290517f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e9181900360600190a1600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600254600090600160e81b900460ff1615611b1757604051632a6ab56360e21b815260040160405180910390fd5b600254600160e01b900460ff166001816002811115611b3857611b38615ab7565b1415611f3c576000838152600c60205260409020805460019091015481611b8b576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b9683613675565b9050600080600080611ba8858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b031680611c21576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b8152600401611cad96959493929190615b58565b6060604051808303816000875af1158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615bb2565b92509250925080611d26575050506020908101516000908152600c90915260408120989098555095975061133d95505050505050565b600082118015611d4b5750600086604001516003811115611d4957611d49615ab7565b145b15611d85576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b82158015611d91575081155b15611dc357611daa858a86600001518760200151613bcb565b611dbe858986600001518760200151613bcb565b611de3565b611dd38588858760200151613bcb565b611de38587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff166102008183600101011115611e8357632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e505050505050505050505050505061133d565b6000816002811115611f5057611f50615ab7565b1415612376576002805460ff60e01b1916600160e01b1790556000838152600c6020526040902080546001919091015481611fb7576040517f973e3ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc283613675565b9050600080600080611fd4858b6138e5565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19a63ffffffff8c160154939750919550935091506001600160a01b03168061204d576040517fbb65988600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008d815260200190815260200160002060000181905550600060405180606001604052808981526020018d81526020018860c0015167ffffffffffffffff1681525090506000806000846001600160a01b0316639b07d3428a8a8a8a89602001518a604001516040518763ffffffff1660e01b81526004016120d996959493929190615b58565b6060604051808303816000875af11580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190615bb2565b92509250925080612152575050506020908101516000908152600c90915260408120989098555095975061236495505050505050565b600082118015612177575060008660400151600381111561217557612175615ab7565b145b156121b1576040517f26e939c600000000000000000000000000000000000000000000000000000000815260048101839052602401611052565b821580156121bd575081155b156121ef576121d6858a86600001518760200151613bcb565b6121ea858986600001518760200151613bcb565b61220f565b6121ff8588858760200151613bcb565b61220f8587848760200151613bcb565b6000845160208601516000851460008714161592506040518f81528160208201528260408201528660608201528560808201528360a08201526020600060c08360025afa505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051066002548060c01c6103ff168160d01c6103ff1661020081836001010111156122af57632c52558760e11b60005260046000fd5b50600081815260056020908152604080832095909555600190920160c090811b7ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff909416939093176002558882015189518551908152928301899052938201879052841515606083015260a0608083018190528201528f917f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c910160405180910390a360019e50505050505050505050505050505b6002805460ff60e01b1916905561133d565b604051631e7b117d60e01b815260040160405180910390fd5b600254600160e81b900460ff16156123ba57604051632a6ab56360e21b815260040160405180910390fd5b7fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266123e48161312e565b600060028054600160e01b900460ff169081111561240457612404615ab7565b1461242257604051631e7b117d60e01b815260040160405180910390fd5b600280547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0102000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161116e565b600254600160e81b900460ff16156124c557604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff1615801561250e5750600a54600160a01b900460ff16155b15612545576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff169081111561256557612565615ab7565b1461258357604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b6125be576040516310a0493960e11b815260040160405180910390fd5b6188b88110806125d05750624c4b4081115b15612607576040517f037bbe6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480546001810182557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600f6020908152604091829020859055905184815291929183917f0e62be7fe47a9095143143f8ee61bab3ade27b661223fed33e16122ffe1f284d91015b60405180910390a350600280546000919060ff60e01b1916600160e01b83610f30565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6126ee8161312e565b600060028054600160e01b900460ff169081111561270e5761270e615ab7565b1461272c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0383166000818152600b6020908152604091829020805460ff1916861515908117909155825190815291517f46359ce9dbb6c7f9a375b44072210287916d3de725fc8927a8e762047e4a84249281900390910190a250506002805460ff60e01b1916905550565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e6127d78161312e565b600060028054600160e01b900460ff16908111156127f7576127f7615ab7565b1461281557604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b179055600a8054831515600160a01b81027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179091556040519081527fad6b1fc8881be24fc1ad35119b136f0026a4496e6251980e325ddcf86dab394390602001610f11565b7ff94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c6128bb8161312e565b600060028054600160e01b900460ff16908111156128db576128db615ab7565b146128f957604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556040805160a081019091528061293b61292685600a615ccf565b6129369063ffffffff8816615cde565b613c86565b6001600160801b03908116825263ffffffff4281166020808501919091528882166040808601829052898416606080880182905260ff8b81166080998a015260008f8152601287528490208a5181548c8901518d8801518e8701519e909d0151909416600160e01b0260ff60e01b199d8b16600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9d8c16600160a01b029d909d167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff95909b167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1990921692909b169190911717919091169690961797909717979097169490941790925582518a815290810191909152908101929092527f2c87e4aece114a15933668e808bd3756196c2fb05a4902851081ed8584f8690e910160405180910390a150506002805460ff60e01b19169055505050565b60008043817f0000000000000000000000000000000000000000000000000000000000000870612af47f000000000000000000000000000000000000000000000000000000000000096084615d13565b1015905060008115612b8457601154612b1d9063ffffffff640100000000820481169116615d27565b421015612b2957600091505b612b537f000000000000000000000000000000000000000000000000000000000000096084615d13565b612b7d907f0000000000000000000000000000000000000000000000000000000000000960615acd565b9050612bdb565b612bae7f000000000000000000000000000000000000000000000000000000000000096084615d13565b612bd8907f0000000000000000000000000000000000000000000000000000000000000870615acd565b90505b9094909350915050565b7fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e612c0f8161312e565b600060028054600160e01b900460ff1690811115612c2f57612c2f615ab7565b14612c4d57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b612c88576040516310a0493960e11b815260040160405180910390fd5b600a805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0384169081179091556040519081527fc4fc5cbf094d63a6fb20dc7cb9b0236e7dba8c04667182ec259a00a74f95901890602001610f11565b60008281526001602081905260409091200154612cff8161312e565b610fd383836131c2565b60006004612d18600184615acd565b81548110612d2857612d28615ae4565b6000918252602090912001546001600160a01b031692915050565b600254600160e81b900460ff1615612d6e57604051632a6ab56360e21b815260040160405180910390fd5b336000526008602052604060002060205280600052600160406000205550565b600254600160e81b900460ff1615612db957604051632a6ab56360e21b815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612dd957612dd9615ab7565b14612df757604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e01b179055336000908152600b602052604090205460ff1615612e4f57600254600160f01b900460ff1615612e4a576011805463ffffffff19164263ffffffff161790555b612e95565b6000612e59612aa4565b50905080612e93576040517f83633aab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b6000806000612ea2613ccd565b9250925092506000612eb384614069565b9050612efa8487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250879150869050614088565b612f0484826140f2565b5050600280546000935090915060ff60e01b1916600160e01b83611688565b600254600160e81b900460ff1615612f4e57604051632a6ab56360e21b815260040160405180910390fd5b3360009081527f65ab7acc1bb8390bd4d3ba8eb4987cf212c814cedeacf3ad4b0583b29d65f538602052604090205460ff16158015612f975750600a54600160a01b900460ff16155b15612fce576040517f11d74fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060028054600160e01b900460ff1690811115612fee57612fee615ab7565b1461300c57604051631e7b117d60e01b815260040160405180910390fd5b6002805460ff60e01b1916600160e11b1790556001600160a01b0382163b613047576040516310a0493960e11b815260040160405180910390fd5b61d6d881108061305957506216e36081115b15613090576040517f11e80d6c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380546001810182557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915590546000818152600e6020908152604091829020859055905184815291929183917f85ac039d1da307b778050ca29271ac915424bac011342c9452960f6679b18ff091016126a1565b6131388133614177565b50565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff166110655760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16156110655760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b82631fffffff81111561326b57604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083206001600160a01b0387168452909152902054600254600160f01b900460ff16156135be576000858152601260209081526040808320815160a08101835290546001600160801b038116825263ffffffff7001000000000000000000000000000000008204811694830194909452600160a01b8104841692820192909252600160c01b8204909216606083015260ff600160e01b909104166080820181905290919061332890600a615ccf565b9050816040015163ffffffff1660001480613360575080826040015163ffffffff166133549190615cde565b61335e8685615d27565b115b15613397576040517ffb1837c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015163ffffffff166133d8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081836060015163ffffffff166133f09190615cde565b905060006134016201518083615d3f565b9050613426846020015163ffffffff164261341c9190615acd565b6129369083615cde565b84518590613435908390615d53565b6001600160801b0390811690915285511683101590506134645761345882613c86565b6001600160801b031684525b83516001600160801b03168711156134a8576040517fd014828600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134b187613c86565b845185906134c0908390615d75565b6001600160801b0390811690915263ffffffff428116602080890191825260008e81526012909152604090819020895181549351928b015160608c015160808d015160ff16600160e01b0260ff60e01b19918816600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff938916600160a01b02939093167fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff969098167001000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff199097169390981692909217949094179290921693909317919091171691909117905550505050505b6135c88382615d27565b60009586526007602090815260408088206001600160a01b0390971688529590529390942092909255505050565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152836004820152826024820152816044820152843b613645576310a0493960e11b60005260046000fd5b602060006064836000895af190506001600051163d151780821661366d573d6000803e3d6000fd5b505050505050565b604080516101c081018252600060208083018290526101a083019190915263ffffffff8416808352633fffffff9185901c821693830193909352603e84901c81166060830152605c84901c81166080830152607a84901c1660a082015267ffffffffffffffff60b884901c1660c08201526001603d84901c811660e0830152605b84901c8116610100830152607984901c8116610120830152609784901c8116610140830152609884901c81168114610160830152609984901c81168114610180830152909160049161374791615acd565b8154811061375757613757615ae4565b60009182526020808320909101546001600160a01b03168382015282518252600f905260409020546101a082015261016081015115801561379c575060008160600151115b156137d3576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061018001511580156137ea575060008160a00151115b15613821576040517f3448066300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101600151801561383a575080606001518160400151145b156138795780604001516040517f760558e800000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b600081610180015180156138905750816101400151155b90508080156138a657508160a001518260800151145b1561133d5781608001516040517ff23e3f9500000000000000000000000000000000000000000000000000000000815260040161105291815260200190565b61390660408051606081018252600080825260208201819052909182015290565b61392760408051606081018252600080825260208201819052909182015290565b61394860408051606081018252600080825260208201819052909182015290565b61396960408051606081018252600080825260208201819052909182015290565b8560e001511561399c57632000000086604001516139879190615acd565b845260006020850152600360408501526139fa565b6040860180518552516139ae90611297565b6001600160a01b031660208501819052156139ca5760026139cd565b60015b846040019060038111156139e3576139e3615ab7565b908160038111156139f6576139f6615ab7565b9052505b85610120015115613a1b578482526000602083015260036040830152613a79565b608086018051835251613a2d90611297565b6001600160a01b03166020830181905215613a49576002613a4c565b60015b82604001906003811115613a6257613a62615ab7565b90816003811115613a7557613a75615ab7565b9052505b85610100015115613ac35763200000008660600151613a989190615acd565b8352600060208401526040830160035b90816003811115613abb57613abb615ab7565b905250613b27565b85610160015115613b1557606086018051845251613ae090611297565b6001600160a01b03166020840181905215613afc576002613aff565b60015b83604001906003811115613aa857613aa8615ab7565b60008084526020840181905260408401525b85610140015115613b5e57848152600060208201526040810160035b90816003811115613b5657613b56615ab7565b905250613bc2565b85610180015115613bb05760a086018051825251613b7b90611297565b6001600160a01b03166020820181905215613b97576002613b9a565b60015b81604001906003811115613b4357613b43615ab7565b60008082526020820181905260408201525b92959194509250565b81613bd557613c80565b600183604001516003811115613bed57613bed615ab7565b1415613c4f576000818152600d6020526040902054821115613c3b576040517fcbbf6eca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600d6020526040812055613c80565b600283604001516003811115613c6757613c67615ab7565b1415613c80576020830151613c7e818630866135f6565b505b50505050565b60006001600160801b03821115613cc9576040517f7a781de100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b6040805161010080820183526141ec82526141f360208084018290528385019190915261421e606084018190526080840181905260a0840181905260c084015261423360e084015283516111c46004359081013560448201359081046111c883013563ffffffff908116828104808402821415019092029096028481016111e0019098526111c08881018086529498919760009795968a0195602486019589948594615755949391926111cc013590911690888a376111c098909801976111a9888101988a97509091010193505b86841115613dd15760078735168089528060051b830151935050613dc387898563ffffffff16565b965061010088019750613d9b565b505050506111c088810151604051600092828604808c048082028d1415019384900393909261010084029260043560240182376111c08101905060208202810191505b81811015613e635760206000848960025afa613e2f57600080fd5b6000517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006815295820195602001613e14565b8415613fe057600092508360208114613eaf5760108114613ed75760408114613eff5760018114613f275760028114613f4f5760048114613f775760088114613f9f5760019650613fc3565b7f0df0e06ab8a02ce2ff08babd7144ab23ca2e99ddf318080cf88602eeb8913d449350613fc3565b7f1c52c159b4dae66c3dcf33b44d4d61ead6bc4d260f882ac6ba34dccf78892ca49350613fc3565b7f1f83672815ac9b3ca31732d641784035834e96b269eaf6a2e759bf4fcc8e5bfd9350613fc3565b7f22dd983f8337d97d56071f7986209ab2ee6039a422242e89126701c6ee005af09350613fc3565b7f076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f365609350613fc3565b7f2f0c70a5bf5460465e9902f9c96be324e8064e762a5de52589fdb97cbce3c6ee9350613fc3565b7f240ed0de145447ff0ceff2aa477f43e0e2ed7f3543ee3d8832f158ec76b183a993505b5060208502820191505b81811015613fe057828152602001613fcd565b6040519450602060008683038760025afa613ffa57600080fd5b50505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051069650801561405e576040517f3259ec1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050909192565b6111a08101516001600160a01b0381111561408357600080fd5b919050565b60006140948684614267565b90506140a1868587614338565b60006140ad8784614400565b9050817f14054a15b39bfd65ec00fc6d15c7e5f9cbc1dc6f452cbefa359b4da61ad89fb682336040516140e1929190615d9d565b60405180910390a250505050505050565b60005b6010811015610fd3576000614111848360200201610b80015190565b9050801561416e576000614125858461493e565b90508061413e57600080600080858861c350f15061416c565b600061414982611297565b905061416a818685600e60008781526020019081526020016000205461495a565b505b505b506001016140f5565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16611065576141aa816149aa565b6141b58360206149bc565b6040516020016141c6929190615e1d565b60408051601f198184030181529082905262461bcd60e51b825261105291600401615e9e565b5060010190565b600060a0602084016020840137601460c0840160cc840137600460d4840160fc840137505060b90190565b60006080602084016020840137505060810190565b60006040517fd0426f7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405160009063ffffffff600480356111cc810135929092168083016111ec01939290910135037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee38019060ac815360316001820153608c6002820153605d600382015360406004820152846024820152816044820152818360648301376001600160a01b03600254169250823b614309576310a0493960e11b60005260046000fd5b6000806064840183865afa9250505080614327573d6000803e3d6000fd5b5061433183614be5565b9392505050565b60006111e08085019061010085028601015b8082101561366d5760a082015180156143f357825160e084015160c085015160018314156143db5761010086206001600160a01b038216600090815260086020908152604080832084845290915290205460ff166143ce5788880180516060825260006143b684614d98565b90506143c3818487614eb1565b509052606097909701965b6143d9838387614ffd565b505b82600214156143ef576143ef84828461507e565b5050505b610100830192505061434a565b606060008061441185611180015190565b9050601054811461445c576010546040517f88011dd6000000000000000000000000000000000000000000000000000000008152611052918391600401918252602082015260400190565b6000614466615101565b90935090506144758184615acd565b600280547ffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffffffff1660d083901b1790556020878101519194506000935091506144bc9190615cde565b6040805160808082018352600080835260208301819052828401819052606090920182905282519081019092529192506101808701915b6020811015614870578251806145095750614870565b61040084015180614546576040517fb246041300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061455183613675565b9050600080600080614563858c6138e5565b93509350935093506040517f4bd947a800000000000000000000000000000000000000000000000000000000815260048101905060208601518082525084516020820152602085015160408201526040850151606082015283516080820152602084015160a0820152604084015160c0820152825160e082015260208301516101008201526040830151610120820152815161014082015260208201516101608201526040820151610180820152866101a08201528b6101c082015260c0860151806101e083015250600d6102008201528e610220820152600a54803b614655576310a0493960e11b60005260046000fd5b60008061024460048503846101a08c0151f490503d6000833e80600181146146955760008c52600060208d0152600060408d0152600060608d01526146b5565b82518c52602083015160208d0152604083015160408d0152600160608d01525b5050508461018001516146ca57600060208a01525b60408901516001811461480a576040518781528a51602082015260208b0151604082015260608b0151606082015260a0608082015260608b01511561473857600060a08201528c897f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c60c084a35b60608b0151614792573d60a08201523d602081066020038115150281600060c085013e60008260c0018401528e8b7f692cf5822a02f5edf084dc7249b3a06293621e069f11975ed70908ed10ed2e2c83850160c00186a350505b8881528c60208201528760408201528a51606082015260208b0151608082015260608b015160a08201526020600060c08360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600051068d6000526006602052806040600020555060018d019c50614851565b6040518781528c897f38ce48f4c2f3454bcf130721f25a4262b2ff2c8e36af937b30edf01ba481eb1d602084a3508b600052600c6020526040600020888155876001820155505b5060018b019a5060208a019950876001019750505050505050506144f3565b506002548060c01c6103ff166103ff86820111801561489a57632c52558760e11b60005260046000fd5b506040516006602052600560605260005b828110156148cf5787810160009081526040828152808020549120556001016148ab565b506040527ffffffffffffffc00ffffffffffffffffffffffffffffffffffffffffffffffff90860160d01b167ffffffffffc00fc00ffffffffffffffffffffffffffffffffffffffffffffffff9091161760025560008061492e615123565b6010559998505050505050505050565b602081028201610980015163ffffffff811115610da657600080fd5b5a81156149645750805b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815284600482015283602482015260008060448360008a87f150505050505050565b6060610da66001600160a01b03831660145b606060006149cb836002615cde565b6149d6906002615d27565b67ffffffffffffffff8111156149ee576149ee615ed1565b6040519080825280601f01601f191660200182016040528015614a18576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110614a4f57614a4f615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110614ab257614ab2615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000614aee846002615cde565b614af9906001615d27565b90505b6001811115614b96577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614b3a57614b3a615ae4565b1a60f81b828281518110614b5057614b50615ae4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93614b8f81615ee7565b9050614afc565b5083156143315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611052565b600080600080600080614bf7876151ff565b945094509450945094506009548414614c46576040517f34fddf400000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401611052565b60025463ffffffff600160a01b90910481169083168181614c6957614c69615cfd565b0663ffffffff1660001415614cd2578063ffffffff168263ffffffff1614614ccd576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff808416600483015282166024820152604401611052565b614d4c565b60008363ffffffff168263ffffffff1681614cef57614cef615cfd565b068483010363ffffffff169050808363ffffffff1614614d4a576040517f7861e6c600000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260248101829052604401611052565b505b506009929092556002805463ffffffff9390920192909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161790555092915050565b600080614da4836152a8565b90506040517f19457468657265756d205369676e6564204d6573736167653a0a32313000000060208201527f5369676e696e672074686973206d6573736167652077696c6c20616c6c6f7720603d8201527f796f75722070656e64696e672066756e647320746f206265207370656e742069605d8201527f6e20417a746563207472616e73616374696f6e3a0a0a30780000000000000000607d82015260208201516095820152604082015160b58201527f0a0a494d504f5254414e543a204f6e6c79207369676e20746865206d6573736160d58201527f676520696620796f752074727573742074686520636c69656e7400000000000060f582015260ef602082012092505050919050565b6000806001600160a01b038316614ef4576040517fd57e351000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351858552606085015160408601518060608801526020870151604088015281602088015260208760808960015afa601c8314601b84141760608514167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a183101616945050508451861460008114614f6b57614f70565b855192505b508452801519919091169081614fb2576040517f8a3e28aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b0316816001600160a01b031614613c7e576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82631fffffff81111561502357604051630104ef3360e21b815260040160405180910390fd5b60008481526007602090815260408083209091528482529020805483810390915582118015613c7e576040517f8e8af4f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166150be576040517f6df19fea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806150d5576000806000808686617530f150505050565b60006150e082611297565b9050613c80818486600e60008781526020019081526020016000205461495a565b6002546103ff60d082901c16908190602082111561511e57602091505b509091565b60606000806000615132615101565b909250905060006151438284615acd565b90506040519450602085016020610400018601604052828652600660205260005b83811015615188578281016000908152604090205460208202830152600101615164565b5b60208110156151c2577f2d25a1e3a51eb293004c4b56abe12ed0da6bca2b4a21936752a85d102593c1b460208202830152600101615189565b50602060006104008360025afa50507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016000510693505050509091565b604081015160608201516000918291829160011b906020860163ffffffff808411908311171561522e57600080fd5b805195506040518681526060820151602082015260a0820151604082015260e08201516060820152610120820151608082015260a0812095506001870181526080820151602082015260c082015160408201526101008201516060820152610140820151608082015260a081209450505091939590929450565b606081615310576040519050604081527f303030303030303030303030303030303030303030303030303030303030303060208201527f3030303030303030303030303030303030303030303030303030303030303030604082015260608101604052919050565b506040517f3030303130323033303430353036303730383039306130623063306430653066607e8201527f3130313131323133313431353136313731383139316131623163316431653166609e8201527f323032313232323332343235323632373238323932613262326332643265326660be8201527f333033313332333333343335333633373338333933613362336333643365336660de8201527f343034313432343334343435343634373438343934613462346334643465346660fe8201527f353035313532353335343535353635373538353935613562356335643565356661011e8201527f363036313632363336343635363636373638363936613662366336643665366661013e8201527f373037313732373337343735373637373738373937613762376337643765376661015e8201527f383038313832383338343835383638373838383938613862386338643865386661017e8201527f393039313932393339343935393639373938393939613962396339643965396661019e8201527f61306131613261336134613561366137613861396161616261636164616561666101be8201527f62306231623262336234623562366237623862396261626262636264626562666101de8201527f63306331633263336334633563366337633863396361636263636364636563666101fe8201527f643064316432643364346435643664376438643964616462646364646465646661021e8201527f653065316532653365346535653665376538653965616562656365646565656661023e8201527f663066316632663366346635663666376638663966616662666366646665666661025e820152606081018260408352600181901b6101fe908116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c8116830151600252607782901c16820151600052601e51604084015260801c61573f82826101fe600182901b8116830151601e52600782901c8116830151601c52600f82901c8116830151601a52601782901c8116830151601852601f82901c8116830151601652602782901c8116830151601452602f82901c8116830151601252603782901c8116830151601052603f82901c8116830151600e52604782901c8116830151600c52604f82901c8116830151600a52605782901c8116830151600852605f82901c8116830151600652606782901c8116830151600452606f82901c811683015160025260779190911c160151600052565b5050601e51602082015260608101604052919050565b61575d615efe565b565b60006020828403121561577157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461433157600080fd5b6000602082840312156157b357600080fd5b5035919050565b801515811461313857600080fd5b6000602082840312156157da57600080fd5b8135614331816157ba565b60008083601f8401126157f757600080fd5b50813567ffffffffffffffff81111561580f57600080fd5b60208301915083602082850101111561582757600080fd5b9250929050565b60008060008060006080868803121561584657600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561587257600080fd5b61587e888289016157e5565b969995985093965092949392505050565b80356001600160a01b038116811461408357600080fd5b600080604083850312156158b957600080fd5b823591506158c96020840161588f565b90509250929050565b6000602082840312156158e457600080fd5b6143318261588f565b803563ffffffff8116811461408357600080fd5b60006020828403121561591357600080fd5b614331826158ed565b6000806040838503121561592f57600080fd5b6159388361588f565b946020939093013593505050565b6000806000806080858703121561595c57600080fd5b84359350602085013592506159736040860161588f565b9396929550929360600135925050565b6000806040838503121561599657600080fd5b61599f8361588f565b915060208301356159af816157ba565b809150509250929050565b600080600080608085870312156159d057600080fd5b843593506159e0602086016158ed565b92506159ee604086016158ed565b9150606085013560ff81168114615a0457600080fd5b939692955090935050565b60008060008060408587031215615a2557600080fd5b843567ffffffffffffffff80821115615a3d57600080fd5b615a49888389016157e5565b90965094506020870135915080821115615a6257600080fd5b50615a6f878288016157e5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600061ffff808316818516808303821115615aae57615aae615a7b565b01949350505050565b634e487b7160e01b600052602160045260246000fd5b600082821015615adf57615adf615a7b565b500390565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615b0c57600080fd5b5051919050565b805182526001600160a01b036020820151166020830152604081015160048110615b4d57634e487b7160e01b600052602160045260246000fd5b806040840152505050565b6101c08101615b678289615b13565b615b746060830188615b13565b615b8160c0830187615b13565b615b8f610120830186615b13565b8361018083015267ffffffffffffffff83166101a0830152979650505050505050565b600080600060608486031215615bc757600080fd5b83519250602084015191506040840151615be0816157ba565b809150509250925092565b600181815b80851115615c26578160001904821115615c0c57615c0c615a7b565b80851615615c1957918102915b93841c9390800290615bf0565b509250929050565b600082615c3d57506001610da6565b81615c4a57506000610da6565b8160018114615c605760028114615c6a57615c86565b6001915050610da6565b60ff841115615c7b57615c7b615a7b565b50506001821b610da6565b5060208310610133831016604e8410600b8410161715615ca9575081810a610da6565b615cb38383615beb565b8060001904821115615cc757615cc7615a7b565b029392505050565b600061433160ff841683615c2e565b6000816000190483118215151615615cf857615cf8615a7b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615d2257615d22615cfd565b500690565b60008219821115615d3a57615d3a615a7b565b500190565b600082615d4e57615d4e615cfd565b500490565b60006001600160801b03808316818516808303821115615aae57615aae615a7b565b60006001600160801b0383811690831681811015615d9557615d95615a7b565b039392505050565b604080825283519082018190526000906020906060840190828701845b82811015615dd657815184529284019290840190600101615dba565b5050506001600160a01b039490941692019190915250919050565b60005b83811015615e0c578181015183820152602001615df4565b83811115613c805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615e55816017850160208801615df1565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615e92816028840160208801615df1565b01602801949350505050565b6020815260008251806020840152615ebd816040850160208701615df1565b601f01601f19169190910160400192915050565b634e487b7160e01b600052604160045260246000fd5b600081615ef657615ef6615a7b565b506000190190565b634e487b7160e01b600052605160045260246000fdfea26469706673582212204986047a3c1dc740c0f7b2da538464da5d8465856c4b6d0dec03c81aa8d6df1564736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000008700000000000000000000000000000000000000000000000000000000000000960
-----Decoded View---------------
Arg [0] : _escapeBlockLowerBound (uint256): 2160
Arg [1] : _escapeBlockUpperBound (uint256): 2400
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000870
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000960
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.