ETH Price: $2,670.52 (+1.35%)

Transaction Decoder

Block:
18343543 at Oct-13-2023 07:25:23 PM +UTC
Transaction Fee:
0.015782292122911578 ETH $42.15
Gas Used:
2,177,109 Gas / 7.249197042 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x035aC6Ac...D65242A1D
0.0297697 Eth
Nonce: 0
0.013987407877088422 Eth
Nonce: 1
0.015782292122911578
(beaverbuild)
5.615402590597354083 Eth5.615575059617878257 Eth0.000172469020524174
0xB117Fa20...bDE7388A5
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 11330125951278230415811776408230976839226912754147889170135472293638953231879633789175484993683422501088311825815766112990884783746652918954928800728978833099851367927185420142965460584541601171703315703395715643005085876906150514405300385912726105699881197159707703123971695141308195366558558108390379720756735214111831798939549258795100869254030252062930105626242207317245314389095986735933612612091166925960513858751750076346558221003154122826653460641707485912144597173018849008299288444889906135381123485783188913825959383622146002822485874125260987708902354207847783124099340435312050718122217458648070302964957321936909682492569917405607627096088972694239599305405472209436132522566033140954269351535048325611213324764566016935318852682105625790981158313482105704740164072275010800400187585570344770121092696536858811311607784541468631058964672909202107310179735124803464866627376188918977822142166679154872941308295107918605762727001072343960775684154858430385798309944851134450743287505389919008140163821162716425647390792430009161574076794274613673519721947718432404886918596371615765545252138917803918039198787190614635217021178829176804551043773116315648879852861238331025607149720603711602479655908454998718696168948240303366545857801648519009903497853016054536597292716502894628760344092667955962435402210030817642976297481663130382367909048571053977901242024683385462505556793685496322580142036504021764253119063488382160782710390912243136400273179915385137045030755035928062024830718102589851986035457785301088406750414295554839707702538050854199681750199691147205545868570318867212967587935073886629206464123598204421812739140784435952042800079461281032809278765242186615636074151534753065906720784867174372520170890890443224758784294332065331812865502299323324805026273352795825087976340126363994046791704591487679995413405548296767564146590484403531766834823150150757845917577346049658879927859545582261355118045359293920493087996747289330914132190399035487499046987754843202228777798675799377068752431343553156687651298737347451862124173709479982471398515968563917206398338217106585474056830627548061570076262218391047921541371849444882609628075969752606870030673208099950065202905573708791341433511455035759652145429164640186995662811378994464668352400369373159347774224832029677466576691522944483061532014686594711530075573537838747205968026928331140091463287190158180846174726386886326471250447990341302949301241775105062268703727286578993347632788489228120863781052499129118313320661975454528613509620064816578266759075327221860289705272416055466620627454702511125668966167962424322336184097465266207860669715251857599725981744339113084952075748217291309851650749478173401239972258334494136342201650042048255717359742097156450353430605705826547512860165970960225316284071687498987654092558184681592950775927719324498676397626523415239987502025200865969975965684889470487678140723361227891088027671079987814143538628351015200907305790424088956991430772134041376709067504374879916903318166853226537747003602724945520200426207095327062307702995087807587890617046009047892820181897255453806318899384074983534468025541466236511400313877781182532260560435181196759145921938638034313867961412052475034748855006531262518982172705477578807347982279544084851109983586933162361886745992924978072973100265942353469524334196065233385640696109517328451930892772234980000365085658245985319563071331344890350397078004614353544910319623945689159133508154261717591306550347310778578234946334310859803013049610616326855799548102612589128942171919910365293018627731867391545174912565403531308037020410727542430423340864046288808438090668926884378266150701229452754833113839193570223418152281717238291446473600965160071662147079606851763507309691965964405428401157257388245122223201219120067325912137870598919601889748988956948990802539823888792883378861813646809783371388866555340465277162172781277718212232975252233003384079143313128970450362945515657318881127355093500592510192468780177025050727892360613888240824713631568634525079770696602631734796664117146307311118447841917415368068378692140752557224963884710331195622487323057108379539245375948622622409791737745647319868972664073972144521609770606831080500098180422792774939367336634552125183670466883453051863797925153603908329821495307269213381126935318337773692919743822989120323446781167399775667683027586575398065276833170170534401369220063672658650407543066319212014604867638548346551001492072330282135574803891868812494772261298605791112612778176265038370490361267341502433496317209865732256290026943424177658960390212481429321627284821190367000015884131744129284833150310114967161214691953524623632048349803050621348244214898757387280910877171952353524123205980496542622454717245647170787726953884478666752941683998562457220054887514271762708593335505022862786750024771714927621762563855555283710276473344207507707622656494359151748891553421800227527560790019644685908634017474163795869410830136798621689661259822999128921163379367530748603393845140711104860502301208497495261638549327843871611672415612091168143823002954377906779972099023043096637605413951703658542412931700401946975082063274806288594485739574309973520115194069672609148069682277904627158441636864344657940709430468319872995005441166963687137915697754915517222057207618942230694800248850113227298210080195434073197360707722722708233563634661001324908673883266615181953064076339431668302616484332738822667061559453784712966741377809785027876578435273602823514164332233950497784322604548396715059860419180945932913787982375272225182150484439256914928876051175159448854371860734265278693287912479658070752271063360992922643641170297074597558003217734140469633744657459709312771507593391995564319387315810399356074009541384641387668050320640160617314675941961439834303970580925414633039535637051519025584222489215174202945051068478253557749901243251793150111495712051895532772828637913712182158104130686206599851611276763938165045284418152254773994172938100030014408029219681925891983978223540550166341696932918114412120921940880092926812090862929249022789566758559024488712202246359040653145286225235067403591441641616538158724029235620799494689056875609808318051956366374000718965253724464054970237147449891018160988689344262598263145110770904241246441072452366197849010522425887015185096699038190937843121543739257679414565298029970272392582333656781582855317108633136029908946599394177370298062643934954334768764594444029897178062553158023898977684654614513559809432098018083047051358528357023122209338699306099850040898958204320712701261164465449490078721256227960573104474535571389635910528621837150237940740926485843006947984721409849722698542135833524252862918783211364617095673809874619824940648315553947454005904921896179604219006277149577775395072382741368065869828040899247854156177493707088050165555178277512536245890159425534700447687371761815885021784652712468671816324063896614606285702224999801161471671839653820750237802400379340988246247444127586460279440168831826536153100869112206938181677644798454814763993355040781177823355699525400831954664119707477425303031585440473979923561947730302238357350625655258890119291630305785970170007323752790442217428029377419369523701908086587015815466019110298561517693776230623142250493758580245457136399872196227610122250436926916106662975757722712925509564585715882546453781223610207235996923276374751210121692084999684571841725077921586141330778711898174483856988322423483562968524666919126196383841031202141616713430144642596379132288732597768266687056010469996299853056349939964204713562680855554360142789628555631136150332100010907528805804564539015808815307005952923347849589897402715558933715682692861637878894135147987837517236891237534308831721699153858006657554618361388928390419953225439803721403067765533573580976220065075838576388338076437663525836209470668097222683013825559523392340712241430896567929251220152035389409549226596146756575416785894408282595044557779690528862921126912939325126831096190669303343196790291992009594735103424695457739159110326980066095064208838090188940520586771112670381778691949564896695295876134594327335939503976332533792356031061851834918351571969934014495247254530218488713497496316739753618932110225749513602016025941789003996769956439951316400263612418750004808926570218626472922529075216873782009593741760029129977638762037814387322542679241375324693789764416488205019643441883637869930602335627483167689853262049479397636231789146248242213032630755999693743838167811387746188827658979846672198369479468629257918266418148520176337062064227971096881851479607012733963160125066086051608442454420086858035878485831515190546004720322842179192311316573967222248974052053305368560593966128755641342309630499961732571486735035402175742343691461677609470283467723956202532090254645926922352450794210659718524362258798594381626737884299431838356911744266659948822992473665711028132587371640239707460449972104749564416983644327830697062638953934881790717833447901398261878655936341941863641668198221445473914229149862348261478377826286784107095155578139934893945120000427831776180395969316176205892291198394155059023791792898446597816690790077835772367686508688061664412308358502614338916399149588104895781518585839578758032709938705312689435442868931785206435827747889638724428292132099328006934920064787523345835956423292795290602167385517783568871410141535802397720320022816372516891716300560143532721520351720301055289740217577868718388622596265933421194355140271484576579393932785426814120196935984841642892127398809209552784966498083430379740448791166847932862848130949865830301214575144597637008553647894260179727335200274645362434564475547394736171330579379546897320429920200392309331330131753103716371674308960261630341252729337125172243567997011756567862974887677471917389086526538300990563864990870972826956217485422642513988407931638818957928487171161358502787482562315942174622129760089040200933340176325087102200980525582770548606964837006535422993014531327767327314244213922373848692347706865667171575854053483521368695107748837564168932659356927977007200913985463722036561705314731737786864836991636815306006025928422177413654408818438552742745408776443392623870917316602118336315537895217215490355529995283976754735170681563335845582174148567377308940152598083945851323378902955734581674320270694317072926978759400022706496131443478131853168876047070969536363437671785032162771970742698259005496801056499870729206663237903586440072722796563229078954932197153657099082585717035718987934291696152037258365590135100866452892250641725879923332152480941490520587340996364233013034917292618875204767148141868142543878574395296182596078492736568573902146203492101002956436610613189250249216705973495320067048150229573606540974454513352315107565822973020233583899328899875331881509862958601906319247766152395089561643988356721654545555586666498062875618060557367763503043558897030832646292740021312622710146521709506939140952396214499552254345412201826111310493447303079304648227774930016539331054585895266107627170278159412668767852211900198602668362710056958247296747849379801886952929801084412865648488053667629297550107285195928489455576530757066904087567373164381462851210647146360103237825548441111462536071697174805303298936047144615199305365588409835344031344783998214988457266746531271981117373302286917374115109050866165722838173950885230896238104616440223506685927867039774996730665650760243864613935100889053211798085371364611953657470936963705390947748378912794487043733418199816980227590103175549748434648961715848664725006319088517300329893193591764935312505974921060818409197040532623786221408778077713040296845349383992899795904511165728048372253698612897439353471611177105670488271349641954924789588531100119492866156096979310063126934094808688677072492497065033096239206444568989495380687546857432768760948714226902006929974153595661696744955898520612153779180314908926695087604090961148684849325422061226698472423737007568251924319533108012659464632803326225143491235796153612834018267357302630563467915918257711246832138436116693715488831199777043687392732517696522624903272633104019059183164115558283607725061709056968483405479343969423153506215801102712271209131815233912494800864521415778666641225781251018654327744172052440834238147310294874472917256932477872332839096116701811645351597184332181194041327997129295639808955543338750928754866698739706097526041321892958885847518155025034344324607789217967588030500086132587293937258854001172344766960938774919923197544459939294909457451637319232528328354389221612258200410555919050492443969050352401883801705402749355188974500934078218236944511563727580687371833163055294447167428027787757786479746816102534603235394281934823152411814777396823927928494635511354538179217493262139603722102015496197997405211781889746548169570206652287480726725898888230619114977075901701304634179245343370445734218230859224308179033022021396681729667656615337084174723043794179319347736674055251590543661350728053177728068154193331796613265924744982150188359415892702480263184002331472942295362707640383503208148312146693297819468472327994465985614134502475087688947986962735941077459782019924389654270154124628034201978379173809233598089089900726733826684520086033928736380159803227828957430296861188295217150205971769091096587498060667461524028106234179079368746231481985640113562778200535181369102378784817560517347051666704543077144063119332573762242635793400954831599974445245654548448774388196439631117079236199765781141726813888569966284857367044926990628443013665701666258751747121509529830921525155688383201090452219659815195284995682306523406176194130666462440943871317355224660425931535982885054386347463947665270999435084939899637806458217693911520629234269514393343470968301652270423446308254015665218383231069093827269070780000180211803510112253921204761016486173615913557749239959819005689700106943513027154880903514199626563632534452957554219582794202874162185592640796236148120661000885398617288312770317678334006855004994647121078484656544310935423434504733094835416027638488668287866674721932509663135814596200216366873693764067847040698407810281093480281337698875546209223165564473406505315571215822542061693993022436990924115333770540048320531675490675946462280581670665014242350349440646302331465474792921166545810234581618184459898831189350262907376664120114735049414047792803654364765383258528510721718393723886183389266436740341816625548855945257876908455138009765936330997525546038912874863748253245507823029385069886503072250803454634378202085119106147160984627860894520512706045308857781383603892326644657695528738593320992128752435439850184840361532701083666153993449793023141047450333722987326798372306055142989237685462927852497650561296879488581225575193673462333141082179610935534669101176727268099999117041891559486263365434119211956464855654092329408765530820064362517666409176342697606797720567147301339853766134221261964596139999775437701062301253920465129945580197306588591591277877323711347877901032936121883902535623245671500661346653948473304445322100594105552305580450413586673457231154804935598126742503207535436889680199850080452637651001678555679831938801822058382207243577923099764108359858126519442154118411089220451191006713874809537551928681266050578663438352488450256712870181550550458021755107546580377030025237932975680499598156399727348914680876802991551545179508643376664166939747732688535690556836121179452549313410737900283357691296638044999265482219178444630380150832294586632732052569830729112526924794173087137684570269718760846115835462083282531695665624724159078391511855939000091306935135033737786913009350240222212252339155355325328547601443620874310410284291350796165714759545379173216044020167183364548232241545700544772288483171376133826559552499905662161352493848038439542109898226523826816573230408400316461526229379248611430792984321846031965652589007672990518911636557711209501889091412988439436986875475844220112677882105387057686070167660749326240930334906531019638438408759843118619281013142812920053629948262078202930877491148928566377094892315967424792677615795653941985336387963201524333677393709417971815952357068894778601891397421765180518566020200858188111626811926038769136676166554514940951606678106755228773427398771299120742646681306078181252992703222798316691600744358713568550625482856149585615043105131414055354132250501467677600602026677458298314431587054679004383583908041567518986417687393263647370640347857396531134016364776177628971104053527638044761214553737010539919443713547948284254879988035558053790994363364646309149208516180667442593806583394059050934400969743750776946615705966006357161209593857598309024517475293376865745022787094982341445288106345202439792353806835930578461525502318874185271656698488942669582472199461106300417019093367936356899274952694846748511756741958589376924919881692351375793573176761929516109532757708580842026075541263815199408017609300108526969596121888404946818811058676515740796351384421935144054021836713082494593288061164062900582423205006528167001913869512389086277240588040882457744398734195857093273968474448798885375107172308605375862039992894220273652370548580103512860382117862381494778732130016795721895661049860366406775576420732749074937899024782157925508567105294916535177561781910528565265824398398948370570296925405588526856675413026504590342254281286223343385908062304962232539901537820001451320451000816679641547026972973982224278092190353627129795076916293444996929448656142812064376069669172996765112705335624692139993913960187989218773203552361732543746954821342879947424124837595325469209467885156710755742083006186256400491729144818255305377348424721700417942686466916653435883854855083833944931725417478600115597295441160941313469081386873708479427668837651233751154002049402715375721969096570307046871593169170409402832186002537840884027173664612697039338109772268929520007147647460547871074423173337511359508604036069774125126195529766769392531252272811933669934390449799123077731354748740528494559400923308545505759529620709253727292421056076517149271781896159137633604606245626626530236776518395397570425976358993314133015926286959102455554051952132062319275571213711050691838045333360435349512687227376569420977048369158656992855411251293762938892650470225592872095653471318976692307127119636319903490123878254599314587057128142017065876275951933809318423661417764818136954349801910947289659183205907635978138050595822817167382634695048482253157744039914431605407705833327862093429699073438637386564951267182020458189759639539473167305262740284225071497507262457351922563534531542013790807362096638967985972577233950127720880384678522269800818554838665988472686904725681783901668824751936421258981000261828242225303026541670953589896666403845017027801815095760182819731801373626506748649545334216147645301583637163392909561647882497385859202059693670861639633293087437877384915699722898602377280299589178981751445184815280690958557703331175083704258546808810778947268046285827679688676827960063420400635987497380624421899792134999122385982480962030787211760391418906033019456808071585813587855040591680463301169869976919272639519319957884486473507983156411773505229000774201026647133931017063535028172687046284512617846400326121260495019210841287975015215993377806364029650712736685647882277137470700409893971747477830976212471207113540890832711054032009502602396484901498297288488539479458831800192268848339196670216206275574832515221886262688014366560936112274820084678046554106772069816684413558368288304727052830244657059131595549802314508824276781591060973212684674348627528413115636411247246847734577829677746303734464686928337447130102043400246830239006257103359252930741117514693734434650341156094279154694658210195494448938367355244842110701624757606277869634721104708659611524616097621739076803054990429938975863685895853611689317501842386381822544319182675159143184448548805666695858957444093483300212083404408396447026845691145508978073224481632856901021147092841887153554798211755737911866074846084661647032434198007988796887468196284112523718999669784681024072426963391496416642876726679052255398689088672124288898547101995857838011002784141911852520708499390194778568288126988177289165665092995232831370309364116752589857134807788396892654854001620489185101289133824821592521438212096276891971449636416388964495955791232321788991003754159550974526716671276605136978114880585770749425509014346902267204371078502400248682929545789511459653304339571389028026459054323358988407028053082867795514104164552149791848954899198904981626741346957023585384557539715276421044488247353697713178586089356923016778398874259784095764170151421553811308198679927682831341340134960958956451988589194839482218529720401068083

Execution Trace

VitalikPunks.60806040( )
// SPDX-License-Identifier: MIT

// File: @openzeppelin/contracts/security/ReentrancyGuard.sol


// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// File: @openzeppelin/contracts/utils/Strings.sol


// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

// File: @openzeppelin/contracts/utils/Context.sol


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

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;


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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

// File: @openzeppelin/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [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://diligence.consensys.net/posts/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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol


// 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);
}

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;


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

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;


/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// File: erc721a/contracts/ERC721A.sol


// Creator: Chiru Labs

pragma solidity ^0.8.4;








error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension. Built to optimize for lower gas during batch mints.
 *
 * Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..).
 *
 * Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 *
 * Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Compiler will pack this into a single 256bit word.
    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Keeps track of the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
    }

    // Compiler will pack this into a single 256bit word.
    struct AddressData {
        // Realistically, 2**64-1 is more than enough.
        uint64 balance;
        // Keeps track of mint count with minimal overhead for tokenomics.
        uint64 numberMinted;
        // Keeps track of burn count with minimal overhead for tokenomics.
        uint64 numberBurned;
        // For miscellaneous variable(s) pertaining to the address
        // (e.g. number of whitelist mint slots used).
        // If there are multiple variables, please pack them into a uint64.
        uint64 aux;
    }

    // The tokenId of the next token to be minted.
    uint256 internal _currentIndex;

    // The number of tokens burned.
    uint256 internal _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned. See _ownershipOf implementation for details.
    mapping(uint256 => TokenOwnership) internal _ownerships;

    // Mapping owner address to address data
    mapping(address => AddressData) private _addressData;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    /**
     * To change the starting tokenId, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens.
     */
    function totalSupply() public view returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than _currentIndex - _startTokenId() times
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view returns (uint256) {
        // Counter underflow is impossible as _currentIndex does not decrement,
        // and it is initialized to _startTokenId()
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return uint256(_addressData[owner].balance);
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return uint256(_addressData[owner].numberMinted);
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return uint256(_addressData[owner].numberBurned);
    }

    /**
     * Returns the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return _addressData[owner].aux;
    }

    /**
     * Sets the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal {
        _addressData[owner].aux = aux;
    }

    /**
     * Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around in the collection over time.
     */
    function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr && curr < _currentIndex) {
                TokenOwnership memory ownership = _ownerships[curr];
                if (!ownership.burned) {
                    if (ownership.addr != address(0)) {
                        return ownership;
                    }
                    // Invariant:
                    // There will always be an ownership that has an address and is not burned
                    // before an ownership that does not have an address and is not burned.
                    // Hence, curr will not underflow.
                    while (true) {
                        curr--;
                        ownership = _ownerships[curr];
                        if (ownership.addr != address(0)) {
                            return ownership;
                        }
                    }
                }
            }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view override returns (address) {
        return _ownershipOf(tokenId).addr;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : '';
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return '';
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public override {
        address owner = ERC721A.ownerOf(tokenId);
        if (to == owner) revert ApprovalToCurrentOwner();

        if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) {
            revert ApprovalCallerNotOwnerNorApproved();
        }

        _approve(to, tokenId, owner);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        if (operator == _msgSender()) revert ApproveToCaller();

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        _transfer(from, to, tokenId);
        if (to.isContract() && !_checkContractOnERC721Received(from, to, tokenId, _data)) {
            revert TransferToNonERC721ReceiverImplementer();
        }
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        return _startTokenId() <= tokenId && tokenId < _currentIndex && !_ownerships[tokenId].burned;
    }

    function _safeMint(address to, uint256 quantity) internal {
        _safeMint(to, quantity, '');
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal {
        _mint(to, quantity, _data, true);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event.
     */
    function _mint(
        address to,
        uint256 quantity,
        bytes memory _data,
        bool safe
    ) internal {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1
        // updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1
        unchecked {
            _addressData[to].balance += uint64(quantity);
            _addressData[to].numberMinted += uint64(quantity);

            _ownerships[startTokenId].addr = to;
            _ownerships[startTokenId].startTimestamp = uint64(block.timestamp);

            uint256 updatedIndex = startTokenId;
            uint256 end = updatedIndex + quantity;

            if (safe && to.isContract()) {
                do {
                    emit Transfer(address(0), to, updatedIndex);
                    if (!_checkContractOnERC721Received(address(0), to, updatedIndex++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (updatedIndex != end);
                // Reentrancy protection
                if (_currentIndex != startTokenId) revert();
            } else {
                do {
                    emit Transfer(address(0), to, updatedIndex++);
                } while (updatedIndex != end);
            }
            _currentIndex = updatedIndex;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) private {
        TokenOwnership memory prevOwnership = _ownershipOf(tokenId);

        if (prevOwnership.addr != from) revert TransferFromIncorrectOwner();

        bool isApprovedOrOwner = (_msgSender() == from ||
            isApprovedForAll(from, _msgSender()) ||
            getApproved(tokenId) == _msgSender());

        if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId, from);

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
        unchecked {
            _addressData[from].balance -= 1;
            _addressData[to].balance += 1;

            TokenOwnership storage currSlot = _ownerships[tokenId];
            currSlot.addr = to;
            currSlot.startTimestamp = uint64(block.timestamp);

            // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
            // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
            uint256 nextTokenId = tokenId + 1;
            TokenOwnership storage nextSlot = _ownerships[nextTokenId];
            if (nextSlot.addr == address(0)) {
                // This will suffice for checking _exists(nextTokenId),
                // as a burned slot cannot contain the zero address.
                if (nextTokenId != _currentIndex) {
                    nextSlot.addr = from;
                    nextSlot.startTimestamp = prevOwnership.startTimestamp;
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev This is equivalent to _burn(tokenId, false)
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
        TokenOwnership memory prevOwnership = _ownershipOf(tokenId);

        address from = prevOwnership.addr;

        if (approvalCheck) {
            bool isApprovedOrOwner = (_msgSender() == from ||
                isApprovedForAll(from, _msgSender()) ||
                getApproved(tokenId) == _msgSender());

            if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId, from);

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
        unchecked {
            AddressData storage addressData = _addressData[from];
            addressData.balance -= 1;
            addressData.numberBurned += 1;

            // Keep track of who burned the token, and the timestamp of burning.
            TokenOwnership storage currSlot = _ownerships[tokenId];
            currSlot.addr = from;
            currSlot.startTimestamp = uint64(block.timestamp);
            currSlot.burned = true;

            // If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it.
            // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
            uint256 nextTokenId = tokenId + 1;
            TokenOwnership storage nextSlot = _ownerships[nextTokenId];
            if (nextSlot.addr == address(0)) {
                // This will suffice for checking _exists(nextTokenId),
                // as a burned slot cannot contain the zero address.
                if (nextTokenId != _currentIndex) {
                    nextSlot.addr = from;
                    nextSlot.startTimestamp = prevOwnership.startTimestamp;
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(
        address to,
        uint256 tokenId,
        address owner
    ) private {
        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
            return retval == IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
     * minting.
     * And also called after one token has been burned.
     *
     * startTokenId - the first token id to be transferred
     * quantity - the amount to be transferred
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}
}

// File: contracts/VitalikPunks.sol


 
pragma solidity >=0.8.0 <0.9.0;




 
contract VitalikPunks is ERC721A, Ownable, ReentrancyGuard {
  using Strings for uint256;
 
  string public _baseTokenURI;
  string public hiddenMetadataUri;
 
  uint256 public cost = 0.00088 ether;
  uint256 public maxSupply = 5000;
  uint256 public freeSupply = 3000;
  uint256 public maxMintAmountPerTx = 5;
 
  bool public paused;
  bool public revealed = true;
  bool private parametersUpdated = false;
 
  constructor(
    string memory _hiddenMetadataUri
  ) ERC721A("Vitalik Punks", "VPUNK") {
 
    setHiddenMetadataUri(_hiddenMetadataUri);
  }
 
  function mint(uint256 _mintAmount) public payable nonReentrant {
    require(_mintAmount > 0 && _mintAmount <= maxMintAmountPerTx, "Invalid mint amount!");
    require(totalSupply() + _mintAmount <= maxSupply, "Max supply exceeded!");
    require(!paused, "The contract is paused!");
    require(msg.value >= cost * _mintAmount, "Insufficient funds!");
 
    if (totalSupply() >= freeSupply) {
      require(msg.value > 0, "Max free supply exceeded!");
    }

    _safeMint(_msgSender(), _mintAmount);

    if (totalSupply() >= freeSupply - 10 && !parametersUpdated) {
      updateParameters();
    }

  }

  function updateParameters() internal {
    cost = 0.00088 ether;
    maxMintAmountPerTx = 50;
    parametersUpdated = true;
  }

  function setParametersUpdated(bool _parametersUpdated) public onlyOwner {
    parametersUpdated = _parametersUpdated;
  }

  function setParameters(uint256 _cost, uint256 _maxMintAmountPerTx, bool _parametersUpdated) public onlyOwner {
    cost = _cost;
    maxMintAmountPerTx = _maxMintAmountPerTx;
    parametersUpdated = _parametersUpdated;
  }
 
  function mintForAddress(uint256 _mintAmount, address _receiver) public onlyOwner {
    _safeMint(_receiver, _mintAmount);
  }
 
  function _startTokenId() internal view virtual override returns (uint256) {
    return 1;
  }
 
  function setRevealed(bool _state) public onlyOwner {
    revealed = _state;
  }
 
  function setCost(uint256 _cost) public onlyOwner {
    cost = _cost;
  }
 
  function setMaxMintAmountPerTx(uint256 _maxMintAmountPerTx) public onlyOwner {
    maxMintAmountPerTx = _maxMintAmountPerTx;
  }
 
  function setMaxSupply(uint256 _maxSupply) public onlyOwner {
    maxSupply = _maxSupply;
  }

  function setFreeSupply(uint256 _freeSupply) public onlyOwner {
    freeSupply = _freeSupply;
  }

  function setPaused(bool _state) public onlyOwner {
    paused = _state;
  }
 
  function withdraw() public onlyOwner nonReentrant {
    (bool os, ) = payable(owner()).call{value: address(this).balance}('');
    require(os);
  }
 
  // METADATA HANDLING
 
  function setHiddenMetadataUri(string memory _hiddenMetadataUri) public onlyOwner {
    hiddenMetadataUri = _hiddenMetadataUri;
  }
 
  function setBaseURI(string calldata baseURI) public onlyOwner {
    _baseTokenURI = baseURI;
  }
 
  function _baseURI() internal view virtual override returns (string memory) {
      return _baseTokenURI;
  }
 
  function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
      require(_exists(_tokenId), "URI does not exist!");
 
      if (revealed) {
          return string(abi.encodePacked(_baseURI(), _tokenId.toString()));
      } else {
          return hiddenMetadataUri;
      }
  }
}