false
true
0

Contract Address Details

0xCf59B47B780A73ee10AeEa21A81dFc3Cb70b9c88

Contract Name
ZKVerifier
Creator
0x5a5db3–1f0f74 at 0x2ad123–aae4d5
Balance
0 tPLS
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
25394756
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ZKVerifier




Optimization enabled
false
Compiler version
v0.8.24+commit.e11b9ed9




EVM Version




Verified at
2026-09-04T12:42:35.142042Z

Constructor Arguments

000000000000000000000000f119beb1b343e46c4ed0e78362cd3f87e87ef4cc

Arg [0] (address) : 0xf119beb1b343e46c4ed0e78362cd3f87e87ef4cc

              

contracts/ZKVerifier.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./AdminZamik.sol";

interface IRWAToken {
    function mintWithProof(address to, uint256 amount, bytes32 proofHash) external;
    function mintFee(address to, uint256 amount) external;
    function assetValueUSD() external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function feeRecipient() external view returns (address);
}

/**
 * @title ZKVerifier
 * @notice Verifies Groth16 ZK proofs for RWA ownership claims
 *
 * Security fixes (v2):
 *  - recipient mora biti msg.sender → prepreči frontrunning
 *  - amount je omejen na maxMintable (izračunan iz assetValueUSD) → prepreči neomejeni mint
 *  - amount > 0 check
 *  - proofHash vključuje recipient in amount
 *  - registeredCommitments počiščen po mintu
 *  - setRwaToken odstranjen (mrtva koda — konstruktor že nastavi token)
 */
contract ZKVerifier is Ownable, AdminZamik {

    // === snarkjs-generated VK constants (from rwa_proof_verifier.sol) ===
    // Scalar field size
        uint256 constant r    = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
        // Base field size
        uint256 constant q   = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
    
        // Verification Key data
        uint256 constant alphax  = 20491192805390485299153009773594534940189261866228447918068658471970481763042;
        uint256 constant alphay  = 9383485363053290200918347156157836566562967994039712273449902621266178545958;
        uint256 constant betax1  = 4252822878758300859123897981450591353533073413197771768651442665752259397132;
        uint256 constant betax2  = 6375614351688725206403948262868962793625744043794305715222011528459656738731;
        uint256 constant betay1  = 21847035105528745403288232691147584728191162732299865338377159692350059136679;
        uint256 constant betay2  = 10505242626370262277552901082094356697409835680220590971873171140371331206856;
        uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
        uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
        uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
        uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
        uint256 constant deltax1 = 7634694382555350249182314939945794752801670761871442236918755611747247981945;
        uint256 constant deltax2 = 7785580959050401778007424472707980943542624615417776150098749352587788464225;
        uint256 constant deltay1 = 19797755760015837479531733607381070868376789853134730363187779619202029563244;
        uint256 constant deltay2 = 19885317433472164527823093690594480541727870532036884219862146880419864556528;
    
        
        uint256 constant IC0x = 5313285605904455468883044812252347068829101215429313644709835484872601966339;
        uint256 constant IC0y = 2611852344649716617799171908939889777235094010478351269767823832353876722738;
        
        uint256 constant IC1x = 3721507159761245641438686913490987492444926420712387384343195655500770466953;
        uint256 constant IC1y = 10884128966892936170203469452538504289719178213118369098919656563615016733370;
        
        uint256 constant IC2x = 11919587884350751358344086380913156139705038053372491645096979466761922566199;
        uint256 constant IC2y = 11737085826314024049430266969005569805271747491015946543900350977318458074708;
        
     
        // Memory data
        uint16 constant pVk = 0;
        uint16 constant pPairing = 128;
    
        uint16 constant pLastMem = 896;
    // === end generated constants ===

    address public entropyOracle;

    /**
     * VEC SREDSTEV, VSAKO SVOJ ZETON  (odlocitev 30. 8. 2026)
     *
     * Prej je bil tu `address public rwaToken` — EN zeton na verifier. Ker so vsa
     * sredstva nastajala v isti ERC-20 pogodbi, so bili zetoni med seboj ZAMENLJIVI:
     * 1 RWA od apartmaja je bil nerazlocljiv od 1 RWA od zlatih kovancev. Kupec
     * "deleza apartmaja" je torej dobil zahtevek do nerazlocene mase. To ni bila
     * napaka prikaza in je z metapodatki ni bilo mogoce popraviti.
     *
     * Zdaj: en ZKVerifier strezhe vsem zetonom, vsak zeton je svoje sredstvo.
     * Commitment se registrira ZA DOLOCEN ZETON, zato dokaz za sredstvo A ne more
     * kovati na sredstvu B — tudi ce bi bil dokaz sam po sebi veljaven.
     *
     * ZK vezja NI bilo treba spreminjati: vez med commitmentom in zetonom je
     * on-chain stanje, ne javni signal dokaza.
     */
    mapping(address => bool) public pooblasceniZetoni;   // kateri zetoni smejo kovati prek tega verifierja
    address public tovarna;                              // RWATokenFactory — sme registrirati svoje zetone

    // Asset registry: samo vnaprej registrirani assetCommitment-i lahko mintajo.
    // assetCommitment = Poseidon(privateKey, entropyNonce) = javni signal _pubSignals[0]
    mapping(uint256 => address) public commitmentZeton;   // commitment → za KATERI zeton je registriran
    mapping(uint256 => bool) public commitmentUsed;       // porabljeno (vsak asset minta enkrat)

    /// @notice Zdruzljivost s frontendom: prej je bil to mapping(uint256=>bool).
    function registeredCommitments(uint256 commitment) external view returns (bool) {
        return commitmentZeton[commitment] != address(0);
    }

    // Pooblaščeni UORS operaterji — smejo registrirati commitmente
    mapping(address => bool) public authorizedUORS;

    // Tokenizacijska provizija: 0,5% ob mintu
    uint256 public constant MINT_FEE_BPS = 50; // 50 = 0,5%

    event ProofVerified(address indexed claimant, bytes32 proofHash);
    event TovarnaNastavljena(address indexed tovarna);
    event ZetonPooblascen(address indexed zeton);
    event ZetonOdvzet(address indexed zeton);
    event MintFeeCollected(address indexed feeRecipient, uint256 fee);
    event AssetRegistered(uint256 indexed commitment, address indexed zeton);
    event AssetUnregistered(uint256 indexed commitment);
    event AssetMinted(uint256 indexed commitment, address indexed recipient, uint256 amount, address indexed zeton);
    event UORSAuthorized(address indexed uors);
    event UORSRevoked(address indexed uors);
    event Zaustavljeno(address indexed kdo);
    event Sproscen(address indexed kdo);

    // ─────────────────────────────────────────────────────────────────────────
    //  SISTEMSKA ZAUSTAVITEV — to je adminova pot, ne presoja posameznega sredstva
    //
    //  Delitev iz 3. 9. 2026: UORS odgovarja za SREDSTVA (in edini sme zamrzniti
    //  posamezen zeton), admin odgovarja za SISTEM. Zato admin tu ustavi VSE
    //  kovanje naenkrat — grobo orodje, ki nikogar ne obtozi in nicesar ne presodi.
    //
    //  `pause` sme vec naslovov (owner + zaustavljalci, npr. watchdog), `unpause`
    //  samo owner: ustaviti mora biti mogoce hitro, znova zagnati pa premisljeno.
    // ─────────────────────────────────────────────────────────────────────────
    bool public paused;
    mapping(address => bool) public jeZaustavljalec;
    event ZaustavljalecSpremenjen(address indexed kdo, bool lahko);

    /// @dev Takojsno v obe smeri: ob razkritem kljucu odvzema ne smes cakati.
    function nastaviZaustavljalca(address kdo, bool lahko) external onlyOwner {
        require(kdo != address(0), "Zero address");
        jeZaustavljalec[kdo] = lahko;
        emit ZaustavljalecSpremenjen(kdo, lahko);
    }

    function pause() external {
        require(msg.sender == owner() || jeZaustavljalec[msg.sender], "Ni pooblascen za zaustavitev");
        paused = true;
        emit Zaustavljeno(msg.sender);
    }

    function unpause() external onlyOwner {
        paused = false;
        emit Sproscen(msg.sender);
    }

    modifier onlyOwnerOrUORS() {
        require(msg.sender == owner() || authorizedUORS[msg.sender], "Not authorized");
        _;
    }

    /// @dev Krozne odvisnosti ni vec: verifier se postavi PRVI, zetoni pridejo za njim.
    constructor(address _entropyOracle) Ownable(msg.sender) {
        entropyOracle = _entropyOracle;
    }

    // ─────────────────────────────────────────────────────────────────────────
    //  Pooblascanje zetonov
    //
    //  Kdor sme dodati zeton, sme kovati nova sredstva — to je enako mocno kot
    //  pooblastitev UORS operaterja. Zato gre owner-jeva pot SKOZI ZAMIK.
    //
    //  Tovarna je izjema in mora biti: ce bi vsako novo sredstvo cakalo 48 ur,
    //  bi bilo ustvarjanje sredstev neuporabno. Namesto tega gre skozi zamik
    //  NASTAVITEV TOVARNE — enkrat, vidno, vnaprej — potem pa tovarna registrira
    //  samo zetone, ki jih je sama postavila.
    // ─────────────────────────────────────────────────────────────────────────

    function napoviNastaviTovarno(address _tovarna) external onlyOwner {
        require(_tovarna != address(0), "Zero address");
        _napovej(keccak256(abi.encode("nastaviTovarno", _tovarna)), "ZKVerifier.nastaviTovarno");
    }

    function nastaviTovarno(address _tovarna) external onlyOwner {
        require(_tovarna != address(0), "Zero address");
        _porabi(keccak256(abi.encode("nastaviTovarno", _tovarna)), "ZKVerifier.nastaviTovarno");
        tovarna = _tovarna;
        emit TovarnaNastavljena(_tovarna);
    }

    /// @notice Tovarna registrira zeton, ki ga je pravkar postavila.
    function registrirajZeton(address zeton) external {
        require(msg.sender == tovarna, "Samo tovarna");
        require(zeton != address(0), "Zero address");
        pooblasceniZetoni[zeton] = true;
        emit ZetonPooblascen(zeton);
    }

    function napoviDodajZeton(address zeton) external onlyOwner {
        require(zeton != address(0), "Zero address");
        _napovej(keccak256(abi.encode("dodajZeton", zeton)), "ZKVerifier.dodajZeton");
    }

    /// @notice Rocno pooblastilo zetona (mimo tovarne) — pod zamikom.
    function dodajZeton(address zeton) external onlyOwner {
        require(zeton != address(0), "Zero address");
        _porabi(keccak256(abi.encode("dodajZeton", zeton)), "ZKVerifier.dodajZeton");
        pooblasceniZetoni[zeton] = true;
        emit ZetonPooblascen(zeton);
    }

    /// @notice Odvzem je TAKOJSEN — isto merilo kot revokeUORS: nevarnost ne caka.
    function odvzemiZeton(address zeton) external onlyOwner {
        pooblasceniZetoni[zeton] = false;
        emit ZetonOdvzet(zeton);
    }

    /**
     * @notice Registrira legitimen assetCommitment — samo lastnik (izdajatelj sredstva).
     * @dev Lastnik sredstva izračuna commitment = Poseidon(privateKey, entropyNonce)
     *      in deli SAMO commitment (ne ključa). Izdajatelj ga tu registrira.
     */
    /**
     * PODELITEV MOCI GRE SKOZI ZAMIK, ODVZEM NE.
     *
     * Nov UORS lahko registrira commitmente, ti pa so pot do kovanja zetonov.
     * Podtaknjen operater je zato med najmocnejsimi napadi, ki jih owner kljuc
     * sploh omogoca — in je hkrati napad, ki ga je mogoce VIDETI VNAPREJ.
     * Zato javna napoved + zamik.
     *
     * revokeUORS ostaja takojsen: ob razkritem kljucu operaterja ga moras vreci
     * ven zdaj, ne cez 48 ur. Nevarnost caka, zasilna zavora ne.
     */
    function napoviAuthorizeUORS(address uors) external onlyOwner {
        require(uors != address(0), "Zero address");
        _napovej(keccak256(abi.encode("authorizeUORS", uors)), "ZKVerifier.authorizeUORS");
    }

    /// @notice Pooblasti UORS operaterja za registracijo commitmentov.
    function authorizeUORS(address uors) external onlyOwner {
        require(uors != address(0), "Zero address");
        _porabi(keccak256(abi.encode("authorizeUORS", uors)), "ZKVerifier.authorizeUORS");
        authorizedUORS[uors] = true;
        emit UORSAuthorized(uors);
    }

    /// @notice Prekliče pooblastilo UORS operaterja.
    function revokeUORS(address uors) external onlyOwner {
        authorizedUORS[uors] = false;
        emit UORSRevoked(uors);
    }

    /**
     * @notice Registrira commitment ZA DOLOCEN zeton (sredstvo).
     * @dev Prav ta vez preprecuje, da bi dokaz za sredstvo A kovav na sredstvu B.
     *      Brez nje bi vsak veljaven dokaz odprl vsak zeton.
     */
    function registerCommitment(uint256 commitment, address zeton) external onlyOwnerOrUORS {
        require(commitment != 0, "Zero commitment");
        require(pooblasceniZetoni[zeton], "Zeton ni pooblascen");
        require(commitmentZeton[commitment] == address(0), "Already registered");
        commitmentZeton[commitment] = zeton;
        emit AssetRegistered(commitment, zeton);
    }

    /// @notice Paketna registracija — vsi commitmenti za ISTO sredstvo.
    function registerCommitments(uint256[] calldata commitments, address zeton) external onlyOwnerOrUORS {
        require(pooblasceniZetoni[zeton], "Zeton ni pooblascen");
        for (uint256 i = 0; i < commitments.length; i++) {
            uint256 c = commitments[i];
            if (c != 0 && commitmentZeton[c] == address(0)) {
                commitmentZeton[c] = zeton;
                emit AssetRegistered(c, zeton);
            }
        }
    }

    /// @notice Prekliče registracijo (le če še ni bil porabljen).
    function unregisterCommitment(uint256 commitment) external onlyOwner {
        require(commitmentZeton[commitment] != address(0), "Not registered");
        require(!commitmentUsed[commitment], "Already used");
        commitmentZeton[commitment] = address(0);
        emit AssetUnregistered(commitment);
    }

    /// @notice Onemogoceno: renounceOwnership() bi trajno onemogocil
    ///         (de)avtorizacijo UORS operatorjev in registracijo commitmentov.
    function renounceOwnership() public pure override {
        revert("Renounce onemogocen");
    }

    /**
     * @notice Verify ZK proof and mint RWA tokens to caller.
     * @dev recipient je vedno msg.sender — prepreči frontrunning.
     *      amount je omejen na maxMintable = assetValueUSD / 1e16
     *      (1 RWA token = $0.01 USD pri 18 decimalkah).
     *      Prilagodi delilnik glede na tvojo tokenomiko.
     */
    function verifyAndMint(
        uint[2] calldata _pA,
        uint[2][2] calldata _pB,
        uint[2] calldata _pC,
        uint[2] calldata _pubSignals,
        address zeton,
        uint256 amount
    ) external {
        // FIX #2: recipient je vedno msg.sender — prepreči frontrunning iz mempoola
        address recipient = msg.sender;

        // FIX #1a: amount > 0
        require(amount > 0, "Zero amount");
        require(!paused, "Kovanje je zaustavljeno");
        require(pooblasceniZetoni[zeton], "Zeton ni pooblascen");

        // Asset registry: dokaz mora pripadati registriranemu, še neporabljenemu sredstvu
        uint256 commitment = _pubSignals[0];
        // ⚠️ Jedro locitve sredstev: commitment mora biti registriran ZA TA zeton.
        //    Brez te vrstice bi veljaven dokaz za sredstvo A koval na sredstvu B.
        require(commitmentZeton[commitment] == zeton, "Commitment ni za ta zeton");
        require(!commitmentUsed[commitment], "Asset already minted");

        // ─────────────────────────────────────────────────────────────────────
        //  F1 — kolicina mora biti vezana na to, kar dokaz RES dokaze
        //
        //  Prej je bila edina meja `assetValueUSD * 100`, torej vrednost, ki jo je
        //  prijavil UORS. Dokaz pa poleg lastnistva dokazuje se `assetValue >=
        //  minValue`, in `minValue` je JAVEN signal — bil je izracunan, preverjen
        //  in nato zavrzen. Imetnik veljavne kode za sredstvo, vredno 10.000, je
        //  tako lahko koval do meje 180.000, ce je zeton pripadal drazjemu sredstvu.
        //
        //  Odslej velja OBOJE:
        //    1. dokazana vrednost ne sme presegati prijavljene (UORS je zgornja meja),
        //    2. kolicina ne sme presegati dokazane vrednosti.
        //
        //  minValue je v celih enotah valute (npr. 180000), assetValueUSD pa ima
        //  18 decimalk — zato mnozenje z 1e18. Faktor 100 ostaja: 1 zeton = $0,01.
        // ─────────────────────────────────────────────────────────────────────
        uint256 dokazanaVrednost = _pubSignals[1];
        require(dokazanaVrednost > 0, "Dokazana vrednost je 0");
        require(dokazanaVrednost * 1e18 <= IRWAToken(zeton).assetValueUSD(),
                "Dokazana vrednost presega prijavljeno");
        require(amount <= dokazanaVrednost * 1e18 * 100,
                "Kolicina presega dokazano vrednost");

        require(verifyProof(_pA, _pB, _pC, _pubSignals), "Invalid ZK proof");

        commitmentUsed[commitment] = true;
        // FIX #3: počisti registracijo po mintu (clean state)
        commitmentZeton[commitment] = address(0);

        bytes32 proofHash = _odtisDokaza(_pA, _pB, _pC, _pubSignals, recipient, amount, zeton);
        uint256 mintFee   = amount * MINT_FEE_BPS / 10_000;

        IRWAToken(zeton).mintWithProof(recipient, amount - mintFee, proofHash);

        if (mintFee > 0) {
            address prejemnikProvizije = IRWAToken(zeton).feeRecipient();
            IRWAToken(zeton).mintFee(prejemnikProvizije, mintFee);
            emit MintFeeCollected(prejemnikProvizije, mintFee);
        }

        emit AssetMinted(commitment, recipient, amount - mintFee, zeton);
        emit ProofVerified(recipient, proofHash);
    }

    /**
     * @dev Locena funkcija zato, da `verifyAndMint` ne pride v "stack too deep" ob
     *      Groth16 assembly. Vsebinsko je pomembno TO, kaj je v odtisu:
     *
     *      · recipient in amount  — auditability (FIX #4)
     *      · zeton                — sicer bi bil isti odtis veljaven na VEC sredstvih;
     *                               to je razsiritev ugotovitve F8 (ponovitev ne le
     *                               med verigami, ampak med sredstvi)
     *      · block.chainid        — F8 sama: prepreci ponovitev na drugi verigi
     */
    function _odtisDokaza(
        uint[2] calldata _pA,
        uint[2][2] calldata _pB,
        uint[2] calldata _pC,
        uint[2] calldata _pubSignals,
        address recipient,
        uint256 amount,
        address zeton
    ) private view returns (bytes32) {
        return keccak256(abi.encode(_pA, _pB, _pC, _pubSignals, recipient, amount, zeton, block.chainid));
    }

    function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[2] calldata _pubSignals) internal view returns (bool result) {
        assembly {
            function checkField(v) {
                if iszero(lt(v, r)) {
                    mstore(0, 0)
                    revert(0, 0)
                }
            }
            
            // G1 function to multiply a G1 value(x,y) to value in an address
            function g1_mulAccC(pR, x, y, s) {
                let success
                let mIn := mload(0x40)
                mstore(mIn, x)
                mstore(add(mIn, 32), y)
                mstore(add(mIn, 64), s)

                success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)

                if iszero(success) {
                    mstore(0, 0)
                    revert(0, 0)
                }

                mstore(add(mIn, 64), mload(pR))
                mstore(add(mIn, 96), mload(add(pR, 32)))

                success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)

                if iszero(success) {
                    mstore(0, 0)
                    revert(0, 0)
                }
            }

            function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
                let _pPairing := add(pMem, pPairing)
                let _pVk := add(pMem, pVk)

                mstore(_pVk, IC0x)
                mstore(add(_pVk, 32), IC0y)

                // Compute the linear combination vk_x
                
                g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
                
                g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
                

                // -A
                mstore(_pPairing, calldataload(pA))
                mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))

                // B
                mstore(add(_pPairing, 64), calldataload(pB))
                mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
                mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
                mstore(add(_pPairing, 160), calldataload(add(pB, 96)))

                // alpha1
                mstore(add(_pPairing, 192), alphax)
                mstore(add(_pPairing, 224), alphay)

                // beta2
                mstore(add(_pPairing, 256), betax1)
                mstore(add(_pPairing, 288), betax2)
                mstore(add(_pPairing, 320), betay1)
                mstore(add(_pPairing, 352), betay2)

                // vk_x
                mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
                mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))


                // gamma2
                mstore(add(_pPairing, 448), gammax1)
                mstore(add(_pPairing, 480), gammax2)
                mstore(add(_pPairing, 512), gammay1)
                mstore(add(_pPairing, 544), gammay2)

                // C
                mstore(add(_pPairing, 576), calldataload(pC))
                mstore(add(_pPairing, 608), calldataload(add(pC, 32)))

                // delta2
                mstore(add(_pPairing, 640), deltax1)
                mstore(add(_pPairing, 672), deltax2)
                mstore(add(_pPairing, 704), deltay1)
                mstore(add(_pPairing, 736), deltay2)


                let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)

                isOk := and(success, mload(_pPairing))
            }

            let pMem := mload(0x40)
            mstore(0x40, add(pMem, pLastMem))

            // Validate that all evaluations ∈ F
            
            checkField(calldataload(add(_pubSignals, 0)))
            
            checkField(calldataload(add(_pubSignals, 32)))
            

            // Validate all evaluations
            let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)

            result := isValid
         }
     }
}
        

@openzeppelin/contracts/access/Ownable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
          

@openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

contracts/AdminZamik.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title AdminZamik
 * @notice Casovni zamik na nevarne admin spremembe.
 *
 * ZAKAJ TO OBSTAJA
 * ----------------
 * Owner kljuc na tej platformi NE more krasti: ne more kovati zetonov, ne more
 * premikati tujih zetonov in ne more v escrow. Kar PA lahko, je tiho zamenjati
 * nastavitve pod nogami uporabnikov — KYC listo, placilni token, prijavljeno
 * vrednost sredstva.
 *
 * Vsi trije so napadi, ki jih je mogoce VIDETI VNAPREJ. Zato jih ne branimo z
 * multisigom (ki varuje lastnika kljuca), ampak s casovnim zamikom (ki varuje
 * UPORABNIKA): sprememba se mora najprej javno napovedati, sele po zamiku jo je
 * mogoce izvesti. Uporabnik ima ves ta cas, da spremembo vidi in izstopi.
 *
 * Namenoma NI zunanje timelock pogodbe kot lastnika. Tak vzorec doda tveganje
 * nedosegljivosti: ce lastniku kdaj ne uspe sestaviti transakcije skozi tujo
 * pogodbo, so kontrakti zamrznjeni za vedno. Tu je zamik vgrajen, lastnik pa
 * ostane navadna denarnica.
 *
 * KAJ ZAMIK NE POKRIVA (namerno)
 * ------------------------------
 *   - pause()   — zasilna zavora mora biti takojsnja, sicer ni zavora
 *   - unpause() — vrnitev v obratovanje naj bo hitra
 *   - odvzem pravice zaustavljalca — ob razkritem kljucu ga moras vreci TAKOJ
 * Nevarnost caka, zasilna zavora ne.
 */
abstract contract AdminZamik is Ownable {
    /// @notice Rok, v katerem je napoved uporabna. Po njem potece.
    /// @dev Brez tega bi stara napoved lezala na verigi kot nabita puska:
    ///      napoves nekaj neopaznega danes, izvedes cez pol leta, ko nihce vec
    ///      ne gleda. Napoved, ki ni bila izvedena v roku, je treba ponoviti.
    uint256 public constant ROK = 7 days;

    /// @notice id napovedi → cas, od katerega je izvedljiva (0 = ni napovedi)
    mapping(bytes32 => uint256) public izvedljivoOd;

    event SpremembaNapovedana(bytes32 indexed id, string kaj, uint256 izvedljivoOd, uint256 potece);
    event SpremembaIzvedena(bytes32 indexed id, string kaj);
    event SpremembaPreklicana(bytes32 indexed id, string kaj);

    /// @notice PulseChain mainnet. Edina veriga, kjer zamik varuje pravo vrednost.
    uint256 internal constant MAINNET = 369;

    /// @notice Koliko casa mora sprememba cakati.
    ///
    /// VREDNOST DOLOCA VERIGA, NE CLOVEK  (spremenjeno 30. 8. 2026)
    ///
    ///   mainnet (369)   48 ur      imetnik ima cas videti in izstopiti
    ///   drugod          10 minut   razvoj; dva dni cakanja na testnetu bi
    ///                              pomenila, da se nihce ne bi testiral
    ///
    /// ZAKAJ TAKO IN NE Z ROCNO VREDNOSTJO
    ///   Prej je bilo tu fiksnih `10 minutes` z opozorilom "PRED DEPLOYEM NA
    ///   MAINNET VRNI NA 48 ur". To je zanasanje na cloveski spomin — ista
    ///   tocka odpovedi, ki smo jo ze odpravili pri `mockApproveMe` (locena
    ///   pogodba, ki na mainnet ne more).
    ///
    ///   Nevarnost ni bila teoreticna: deset minut zamika na mainnetu pomeni,
    ///   da napadalec z admin kljucem izvede spremembo, preden jo utegnes
    ///   opaziti. Zamik je takrat videti prisoten, a je brez ucinka — najslabsa
    ///   vrsta obrambe, ker nanjo racunas.
    ///
    ///   Zdaj razvojne vrednosti NI mogoce po pomoti odnesti na mainnet: ista
    ///   koda tam vrne 48 ur sama od sebe.
    ///
    /// @dev virtual ostaja, da lahko posamezna pogodba vrednost se povozi
    ///      (MarketplaceTestnet to pocne).
    function zamik() public view virtual returns (uint256) {
        return block.chainid == MAINNET ? 48 hours : 10 minutes;
    }

    // ── Notranje ────────────────────────────────────────────────────────────

    /// @dev id MORA vsebovati tocne parametre spremembe, sicer bi lahko
    ///      napovedal nedolzno vrednost in izvedel skodljivo.
    function _napovej(bytes32 id, string memory kaj) internal {
        require(izvedljivoOd[id] == 0, "Ze napovedano");
        uint256 od = block.timestamp + zamik();
        izvedljivoOd[id] = od;
        emit SpremembaNapovedana(id, kaj, od, od + ROK);
    }

    function _porabi(bytes32 id, string memory kaj) internal {
        uint256 od = izvedljivoOd[id];
        require(od != 0, "Ni napovedano");
        require(block.timestamp >= od, "Zamik se ni potekel");
        require(block.timestamp <= od + ROK, "Napoved je potekla");
        delete izvedljivoOd[id];
        emit SpremembaIzvedena(id, kaj);
    }

    // ── Javno ───────────────────────────────────────────────────────────────

    /// @notice Preklic napovedane spremembe. Takojsen — premisliti se mora biti
    ///         mogoce hitreje, kot se izvede.
    function prekliciSpremembo(bytes32 id, string calldata kaj) external onlyOwner {
        require(izvedljivoOd[id] != 0, "Ni napovedano");
        delete izvedljivoOd[id];
        emit SpremembaPreklicana(id, kaj);
    }

    /// @notice Stanje napovedi — da ga stran in nadzorni sistem lahko prikazeta.
    function stanjeNapovedi(bytes32 id)
        external
        view
        returns (bool napovedana, uint256 od, uint256 potece, bool izvedljivaZdaj)
    {
        uint256 t = izvedljivoOd[id];
        if (t == 0) return (false, 0, 0, false);
        return (true, t, t + ROK, block.timestamp >= t && block.timestamp <= t + ROK);
    }
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_entropyOracle","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"AssetMinted","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256","indexed":true},{"type":"address","name":"recipient","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"zeton","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"AssetRegistered","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256","indexed":true},{"type":"address","name":"zeton","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"AssetUnregistered","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"MintFeeCollected","inputs":[{"type":"address","name":"feeRecipient","internalType":"address","indexed":true},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ProofVerified","inputs":[{"type":"address","name":"claimant","internalType":"address","indexed":true},{"type":"bytes32","name":"proofHash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaIzvedena","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaNapovedana","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false},{"type":"uint256","name":"izvedljivoOd","internalType":"uint256","indexed":false},{"type":"uint256","name":"potece","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SpremembaPreklicana","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"string","name":"kaj","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"Sproscen","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TovarnaNastavljena","inputs":[{"type":"address","name":"tovarna","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UORSAuthorized","inputs":[{"type":"address","name":"uors","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UORSRevoked","inputs":[{"type":"address","name":"uors","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ZaustavljalecSpremenjen","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true},{"type":"bool","name":"lahko","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Zaustavljeno","inputs":[{"type":"address","name":"kdo","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ZetonOdvzet","inputs":[{"type":"address","name":"zeton","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ZetonPooblascen","inputs":[{"type":"address","name":"zeton","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MINT_FEE_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ROK","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"authorizeUORS","inputs":[{"type":"address","name":"uors","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"authorizedUORS","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"commitmentUsed","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"commitmentZeton","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"dodajZeton","inputs":[{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"entropyOracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"izvedljivoOd","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"jeZaustavljalec","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviAuthorizeUORS","inputs":[{"type":"address","name":"uors","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviDodajZeton","inputs":[{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"napoviNastaviTovarno","inputs":[{"type":"address","name":"_tovarna","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nastaviTovarno","inputs":[{"type":"address","name":"_tovarna","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nastaviZaustavljalca","inputs":[{"type":"address","name":"kdo","internalType":"address"},{"type":"bool","name":"lahko","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"odvzemiZeton","inputs":[{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"pooblasceniZetoni","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"prekliciSpremembo","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"string","name":"kaj","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registerCommitment","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256"},{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registerCommitments","inputs":[{"type":"uint256[]","name":"commitments","internalType":"uint256[]"},{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"registeredCommitments","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"registrirajZeton","inputs":[{"type":"address","name":"zeton","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeUORS","inputs":[{"type":"address","name":"uors","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"napovedana","internalType":"bool"},{"type":"uint256","name":"od","internalType":"uint256"},{"type":"uint256","name":"potece","internalType":"uint256"},{"type":"bool","name":"izvedljivaZdaj","internalType":"bool"}],"name":"stanjeNapovedi","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tovarna","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unregisterCommitment","inputs":[{"type":"uint256","name":"commitment","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"verifyAndMint","inputs":[{"type":"uint256[2]","name":"_pA","internalType":"uint256[2]"},{"type":"uint256[2][2]","name":"_pB","internalType":"uint256[2][2]"},{"type":"uint256[2]","name":"_pC","internalType":"uint256[2]"},{"type":"uint256[2]","name":"_pubSignals","internalType":"uint256[2]"},{"type":"address","name":"zeton","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"zamik","inputs":[]}]
              

Contract Creation Code

0x60806040523480156200001157600080fd5b5060405162002531380380620025318339810160408190526200003491620000dd565b33806200005b57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b62000066816200008d565b50600280546001600160a01b0319166001600160a01b03929092169190911790556200010f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620000f057600080fd5b81516001600160a01b03811681146200010857600080fd5b9392505050565b612412806200011f6000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c8063715018a61161011a5780639db2f571116100ad578063cd2b1a5f1161007c578063cd2b1a5f146104da578063d48693d1146104ed578063e5236f86146104f5578063e826f69a14610508578063f2fde38b1461051257600080fd5b80639db2f57114610489578063a2a230131461049c578063a9a9855d146104af578063c714d0f7146104d257600080fd5b80638456cb59116100e95780638456cb591461044a578063847561f8146104525780638da5cb5b146104655780639bcc6e7e1461047657600080fd5b8063715018a6146103e557806376e382c8146103ed578063776528cd146104005780637af89ef51461043757600080fd5b806328ce0d861161019d5780634a2ddbd11161016c5780634a2ddbd11461036c5780634d63ce361461037f5780635c975abb14610392578063666ddb231461039f578063704c1796146103c257600080fd5b806328ce0d8614610315578063365a0ca5146103285780633f4ba83a1461035157806344b0eb021461035957600080fd5b80630e78931d116101d95780630e78931d146102995780631446b861146102c457806319ee63c1146102d7578063235a0b9b146102ea57600080fd5b806305e105b91461020b5780630854eef5146102435780630a5b2df1146102715780630d8227da14610286575b600080fd5b61022e610219366004611eb2565b60066020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b610263610251366004611eb2565b60016020526000908152604090205481565b60405190815260200161023a565b61028461027f366004611ee0565b610525565b005b610284610294366004611ee0565b610576565b6002546102ac906001600160a01b031681565b6040516001600160a01b03909116815260200161023a565b6102846102d2366004611ee0565b610658565b6102846102e5366004611ee0565b61072f565b61022e6102f8366004611eb2565b6000908152600560205260409020546001600160a01b0316151590565b610284610323366004611eb2565b61079e565b6102ac610336366004611eb2565b6005602052600090815260409020546001600160a01b031681565b61028461088f565b610284610367366004611ee0565b6108ce565b61028461037a366004611f04565b61095c565b61028461038d366004611f42565b6109e9565b60085461022e9060ff1681565b61022e6103ad366004611ee0565b60036020526000908152604090205460ff1681565b61022e6103d0366004611ee0565b60076020526000908152604090205460ff1681565b610284610b3e565b6102846103fb366004611fc8565b610b7c565b61041361040e366004611eb2565b610c23565b6040805194151585526020850193909352918301521515606082015260800161023a565b610284610445366004611ee0565b610c90565b610284610ce1565b610284610460366004611ee0565b610d8f565b6000546001600160a01b03166102ac565b6004546102ac906001600160a01b031681565b610284610497366004612044565b610e69565b6102846104aa366004611ee0565b610ffb565b61022e6104bd366004611ee0565b60096020526000908152604090205460ff1681565b610263603281565b6102846104e8366004612080565b61108a565b61026361167f565b610284610503366004611ee0565b6116a1565b61026362093a8081565b610284610520366004611ee0565b61172f565b61052d61176a565b6001600160a01b038116600081815260036020526040808220805460ff19169055517f513cdc19277bafa59b350daee3326371868289df4611fab72ab9749643ad7fef9190a250565b61057e61176a565b6001600160a01b0381166105ad5760405162461bcd60e51b81526004016105a4906120ff565b60405180910390fd5b61060e816040516020016105c19190612125565b60405160208183030381529060405280519060200120604051806040016040528060198152602001785a4b56657269666965722e6e617374617669546f7661726e6f60381b815250611799565b600480546001600160a01b0319166001600160a01b0383169081179091556040517fe364cf452581b78d64b23d0370f72ba8380777f0a90e52e223986e17f014382790600090a250565b61066061176a565b6001600160a01b0381166106865760405162461bcd60e51b81526004016105a4906120ff565b6106e38160405160200161069a919061215e565b60405160208183030381529060405280519060200120604051806040016040528060158152602001742d25ab32b934b334b2b9173237b230b52d32ba37b760591b815250611799565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517f2e55dec88f978eb8229e3f08822286f2c8befca5884b9de310678253f6d171469190a250565b6004546001600160a01b031633146107785760405162461bcd60e51b815260206004820152600c60248201526b53616d6f20746f7661726e6160a01b60448201526064016105a4565b6001600160a01b0381166106e35760405162461bcd60e51b81526004016105a4906120ff565b6107a661176a565b6000818152600560205260409020546001600160a01b03166107fb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd081c9959da5cdd195c995960921b60448201526064016105a4565b60008181526006602052604090205460ff16156108495760405162461bcd60e51b815260206004820152600c60248201526b105b1c9958591e481d5cd95960a21b60448201526064016105a4565b60008181526005602052604080822080546001600160a01b03191690555182917f99088e6d10d683bcaedea1a362ff6ebb8ab7d7c38f4e8c852e68161ae4cde7d391a250565b61089761176a565b6008805460ff1916905560405133907f3a4aad69711d2e0c9ee20d814b95ca020a6a23491162ca2396215a432bbe773990600090a2565b6108d661176a565b6001600160a01b0381166108fc5760405162461bcd60e51b81526004016105a4906120ff565b61095981604051602001610910919061215e565b60405160208183030381529060405280519060200120604051806040016040528060158152602001742d25ab32b934b334b2b9173237b230b52d32ba37b760591b8152506118c2565b50565b61096461176a565b6001600160a01b03821661098a5760405162461bcd60e51b81526004016105a4906120ff565b6001600160a01b038216600081815260096020908152604091829020805460ff191685151590811790915591519182527f9562c728fd52688e7dc1a376e3ee2035e842ac8dff05803952c69492f957d88a910160405180910390a25050565b6000546001600160a01b0316331480610a1157503360009081526007602052604090205460ff165b610a4e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016105a4565b6001600160a01b03811660009081526003602052604090205460ff16610a865760405162461bcd60e51b81526004016105a490612193565b60005b82811015610b38576000848483818110610aa557610aa56121c0565b90506020020135905080600014158015610ad457506000818152600560205260409020546001600160a01b0316155b15610b2f5760008181526005602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051909183917f85819f62de3f36778ef25274607ec7071cf41151e6e04a29971d86f30e8bbf919190a35b50600101610a89565b50505050565b60405162461bcd60e51b81526020600482015260136024820152722932b737bab731b29037b732b6b7b3b7b1b2b760691b60448201526064016105a4565b610b8461176a565b6000838152600160205260408120549003610bd15760405162461bcd60e51b815260206004820152600d60248201526c4e69206e61706f766564616e6f60981b60448201526064016105a4565b600083815260016020526040808220919091555183907f72003eda7c2c39777210bccbf69141a92bbe56d746914a16f5ee3aaf5e6f7a8390610c1690859085906121d6565b60405180910390a2505050565b600081815260016020526040812054819081908190808203610c5357600080600080945094509450945050610c89565b600181610c6362093a808261221b565b834210158015610c7f5750610c7b62093a808561221b565b4211155b9450945094509450505b9193509193565b610c9861176a565b6001600160a01b038116600081815260076020526040808220805460ff19169055517fd84b626bc6cd1f6d62d5e197f48869d2a5ef1a750b360ad929c3de63c88bdfe49190a250565b6000546001600160a01b0316331480610d0957503360009081526009602052604090205460ff165b610d555760405162461bcd60e51b815260206004820152601c60248201527f4e6920706f6f626c617363656e207a61207a617573746176697465760000000060448201526064016105a4565b6008805460ff1916600117905560405133907f65b3009f81d789a2064493bfd78059e5eaacca20215307e85f985bf0e513ebd690600090a2565b610d9761176a565b6001600160a01b038116610dbd5760405162461bcd60e51b81526004016105a4906120ff565b610e1d81604051602001610dd1919061222e565b60405160208183030381529060405280519060200120604051806040016040528060188152602001775a4b56657269666965722e617574686f72697a65554f525360401b815250611799565b6001600160a01b038116600081815260076020526040808220805460ff19166001179055517fb334427bfaed9992168ed99fda266e2d7cf5c2ea1a37a1f76e82fd1e307edf7f9190a250565b6000546001600160a01b0316331480610e9157503360009081526007602052604090205460ff165b610ece5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016105a4565b81600003610f105760405162461bcd60e51b815260206004820152600f60248201526e16995c9bc818dbdb5b5a5d1b595b9d608a1b60448201526064016105a4565b6001600160a01b03811660009081526003602052604090205460ff16610f485760405162461bcd60e51b81526004016105a490612193565b6000828152600560205260409020546001600160a01b031615610fa25760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b60448201526064016105a4565b60008281526005602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f85819f62de3f36778ef25274607ec7071cf41151e6e04a29971d86f30e8bbf919190a35050565b61100361176a565b6001600160a01b0381166110295760405162461bcd60e51b81526004016105a4906120ff565b6109598160405160200161103d9190612125565b60405160208183030381529060405280519060200120604051806040016040528060198152602001785a4b56657269666965722e6e617374617669546f7661726e6f60381b8152506118c2565b33816110c65760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b60448201526064016105a4565b60085460ff16156111195760405162461bcd60e51b815260206004820152601760248201527f4b6f76616e6a65206a65207a6175737461766c6a656e6f00000000000000000060448201526064016105a4565b6001600160a01b03831660009081526003602052604090205460ff166111515760405162461bcd60e51b81526004016105a490612193565b83356000818152600560205260409020546001600160a01b038581169116146111bc5760405162461bcd60e51b815260206004820152601960248201527f436f6d6d69746d656e74206e69207a61207461207a65746f6e0000000000000060448201526064016105a4565b60008181526006602052604090205460ff16156112125760405162461bcd60e51b8152602060048201526014602482015273105cdcd95d08185b1c9958591e481b5a5b9d195960621b60448201526064016105a4565b60208501358061125d5760405162461bcd60e51b81526020600482015260166024820152750446f6b617a616e6120767265646e6f7374206a6520360541b60448201526064016105a4565b846001600160a01b031663cde2202a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf9190612266565b6112d182670de0b6b3a764000061227f565b111561132d5760405162461bcd60e51b815260206004820152602560248201527f446f6b617a616e6120767265646e6f73742070726573656761207072696a61766044820152646c6a656e6f60d81b60648201526084016105a4565b61133f81670de0b6b3a764000061227f565b61134a90606461227f565b8411156113a45760405162461bcd60e51b815260206004820152602260248201527f4b6f6c6963696e61207072657365676120646f6b617a616e6f20767265646e6f6044820152611cdd60f21b60648201526084016105a4565b6113b089898989611975565b6113ef5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2102d2590383937b7b360811b60448201526064016105a4565b6000828152600660209081526040808320805460ff191660011790556005909152812080546001600160a01b031916905561142f8a8a8a8a888a8c611e1e565b9050600061271061144160328861227f565b61144b9190612296565b90506001600160a01b038716636a3b5c4d86611467848a6122b8565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260448101859052606401600060405180830381600087803b1580156114b457600080fd5b505af11580156114c8573d6000803e3d6000fd5b5050505060008111156115e4576000876001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611515573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153991906122cb565b604051638cc9d10760e01b81526001600160a01b0380831660048301526024820185905291925090891690638cc9d10790604401600060405180830381600087803b15801561158757600080fd5b505af115801561159b573d6000803e3d6000fd5b50505050806001600160a01b03167fd2b7c9cdd8f0b876462485c766dac30078e9ef6f76ce1e57ca92c7bd553bcf1f836040516115da91815260200190565b60405180910390a2505b6001600160a01b03808816908616857f1365c616f24c2b6838dd9a07b147b6ffd5e232d55f3ffbd59cddbb073def4e9261161e858b6122b8565b60405190815260200160405180910390a4846001600160a01b03167f0565033f3973b38ac07b3b39f05c0bcfa1449a22d6fd347fdc63c7a8370e106a8360405161166a91815260200190565b60405180910390a25050505050505050505050565b6000610171461461169257610258611697565b6202a3005b62ffffff16905090565b6116a961176a565b6001600160a01b0381166116cf5760405162461bcd60e51b81526004016105a4906120ff565b610959816040516020016116e3919061222e565b60405160208183030381529060405280519060200120604051806040016040528060188152602001775a4b56657269666965722e617574686f72697a65554f525360401b8152506118c2565b61173761176a565b6001600160a01b03811661176157604051631e4fbdf760e01b8152600060048201526024016105a4565b61095981611e62565b6000546001600160a01b031633146117975760405163118cdaa760e01b81523360048201526024016105a4565b565b600082815260016020526040812054908190036117e85760405162461bcd60e51b815260206004820152600d60248201526c4e69206e61706f766564616e6f60981b60448201526064016105a4565b8042101561182e5760405162461bcd60e51b815260206004820152601360248201527216985b5a5ac81cd9481b9a481c1bdd195ad95b606a1b60448201526064016105a4565b61183b62093a808261221b565b42111561187f5760405162461bcd60e51b81526020600482015260126024820152714e61706f766564206a6520706f74656b6c6160701b60448201526064016105a4565b600083815260016020526040808220919091555183907ffac4537038ebc9eaa00d86a88a6c2e268012d306f6442966aab36014a195432390610c1690859061232e565b6000828152600160205260409020541561190e5760405162461bcd60e51b815260206004820152600d60248201526c5a65206e61706f766564616e6f60981b60448201526064016105a4565b600061191861167f565b611922904261221b565b60008481526001602052604090208190559050827f63a0d065f46e07e30a4f246d28eb53f839982100439173db92dbd5700ab37c15838361196662093a808261221b565b604051610c1693929190612341565b6000611de2565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181106109595760008052600080fd5b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816119de5760008052600080fd5b825160408201526020830151606082015260408360808360066107d05a03fa91505080611a0e5760008052600080fd5b5050505050565b7f0bbf368c7f6fa7f6559bf65da45c33b505a21ff7fb0874c3bd0e2e7baa1b170385527f05c6418bd08aff1241cc2850606a69d8b73a6d9875e25df448f52ae21907c432602086015260006080860186611ab287357f181032dd16b7eea417d83a9181ab6887bae84d538a8731a6f3003db177c0caba7f083a4c6477d7d1a1feb5f0ba3ddcd764a617b31c182138d6e756100407c25c89846119ac565b611b0260208801357f19f2f485618fdb703d11b2fbc13e61ce7371c4f94e99c148b2d2d8e3f1d9a6547f1a5a3f66f163e8eb3a5351b30773f2cf6126755e91973e02ab7bd68d77525837846119ac565b50823581527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208401357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020820152833560408201526020840135606082015260408401356080820152606084013560a08201527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08201527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08201527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008201527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208201527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408201527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160820152600087015161018082015260206000018701516101a08201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08201527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008201527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220820152843561024082015260208501356102608201527f10e115799fb9e210b69c6459d325cb70991b1a5f7b23166b9cb1079a84ec05796102808201527f11367b8fccc2b903fc7b4fa13cccc3bd581b6ae5bb74403ff1449df18caeb0616102a08201527f2bc521f6593c958f19d068ab6c9d871471993c59807984ff5540d2ae59f7ad6c6102c08201527f2bf6b0d953792ab8a4e7926e629078462da9a25f808b3d5c13c56b035c14b3f06102e08201526020816103008360086107d05a03fa9051169695505050505050565b6040516103808101604052611dfa600084013561197c565b611e07602084013561197c565b611e14818486888a611a15565b9695505050505050565b60008787878787878746604051602001611e3f989796959493929190612366565b604051602081830303815290604052805190602001209050979650505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215611ec457600080fd5b5035919050565b6001600160a01b038116811461095957600080fd5b600060208284031215611ef257600080fd5b8135611efd81611ecb565b9392505050565b60008060408385031215611f1757600080fd5b8235611f2281611ecb565b915060208301358015158114611f3757600080fd5b809150509250929050565b600080600060408486031215611f5757600080fd5b833567ffffffffffffffff80821115611f6f57600080fd5b818601915086601f830112611f8357600080fd5b813581811115611f9257600080fd5b8760208260051b8501011115611fa757600080fd5b60209283019550935050840135611fbd81611ecb565b809150509250925092565b600080600060408486031215611fdd57600080fd5b83359250602084013567ffffffffffffffff80821115611ffc57600080fd5b818601915086601f83011261201057600080fd5b81358181111561201f57600080fd5b87602082850101111561203157600080fd5b6020830194508093505050509250925092565b6000806040838503121561205757600080fd5b823591506020830135611f3781611ecb565b806040810183101561207a57600080fd5b92915050565b600080600080600080610180878903121561209a57600080fd5b6120a48888612069565b955060c08701888111156120b757600080fd5b6040880195506120c78982612069565b9450506120d8886101008901612069565b92506101408701356120e981611ecb565b8092505061016087013590509295509295509295565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b6040808252600e908201526d6e617374617669546f7661726e6f60901b60608201526001600160a01b0391909116602082015260800190565b6040808252600a90820152693237b230b52d32ba37b760b11b60608201526001600160a01b0391909116602082015260800190565b6020808252601390820152722d32ba37b7103734903837b7b13630b9b1b2b760691b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561207a5761207a612205565b6040808252600d908201526c617574686f72697a65554f525360981b60608201526001600160a01b0391909116602082015260800190565b60006020828403121561227857600080fd5b5051919050565b808202811582820484141761207a5761207a612205565b6000826122b357634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561207a5761207a612205565b6000602082840312156122dd57600080fd5b8151611efd81611ecb565b6000815180845260005b8181101561230e576020818501810151868301820152016122f2565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000611efd60208301846122e8565b60608152600061235460608301866122e8565b60208301949094525060400152919050565b6101c081016040808b84378083018a60005b600281101561239557838284379183019190830190600101612378565b505050808960c08501378088610100850137506001600160a01b03958616610140830152610160820194909452919093166101808201526101a0019190915294935050505056fea2646970667358221220d3580d1c57be7145b71e5b08e0276273aecb69c5d02679a72a8d937cec9b7c8e64736f6c63430008180033000000000000000000000000f119beb1b343e46c4ed0e78362cd3f87e87ef4cc

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102065760003560e01c8063715018a61161011a5780639db2f571116100ad578063cd2b1a5f1161007c578063cd2b1a5f146104da578063d48693d1146104ed578063e5236f86146104f5578063e826f69a14610508578063f2fde38b1461051257600080fd5b80639db2f57114610489578063a2a230131461049c578063a9a9855d146104af578063c714d0f7146104d257600080fd5b80638456cb59116100e95780638456cb591461044a578063847561f8146104525780638da5cb5b146104655780639bcc6e7e1461047657600080fd5b8063715018a6146103e557806376e382c8146103ed578063776528cd146104005780637af89ef51461043757600080fd5b806328ce0d861161019d5780634a2ddbd11161016c5780634a2ddbd11461036c5780634d63ce361461037f5780635c975abb14610392578063666ddb231461039f578063704c1796146103c257600080fd5b806328ce0d8614610315578063365a0ca5146103285780633f4ba83a1461035157806344b0eb021461035957600080fd5b80630e78931d116101d95780630e78931d146102995780631446b861146102c457806319ee63c1146102d7578063235a0b9b146102ea57600080fd5b806305e105b91461020b5780630854eef5146102435780630a5b2df1146102715780630d8227da14610286575b600080fd5b61022e610219366004611eb2565b60066020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b610263610251366004611eb2565b60016020526000908152604090205481565b60405190815260200161023a565b61028461027f366004611ee0565b610525565b005b610284610294366004611ee0565b610576565b6002546102ac906001600160a01b031681565b6040516001600160a01b03909116815260200161023a565b6102846102d2366004611ee0565b610658565b6102846102e5366004611ee0565b61072f565b61022e6102f8366004611eb2565b6000908152600560205260409020546001600160a01b0316151590565b610284610323366004611eb2565b61079e565b6102ac610336366004611eb2565b6005602052600090815260409020546001600160a01b031681565b61028461088f565b610284610367366004611ee0565b6108ce565b61028461037a366004611f04565b61095c565b61028461038d366004611f42565b6109e9565b60085461022e9060ff1681565b61022e6103ad366004611ee0565b60036020526000908152604090205460ff1681565b61022e6103d0366004611ee0565b60076020526000908152604090205460ff1681565b610284610b3e565b6102846103fb366004611fc8565b610b7c565b61041361040e366004611eb2565b610c23565b6040805194151585526020850193909352918301521515606082015260800161023a565b610284610445366004611ee0565b610c90565b610284610ce1565b610284610460366004611ee0565b610d8f565b6000546001600160a01b03166102ac565b6004546102ac906001600160a01b031681565b610284610497366004612044565b610e69565b6102846104aa366004611ee0565b610ffb565b61022e6104bd366004611ee0565b60096020526000908152604090205460ff1681565b610263603281565b6102846104e8366004612080565b61108a565b61026361167f565b610284610503366004611ee0565b6116a1565b61026362093a8081565b610284610520366004611ee0565b61172f565b61052d61176a565b6001600160a01b038116600081815260036020526040808220805460ff19169055517f513cdc19277bafa59b350daee3326371868289df4611fab72ab9749643ad7fef9190a250565b61057e61176a565b6001600160a01b0381166105ad5760405162461bcd60e51b81526004016105a4906120ff565b60405180910390fd5b61060e816040516020016105c19190612125565b60405160208183030381529060405280519060200120604051806040016040528060198152602001785a4b56657269666965722e6e617374617669546f7661726e6f60381b815250611799565b600480546001600160a01b0319166001600160a01b0383169081179091556040517fe364cf452581b78d64b23d0370f72ba8380777f0a90e52e223986e17f014382790600090a250565b61066061176a565b6001600160a01b0381166106865760405162461bcd60e51b81526004016105a4906120ff565b6106e38160405160200161069a919061215e565b60405160208183030381529060405280519060200120604051806040016040528060158152602001742d25ab32b934b334b2b9173237b230b52d32ba37b760591b815250611799565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517f2e55dec88f978eb8229e3f08822286f2c8befca5884b9de310678253f6d171469190a250565b6004546001600160a01b031633146107785760405162461bcd60e51b815260206004820152600c60248201526b53616d6f20746f7661726e6160a01b60448201526064016105a4565b6001600160a01b0381166106e35760405162461bcd60e51b81526004016105a4906120ff565b6107a661176a565b6000818152600560205260409020546001600160a01b03166107fb5760405162461bcd60e51b815260206004820152600e60248201526d139bdd081c9959da5cdd195c995960921b60448201526064016105a4565b60008181526006602052604090205460ff16156108495760405162461bcd60e51b815260206004820152600c60248201526b105b1c9958591e481d5cd95960a21b60448201526064016105a4565b60008181526005602052604080822080546001600160a01b03191690555182917f99088e6d10d683bcaedea1a362ff6ebb8ab7d7c38f4e8c852e68161ae4cde7d391a250565b61089761176a565b6008805460ff1916905560405133907f3a4aad69711d2e0c9ee20d814b95ca020a6a23491162ca2396215a432bbe773990600090a2565b6108d661176a565b6001600160a01b0381166108fc5760405162461bcd60e51b81526004016105a4906120ff565b61095981604051602001610910919061215e565b60405160208183030381529060405280519060200120604051806040016040528060158152602001742d25ab32b934b334b2b9173237b230b52d32ba37b760591b8152506118c2565b50565b61096461176a565b6001600160a01b03821661098a5760405162461bcd60e51b81526004016105a4906120ff565b6001600160a01b038216600081815260096020908152604091829020805460ff191685151590811790915591519182527f9562c728fd52688e7dc1a376e3ee2035e842ac8dff05803952c69492f957d88a910160405180910390a25050565b6000546001600160a01b0316331480610a1157503360009081526007602052604090205460ff165b610a4e5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016105a4565b6001600160a01b03811660009081526003602052604090205460ff16610a865760405162461bcd60e51b81526004016105a490612193565b60005b82811015610b38576000848483818110610aa557610aa56121c0565b90506020020135905080600014158015610ad457506000818152600560205260409020546001600160a01b0316155b15610b2f5760008181526005602052604080822080546001600160a01b0319166001600160a01b0387169081179091559051909183917f85819f62de3f36778ef25274607ec7071cf41151e6e04a29971d86f30e8bbf919190a35b50600101610a89565b50505050565b60405162461bcd60e51b81526020600482015260136024820152722932b737bab731b29037b732b6b7b3b7b1b2b760691b60448201526064016105a4565b610b8461176a565b6000838152600160205260408120549003610bd15760405162461bcd60e51b815260206004820152600d60248201526c4e69206e61706f766564616e6f60981b60448201526064016105a4565b600083815260016020526040808220919091555183907f72003eda7c2c39777210bccbf69141a92bbe56d746914a16f5ee3aaf5e6f7a8390610c1690859085906121d6565b60405180910390a2505050565b600081815260016020526040812054819081908190808203610c5357600080600080945094509450945050610c89565b600181610c6362093a808261221b565b834210158015610c7f5750610c7b62093a808561221b565b4211155b9450945094509450505b9193509193565b610c9861176a565b6001600160a01b038116600081815260076020526040808220805460ff19169055517fd84b626bc6cd1f6d62d5e197f48869d2a5ef1a750b360ad929c3de63c88bdfe49190a250565b6000546001600160a01b0316331480610d0957503360009081526009602052604090205460ff165b610d555760405162461bcd60e51b815260206004820152601c60248201527f4e6920706f6f626c617363656e207a61207a617573746176697465760000000060448201526064016105a4565b6008805460ff1916600117905560405133907f65b3009f81d789a2064493bfd78059e5eaacca20215307e85f985bf0e513ebd690600090a2565b610d9761176a565b6001600160a01b038116610dbd5760405162461bcd60e51b81526004016105a4906120ff565b610e1d81604051602001610dd1919061222e565b60405160208183030381529060405280519060200120604051806040016040528060188152602001775a4b56657269666965722e617574686f72697a65554f525360401b815250611799565b6001600160a01b038116600081815260076020526040808220805460ff19166001179055517fb334427bfaed9992168ed99fda266e2d7cf5c2ea1a37a1f76e82fd1e307edf7f9190a250565b6000546001600160a01b0316331480610e9157503360009081526007602052604090205460ff165b610ece5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016105a4565b81600003610f105760405162461bcd60e51b815260206004820152600f60248201526e16995c9bc818dbdb5b5a5d1b595b9d608a1b60448201526064016105a4565b6001600160a01b03811660009081526003602052604090205460ff16610f485760405162461bcd60e51b81526004016105a490612193565b6000828152600560205260409020546001600160a01b031615610fa25760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b60448201526064016105a4565b60008281526005602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f85819f62de3f36778ef25274607ec7071cf41151e6e04a29971d86f30e8bbf919190a35050565b61100361176a565b6001600160a01b0381166110295760405162461bcd60e51b81526004016105a4906120ff565b6109598160405160200161103d9190612125565b60405160208183030381529060405280519060200120604051806040016040528060198152602001785a4b56657269666965722e6e617374617669546f7661726e6f60381b8152506118c2565b33816110c65760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b60448201526064016105a4565b60085460ff16156111195760405162461bcd60e51b815260206004820152601760248201527f4b6f76616e6a65206a65207a6175737461766c6a656e6f00000000000000000060448201526064016105a4565b6001600160a01b03831660009081526003602052604090205460ff166111515760405162461bcd60e51b81526004016105a490612193565b83356000818152600560205260409020546001600160a01b038581169116146111bc5760405162461bcd60e51b815260206004820152601960248201527f436f6d6d69746d656e74206e69207a61207461207a65746f6e0000000000000060448201526064016105a4565b60008181526006602052604090205460ff16156112125760405162461bcd60e51b8152602060048201526014602482015273105cdcd95d08185b1c9958591e481b5a5b9d195960621b60448201526064016105a4565b60208501358061125d5760405162461bcd60e51b81526020600482015260166024820152750446f6b617a616e6120767265646e6f7374206a6520360541b60448201526064016105a4565b846001600160a01b031663cde2202a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf9190612266565b6112d182670de0b6b3a764000061227f565b111561132d5760405162461bcd60e51b815260206004820152602560248201527f446f6b617a616e6120767265646e6f73742070726573656761207072696a61766044820152646c6a656e6f60d81b60648201526084016105a4565b61133f81670de0b6b3a764000061227f565b61134a90606461227f565b8411156113a45760405162461bcd60e51b815260206004820152602260248201527f4b6f6c6963696e61207072657365676120646f6b617a616e6f20767265646e6f6044820152611cdd60f21b60648201526084016105a4565b6113b089898989611975565b6113ef5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2102d2590383937b7b360811b60448201526064016105a4565b6000828152600660209081526040808320805460ff191660011790556005909152812080546001600160a01b031916905561142f8a8a8a8a888a8c611e1e565b9050600061271061144160328861227f565b61144b9190612296565b90506001600160a01b038716636a3b5c4d86611467848a6122b8565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260448101859052606401600060405180830381600087803b1580156114b457600080fd5b505af11580156114c8573d6000803e3d6000fd5b5050505060008111156115e4576000876001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611515573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153991906122cb565b604051638cc9d10760e01b81526001600160a01b0380831660048301526024820185905291925090891690638cc9d10790604401600060405180830381600087803b15801561158757600080fd5b505af115801561159b573d6000803e3d6000fd5b50505050806001600160a01b03167fd2b7c9cdd8f0b876462485c766dac30078e9ef6f76ce1e57ca92c7bd553bcf1f836040516115da91815260200190565b60405180910390a2505b6001600160a01b03808816908616857f1365c616f24c2b6838dd9a07b147b6ffd5e232d55f3ffbd59cddbb073def4e9261161e858b6122b8565b60405190815260200160405180910390a4846001600160a01b03167f0565033f3973b38ac07b3b39f05c0bcfa1449a22d6fd347fdc63c7a8370e106a8360405161166a91815260200190565b60405180910390a25050505050505050505050565b6000610171461461169257610258611697565b6202a3005b62ffffff16905090565b6116a961176a565b6001600160a01b0381166116cf5760405162461bcd60e51b81526004016105a4906120ff565b610959816040516020016116e3919061222e565b60405160208183030381529060405280519060200120604051806040016040528060188152602001775a4b56657269666965722e617574686f72697a65554f525360401b8152506118c2565b61173761176a565b6001600160a01b03811661176157604051631e4fbdf760e01b8152600060048201526024016105a4565b61095981611e62565b6000546001600160a01b031633146117975760405163118cdaa760e01b81523360048201526024016105a4565b565b600082815260016020526040812054908190036117e85760405162461bcd60e51b815260206004820152600d60248201526c4e69206e61706f766564616e6f60981b60448201526064016105a4565b8042101561182e5760405162461bcd60e51b815260206004820152601360248201527216985b5a5ac81cd9481b9a481c1bdd195ad95b606a1b60448201526064016105a4565b61183b62093a808261221b565b42111561187f5760405162461bcd60e51b81526020600482015260126024820152714e61706f766564206a6520706f74656b6c6160701b60448201526064016105a4565b600083815260016020526040808220919091555183907ffac4537038ebc9eaa00d86a88a6c2e268012d306f6442966aab36014a195432390610c1690859061232e565b6000828152600160205260409020541561190e5760405162461bcd60e51b815260206004820152600d60248201526c5a65206e61706f766564616e6f60981b60448201526064016105a4565b600061191861167f565b611922904261221b565b60008481526001602052604090208190559050827f63a0d065f46e07e30a4f246d28eb53f839982100439173db92dbd5700ab37c15838361196662093a808261221b565b604051610c1693929190612341565b6000611de2565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181106109595760008052600080fd5b600060405183815284602082015285604082015260408160608360076107d05a03fa9150816119de5760008052600080fd5b825160408201526020830151606082015260408360808360066107d05a03fa91505080611a0e5760008052600080fd5b5050505050565b7f0bbf368c7f6fa7f6559bf65da45c33b505a21ff7fb0874c3bd0e2e7baa1b170385527f05c6418bd08aff1241cc2850606a69d8b73a6d9875e25df448f52ae21907c432602086015260006080860186611ab287357f181032dd16b7eea417d83a9181ab6887bae84d538a8731a6f3003db177c0caba7f083a4c6477d7d1a1feb5f0ba3ddcd764a617b31c182138d6e756100407c25c89846119ac565b611b0260208801357f19f2f485618fdb703d11b2fbc13e61ce7371c4f94e99c148b2d2d8e3f1d9a6547f1a5a3f66f163e8eb3a5351b30773f2cf6126755e91973e02ab7bd68d77525837846119ac565b50823581527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760208401357f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4703066020820152833560408201526020840135606082015260408401356080820152606084013560a08201527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e260c08201527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d192660e08201527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c6101008201527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab6101208201527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a76101408201527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8610160820152600087015161018082015260206000018701516101a08201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26101c08201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6101e08201527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6102008201527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610220820152843561024082015260208501356102608201527f10e115799fb9e210b69c6459d325cb70991b1a5f7b23166b9cb1079a84ec05796102808201527f11367b8fccc2b903fc7b4fa13cccc3bd581b6ae5bb74403ff1449df18caeb0616102a08201527f2bc521f6593c958f19d068ab6c9d871471993c59807984ff5540d2ae59f7ad6c6102c08201527f2bf6b0d953792ab8a4e7926e629078462da9a25f808b3d5c13c56b035c14b3f06102e08201526020816103008360086107d05a03fa9051169695505050505050565b6040516103808101604052611dfa600084013561197c565b611e07602084013561197c565b611e14818486888a611a15565b9695505050505050565b60008787878787878746604051602001611e3f989796959493929190612366565b604051602081830303815290604052805190602001209050979650505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215611ec457600080fd5b5035919050565b6001600160a01b038116811461095957600080fd5b600060208284031215611ef257600080fd5b8135611efd81611ecb565b9392505050565b60008060408385031215611f1757600080fd5b8235611f2281611ecb565b915060208301358015158114611f3757600080fd5b809150509250929050565b600080600060408486031215611f5757600080fd5b833567ffffffffffffffff80821115611f6f57600080fd5b818601915086601f830112611f8357600080fd5b813581811115611f9257600080fd5b8760208260051b8501011115611fa757600080fd5b60209283019550935050840135611fbd81611ecb565b809150509250925092565b600080600060408486031215611fdd57600080fd5b83359250602084013567ffffffffffffffff80821115611ffc57600080fd5b818601915086601f83011261201057600080fd5b81358181111561201f57600080fd5b87602082850101111561203157600080fd5b6020830194508093505050509250925092565b6000806040838503121561205757600080fd5b823591506020830135611f3781611ecb565b806040810183101561207a57600080fd5b92915050565b600080600080600080610180878903121561209a57600080fd5b6120a48888612069565b955060c08701888111156120b757600080fd5b6040880195506120c78982612069565b9450506120d8886101008901612069565b92506101408701356120e981611ecb565b8092505061016087013590509295509295509295565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b6040808252600e908201526d6e617374617669546f7661726e6f60901b60608201526001600160a01b0391909116602082015260800190565b6040808252600a90820152693237b230b52d32ba37b760b11b60608201526001600160a01b0391909116602082015260800190565b6020808252601390820152722d32ba37b7103734903837b7b13630b9b1b2b760691b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561207a5761207a612205565b6040808252600d908201526c617574686f72697a65554f525360981b60608201526001600160a01b0391909116602082015260800190565b60006020828403121561227857600080fd5b5051919050565b808202811582820484141761207a5761207a612205565b6000826122b357634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561207a5761207a612205565b6000602082840312156122dd57600080fd5b8151611efd81611ecb565b6000815180845260005b8181101561230e576020818501810151868301820152016122f2565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000611efd60208301846122e8565b60608152600061235460608301866122e8565b60208301949094525060400152919050565b6101c081016040808b84378083018a60005b600281101561239557838284379183019190830190600101612378565b505050808960c08501378088610100850137506001600160a01b03958616610140830152610160820194909452919093166101808201526101a0019190915294935050505056fea2646970667358221220d3580d1c57be7145b71e5b08e0276273aecb69c5d02679a72a8d937cec9b7c8e64736f6c63430008180033