ETH Price: $2,282.85 (+4.93%)

Transaction Decoder

Block:
14820602 at May-22-2022 01:26:06 AM +UTC
Transaction Fee:
0.027892844227087086 ETH $63.68
Gas Used:
2,228,026 Gas / 12.519083811 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x4b7274ce...13bA004C9
0.1 Eth
Nonce: 0
0.072107155772912914 Eth
Nonce: 1
0.027892844227087086
0xc9fca2fe...A87D351b8
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 549212059253152619414897563257090507748067348531435743522861995823913239011676489875929274993060877918132355527685210731667359421631368195941310578812316132287396861955586419451275733171766529735948247523924260571405382559094456707983442948826981286269655462857859281214508221511786218779516955994472727038527463623565383492598353164380603350432374934554593830484317358773499011107846019781754114661232452141016249500697074407405711377477622918256215016421456028777375649692294312172698535742596530166860103987912091316607918526555037502234407307333220325859848702231602771693530327150817305029203106126515947360570722783452274003682934031280073011481555743713825652709014303638341127348226869189722637660330403599505735666450926077779376758923365392934258698567297381013414854377548272662890282079476406789408498789855317578925844115909255388667676880517750951930022355290486995236475480239790344353612651488488629093937074768962951940185791243044426444471284977083899992063693900166017870879620463934545614833801885502660730738234966785431635624443060332519401447336876799904225817886692815258102020811828550780481163825960154079254017177815655645611052129789963618877637101021830888995600051899616048173519972158882484872053737046476868379626127926784364414939997315170116274419957333940652100896304056106333285152052192344311862981262144693860779782149767072557880037601022470740013306572894532095673243168786080816251358640749020103951690253411938827392105231454303508464517812133538068071768712131804817063565788310377034984062156405200115905080181862925731867557658492182532832017784173408707598932478760365925053302822118310111104012127901332256673165854003262164189177651952834432799320976249500629170781555206684377809670068025549888152780235006854734052412885534616233183705356473913649582800947899574680025927271746640164248418236861801810529796454594347690151431152563838780236709248708017089465319604753871935724432573243846489994787737214846017790505016656375570414626375820129565434075957403201456596953037072882676736456751996233501170171822784574450955755838564382836531305967103712338238618548346135369534762149576531445932744513796560417780999704881573896343258804973554097835867366871569995979612593216172959643140025253117681290038067089639585147952846446433843097694959200551439469334809697231310264059677448910352480778937175566787441249272813192565653734370636882215997409126949856446261486722454381813558977413575792140981275832457945527445450425394637494911306175658804244349833076557605567056562758693798399082217397945858454410011785799423806612295019120385674735890095763089974427359030698631210248917954924165875070797755618375569434031997305579027286699741899032249183691631704395883319199652457509628808875457501100377485260433039207819044989970615933339645242297314307408285533283870393179856201982896506540071131803246300879976774188027060218218740737144174354030367027586406365344460738828387695491837226737582348450208680203280992529514328617066838233343969259138199734176299496933485292898237534969537716556089507830139123523983524323011460069151721335242463960401304297061784851044405002647501312853865702790660460491459698359807520035524220954458225971297835384128618700022271843008928907338283147402284650316734169398500179764300772863162328205954004399370664255468012813470410096704443456092721348192183229729743440791050662751359965884806962076305188210179958795617069642194000949892250509580511047487414490562485510055181775553235296194241160057995872632449347115384157404304760933737838686034154712784504406501863999289700698102535492013697093641090331982458098465385693140713502285775725599732941150129710452088751203336373979147778211012269768019440697738202425048927692458900053467342366614849502156019431702249775781088235924950749455655635397867843418686022363144819294576159251997433644262834518905744025422573592084885055919406769968539090679783400050757355648140343482154239250923332199531101748896348666226878174159432020342608265119137451461093699371835308972647303230701050836398669764912673654947333177256800468990505078485684913569609734901355087422505099077436556191505370020318036977020740672463473800527545288872163526613643521722876133725617843372301903103876048981498675644456922042142582394833666908994644370778810757650595331004424935960933260098692294324378498236445793352317172612899705954946140367337992345856841336684497067546006070720213051125346099327842740687739464947367971436401356389058138271191933333060807902332518039245727477238931781441379714350432778728484180194598959598581389041758023274647345492606772746560970091339462643804741324717083512515429489595574451468631779290213663695297955928699891533493851310371049754864038770731298109320028765199675780938028069335357476531200234763514207714184436853122869003940810818386872597078621322447292086037700279262952237140268633770231852867807257448748731643854987516811943944378068745260664225003762402482279729143974003804524404102681026127576392875209476019438173301919842030166897279826860299359460297285412010717273989529004903603499987193609572621622940697086707617627595068760622341899992354130578027645987837698231739613758378126984161317274173715873662356584719670547301583425628954960360576935227355423075906057053661962594128747429511519429784057166305882702448208666003581778810743745936437132545600456062897182715068713308206458811346389295769528626807307131821649768317198022708534049566904926702668416758794878333393336213630770441632244028251452489829789322309320381074791462912836818639239565693110311527264786245179713485320209905511786089161158999862403638718614615460606303919780955402803608502075701786348116526055854505215781677297348794673206259943366543104840412406094778455356740946988148113803659629109094700287142288244200162028730552768956594265648237052458454400234928305480784837288321271177966866095756361938673774987950081836153885441894874588566617536814524241379709172364661193811854032744210622947281373511208169694041655464898352184635045846692044979240161521095641538631736142022291310629860827246420702483035410388794432790355788971866732038351972756999700645888041997468681715861247211690653687977251532708341204956713779263931242575801035916334112879378113633870255098452787562321032670103838245445929943169320591992559843135892821505869885880549113242576881798397469165800283117358332235021956100068243546829473379056427074970672157065734661540807092046798581057465893617272335155527828166236972183040371386412824594151135351918686135172748145681530085849582155175547125964962930004786629042274092876151336042574127251070617132236622019563463704420208393669660399575270286210759777201596644384448071402603533653780218022738573928571462122822762361424990171001343410146485306601284851804093294719980446807127683876730908060482209856930993875517350373000563501828378862056771146265868507387716568424895521177713244682120109750328550716639268726419951969872122134119248438090854663367052955857860802060368207616984880194426365857730078598099878560028661550296091161216191228318392635498720038719379650316690470941741643902697889065113066364142777339281767801729087299764893873983994499013952259387476545029019542606893897098431452697265241214514934799268235970925738550318012467511494363870844880497860793887362094628242815217515648314424967600508825700383766263561477252341740384990473572223044223776863587118197889211412487222349816415120911229801088691396007043203063965386288292251739508894612196448861257044353468847998782936253420970982969528044386466645970241503477720110806907977182886633056341454971053254916074683423782438998056438520328858140608657629320108266427551169157301403433597098954097104643924294881363425287052246188774570340209535518140578407582156725018912427795879749695922277808581410915913013020255130775994466519233881856331965395834245118450200195829080477904150214449610339357604913972976933192782117886541130500365887996596439576358636323073767090354184129205355034664313233914781704539931312413814064260486072424271935616541511002245744026955753507399970615859722623818852739552568366239682135380682069471453082613576636505437511738198459873219357262983656120378129352154369309521716881570245132496329221006561687527919824685292789302790634750708957389452039377162440044772257587336653676979480865108081984464688801616331987451280471097586446887727341684243032116319744804666021794916749049302562719133341535967085351751298695776118612630792072979353472841555264982485549886584661374221939805444425163497661764658867581063798254496980847321071219523618596554260949840329938751934528880249371748589884977794336669799110960289077845529704021113991617969277751957986760137846942627640724258832577663522653783188717751560402662858927178546398456651833944068602120182036807948766986286501424853901410227305537069230411532245956280494371877395946183329670771608316422351431071184406448505188782043061053656048649699260007224105853932089635433299728809335025989781216631510255292254704270112222228231532412790199704203259332741769111688820596315502235929507528626226385303123120665386992971142735652224969517301180032993165048527127215038831607164944770140619607844887807999867020734650396972348026549450815062391539175180666062426968307382599412578606495998283629702740773303240002909678972642941437733980232381445540980513103745406786461480004643790081771427111945755348684009132114757570778352632092840374490661317366854481484500197321543854764969279920738546060644024492226293971344330283759154982959622075318426937240623968264638354031824727934609563979668764439159322114273900848703909837521441479868045233604387562052042344059005783438664939831615103772574886224437888672913724814634474130239032557480450886490091869877782776450679600424218489631849363089434231288011351012675146006572755109065221553717830236049313626127685938563415675275441111970221845116963143835284743579495599439026073803349030280822245978024459841637904227259654439729141769447498979622358392867006482716419386973992071274998816849833298489190953768325930195703802458005480815010653306718347098209591160077639948630814774006337057789210437348211910239641717204531569679257137870942302589591012832933915394079890277855183728390636877698563303406187723608813473583998586527695539741768715295887916655139774700910146040665889891727325121171778119266204680672649367951254033209974940387171982127128193511490766892656154121248567548581560144939971092190933039685699752974683519568010681814636091322636770820464192060119119434106033777058196099040438216184927149565775579005510795248902685337279568874735454478689402856473261060448090892734658472173422227908751584642873741092854580095237148948491554442946644529087891685296964075843078169982520881877692509244625686529681752778701332221365869391299170392313953324690333685897310931257772409917467132329022189710780099751774218032239920145597662359268498581742196608343446297007370815627580491772114268419373158590463095862872145033358355567856069691365630555158755203532610731420117499224726084073628128593283039124647691159158984790794930015307230128454749707666053162895443181615377288688089916129601185195523314594524946899165614511258134369047585456465221548277243523720122238702848352530268422905483636301593450427666625231914331976838345097958375341717081844013109293646218034216388961193361185841094624007440900495126073263223361441762257549090154719398891358438010839236475302645592356706372812121403135647779111510148950704630267194265340440791994753677701636008158365384887899093637196810126161159091239861612771161147243857687396224220790552841356072936413448957631568739956203092056058579005325525274288344652611022143293374991039180058488217282650289044221983025532747728706899249925942600949949539643538640778915227802770198357304104311887341825458457041146795834133303958570730277064593795339514833761788131161107438410793819007788586114927536058309249097724152082871020705612368802708017752992041608136024890329984431380625997750830412571098969664378896983891567036927815860135024231390998856445390922160013442499362137833333397309298928274710439036050847406337562067573708607223831491746369662952532164461902560712477408577219624431818139325239546954500101613564527185567246727043485742579386832455018202475184488513202723735507489533263832607409204286323581897230236083826036225343486592549522900585316993831215975680120671892854684625065210028776774782259633228607596327894219428013551344287086375700420785839395908153476269637288927629244101171916389735172385175437608142710486257958110813386296534285722889294705159858639390858322665292231548656312275207110574283213804390846805414185510422825327075211770603233128974042879581587018609402961368725704463757353971421080943128684877262231581142713289427319847861559510019823065885136104170552714885237837343404039162835971741601111565913354976130937451312273017077727698197307921055995508561554554285883949096043275733627545988641567726451164934995390902663571890900728011522998185773399435777945870204065225376353467427101609104207799186352239885830968269363792400654549490571006392719774764766718424081421987575111600456501112198396907462978097462050609901243901977774521961932832695107443687530678318203341062015600831629541548170014975076518544215796865883473505810426265884972199707424593811320462368361694028228414570887147061195469704797514562228294833150701411562098662437820063951181559829215740252455149578976538276371390207675935773602015483297252088737802410484960866451986918463556251864556048264639349846706934323222836866337815630090810030419634627482934937685355912908889058920141999159348982060266588976924709134712364707985107763943524522921685577035774539360542160823761595985197058119695163360499299283514895535673599686763102656364853765162042038952140889908621317501742554896885275470990539162228960989755696983468174407535097130067463780728346034418976361778759727507054457016930710139143665963701830241992296940457695979797928739243798726281092612208103254048340754687295113173857846254471082404760419822639468804017104593376620754446106291354642079735708410635589803099793045695548596502445133964974258298458716125491069934534329910160187042299095735702269311514200360640683093867321552234055321092219651573695895715122429011674109098328765586336821753742812272469340273202420712840568695045876379972149137495081570151166373800958232267691668272940571088751562629646715399946886117297820396894314999116288269551665638969653735622403447240843370087756056991774890200583876532960599455599491106746885965182336149979408344976713605434845359691670559183680930843475505337749375437296037510221997374871013928174021761261834686842948559398747604757279475953042105121509234664338136411353929777017626976920600395107647911245818418432201414089729446420746987800700020118332410844664731809550710148375737862777419031768279890373625988718290230738081830620422159257116845175384257405861040312916752255997636757323313898513798229935131178422670552724869378458035926547884988388676258448810525342558829850197186146509562130428669556330418473076930463852642628021449884391552272963656025461421692534450126104709808183771798834867614245700349541592246347429531395944492807886546152688788035614955722952687625123028101143263544288447439167909805181003453627850002619730441390870932309910744584082886252295119419693792668328378265491647101264029164733466631059496828298169019365639106824205426010947567389493228661489963352373930666735177211967058693843578228519472021812837572869713443614093113746378605892873428029317630711987392048673050617693747324858593268708781745771150767126851320443462958144758010400843227204740304999103493052466583754821698138045653316349180355816532036552120163025086030825897877008084044220188951007507948888602164684624362998400971778505693276336028424016539798326574436685600005832987722085762389056171184225782442376871770161963169389305246698933277870507024818628323260972983476410126224794485072675681604592861720716968374509322035596901099373644438407715481067939231570001516317409744825286429427368387018631830795433344330596834915734148542758363584508583752493117162898242437545284584096689272324332413653206103833836638921217624597787763319039023465036724287999618786618951368696069709415241140426869806285136559501795377712547941333826390884357597167898600316558928069177719473431448431200690416634750650708438128852725346053607667481572962445815988782872105824076880227218525481552251248669061526127379112318342487654952851251058605341460016897907181752518127861942329287673972284312230003954050618065226637122789723520091514521023561098773477698324812678516499426644825410555141170047015394274599836228053300506591900147830837499724818407789907505232449997844002707327580132287484254335550141069321404886627902831009062535935025593183728879984473555396239647718458007269688960699671701293969375116068527324792941141724567245538359299705104534434265739431796829327645044689488984176371075800759441705139783030055765763883190629562790441364341967915335192118511413535023069036060410344825824690844920118369103945220651735995006907105599683595853680916294544585662902469633413708187640014487561948434837445074247223348940158220918111942238160490042265256893008097321776237488008987307610759052505448931086272173799934861235089835898283928593499608509214980982800377393718765944164195292230445945768920171799499461395213634551947126241665657732662730739929078079413203140597068450906326237713465312272903414256451173652179758387684849472940069901063586904006760168526842631615701271819672015890989615102438930276770721787525087459495579784670176099834743796713293469473605016186031629306680271060572963976424092891861715187211154889266243214862941505650352121094466176366588406570742585927407963481251362290482038795733023048485374190613786171270103878033416993084711219335451514358804133274636042418894589620107398679068806328339320731128501928287475244745227100191937966444986392529982135665029103526045859044816505799870598613045364120497298316343252550503006595821026417956337994903979015478425296277340443980485165449373391813049223950516289605029738639711775575201278358182259812933421944534100387865420764487583819515016490259411848202404412826291004910586276734713969690234442132488314492811686142055058651854169172713475232319062125872199618993744351336228167646585557731691515198358085084634540047602230079831595127581682334702326634600098886453281500742500767506970309896218989419743517704507300960054780440127894741157777459594956992385874465329434296744076845393008297642390971827669832995979467673336126199705845375445499310664877209940591933492847509501482156242051272899626023095639521626170092422372102697821519558227625528880137115645768957039950656948302592367426867875765921195029499031507389450862231364224373298165603623738280710587017446973794940026117627435419622701544309419740340076458793463291502899927155961640016650905829375498553792336109652317284665550020182038676654548514172260658977404002800824738725383022197832744686518519095588380218359438826372491124763792449796538202645593899888450934284841700836411020148467897585824635169818158246740158818381553281333279713807132121558388048922500104192715801515925957873971028608875430184775251998191921881494400756323393357249945036046443156698393856246722533737074203117265588350532489343077010091556673111711626424479264648048032691543523324498939495796579556262220724659639991805901174768665679315928504900698958796760167538479202419413107723538900281666203036979978552034997236548908925735088831930762041704531695995165947676057608705377365154597941503424488331830687007485021412811420957442334430388405284268077483222871194449208782249766049552595407442279947345708363031031768590155933627656452817692118619843743954003459760293732876106632630516267566008469792841888883427075843482146043845692865421695948124874328293519025395112049557608854469959993888796824140696817388479294108288201041272494159532679690906674576773046595140725471798222777296344561307929433237959901707418243163546131942630090077953395183884497837439547743122214868242369351427843388247732421804038793473988955135952139442293632769730076643577387275980346570420017870779087426447311320586266953344901877343260907249018996291479477275824517039291205390865518310571150641656906925307792348644208362909983158257214443156320261419885566673863991182609701764423788120809339942436372669442723538649990616322084776524103158130070522007021635577121563035743300158316743138883149618129368416051175705766904065595039468531377014526429246880930916802499759219719542155642053863124270508134595663931596103768611217649811473430939126372275689453588639358727799672670701130706733021985921889415958623756994029876660775778381673615577034223714249894764278869602075492845461212099398400915992602289106580364806891332491316122888455509232946016289601678363157791420575398685527062919922782202660791463820204491848715520522785773932268286842397427719533567527551777873468202313967318018225273167368231346833854195743294438299933190786672371830954097814145530482177699398069373820508449118609064712374685680746655917962029744407241480640829442073800226870255251339649439891642552454219034816719703446087427955372985011671379451667438992906727154346284826739751938755736203381684411312486745621143780195560280679348324642985211555242167647638754409503738167902501374977098976003049904074649773525637613426932530683850722456228019582641362860442175186996047818626265050786426185053416523627330501380214620147946156329318153884805087913457354380144084014665021040807077725468029592502955432814355831416888453502063676408788493931263260138397735922466094529127058218481594300978165053738779097296663385005051861359794159828913715581962688789267931964142328863642021256849185858461331350129003780294567918754485431945255431617052723
(Ethermine)
1,329.874994195583941157 Eth1,329.875491104126074673 Eth0.000496908542133516

Execution Trace

Phoblintown.60008080( )
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

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

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

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

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

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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);
            }
        }
    }
}

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

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

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

pragma solidity ^0.8.0;

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index)
        external
        view
        returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

pragma solidity ^0.8.0;

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata and Enumerable extension. Built to optimize for lower gas during batch mints.
 *
 * Assumes serials are sequentially minted starting at 0 (e.g. 0, 1, 2, 3..).
 *
 * Assumes the number of issuable tokens (collection size) is capped and fits in a uint128.
 *
 * Does not support burning tokens to address(0).
 */
contract ERC721A is
  Context,
  ERC165,
  IERC721,
  IERC721Metadata,
  IERC721Enumerable
{
  using Address for address;
  using Strings for uint256;

  struct TokenOwnership {
    address addr;
    uint64 startTimestamp;
  }

  struct AddressData {
    uint128 balance;
    uint128 numberMinted;
  }

  uint256 private currentIndex = 0;

  uint256 internal immutable collectionSize;
  uint256 internal immutable maxBatchSize;

  // 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) private _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;

  /**
   * @dev
   * `maxBatchSize` refers to how much a minter can mint at a time.
   * `collectionSize_` refers to how many tokens are in the collection.
   */
  constructor(
    string memory name_,
    string memory symbol_,
    uint256 maxBatchSize_,
    uint256 collectionSize_
  ) {
    require(
      collectionSize_ > 0,
      "ERC721A: collection must have a nonzero supply"
    );
    require(maxBatchSize_ > 0, "ERC721A: max batch size must be nonzero");
    _name = name_;
    _symbol = symbol_;
    maxBatchSize = maxBatchSize_;
    collectionSize = collectionSize_;
  }

  /**
   * @dev See {IERC721Enumerable-totalSupply}.
   */
  function totalSupply() public view override returns (uint256) {
    return currentIndex;
  }

  /**
   * @dev See {IERC721Enumerable-tokenByIndex}.
   */
  function tokenByIndex(uint256 index) public view override returns (uint256) {
    require(index < totalSupply(), "ERC721A: global index out of bounds");
    return index;
  }

  /**
   * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
   * This read function is O(collectionSize). If calling from a separate contract, be sure to test gas first.
   * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case.
   */
  function tokenOfOwnerByIndex(address owner, uint256 index)
    public
    view
    override
    returns (uint256)
  {
    require(index < balanceOf(owner), "ERC721A: owner index out of bounds");
    uint256 numMintedSoFar = totalSupply();
    uint256 tokenIdsIdx = 0;
    address currOwnershipAddr = address(0);
    for (uint256 i = 0; i < numMintedSoFar; i++) {
      TokenOwnership memory ownership = _ownerships[i];
      if (ownership.addr != address(0)) {
        currOwnershipAddr = ownership.addr;
      }
      if (currOwnershipAddr == owner) {
        if (tokenIdsIdx == index) {
          return i;
        }
        tokenIdsIdx++;
      }
    }
    revert("ERC721A: unable to get token of owner by index");
  }

  /**
   * @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 ||
      interfaceId == type(IERC721Enumerable).interfaceId ||
      super.supportsInterface(interfaceId);
  }

  /**
   * @dev See {IERC721-balanceOf}.
   */
  function balanceOf(address owner) public view override returns (uint256) {
    require(owner != address(0), "ERC721A: balance query for the zero address");
    return uint256(_addressData[owner].balance);
  }

  function _numberMinted(address owner) internal view returns (uint256) {
    require(
      owner != address(0),
      "ERC721A: number minted query for the zero address"
    );
    return uint256(_addressData[owner].numberMinted);
  }

  function ownershipOf(uint256 tokenId)
    internal
    view
    returns (TokenOwnership memory)
  {
    require(_exists(tokenId), "ERC721A: owner query for nonexistent token");

    uint256 lowestTokenToCheck;
    if (tokenId >= maxBatchSize) {
      lowestTokenToCheck = tokenId - maxBatchSize + 1;
    }

    for (uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
      TokenOwnership memory ownership = _ownerships[curr];
      if (ownership.addr != address(0)) {
        return ownership;
      }
    }

    revert("ERC721A: unable to determine the owner of token");
  }

  /**
   * @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)
  {
    require(
      _exists(tokenId),
      "ERC721Metadata: URI query for nonexistent token"
    );

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

  /**
   * @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);
    require(to != owner, "ERC721A: approval to current owner");

    require(
      _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
      "ERC721A: approve caller is not owner nor approved for all"
    );

    _approve(to, tokenId, owner);
  }

  /**
   * @dev See {IERC721-getApproved}.
   */
  function getApproved(uint256 tokenId) public view override returns (address) {
    require(_exists(tokenId), "ERC721A: approved query for nonexistent token");

    return _tokenApprovals[tokenId];
  }

  /**
   * @dev See {IERC721-setApprovalForAll}.
   */
  function setApprovalForAll(address operator, bool approved) public override {
    require(operator != _msgSender(), "ERC721A: approve to caller");

    _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 override {
    _transfer(from, to, tokenId);
  }

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

  /**
   * @dev See {IERC721-safeTransferFrom}.
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes memory _data
  ) public override {
    _transfer(from, to, tokenId);
    require(
      _checkOnERC721Received(from, to, tokenId, _data),
      "ERC721A: transfer to non ERC721Receiver implementer"
    );
  }

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

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

  /**
   * @dev Mints `quantity` tokens and transfers them to `to`.
   *
   * Requirements:
   *
   * - there must be `quantity` tokens remaining unminted in the total collection.
   * - `to` cannot be the zero address.
   * - `quantity` cannot be larger than the max batch size.
   *
   * Emits a {Transfer} event.
   */
  function _safeMint(
    address to,
    uint256 quantity,
    bytes memory _data
  ) internal {
    uint256 startTokenId = currentIndex;
    require(to != address(0), "ERC721A: mint to the zero address");
    // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering.
    require(!_exists(startTokenId), "ERC721A: token already minted");
    require(quantity <= maxBatchSize, "ERC721A: quantity to mint too high");

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

    AddressData memory addressData = _addressData[to];
    _addressData[to] = AddressData(
      addressData.balance + uint128(quantity),
      addressData.numberMinted + uint128(quantity)
    );
    _ownerships[startTokenId] = TokenOwnership(to, uint64(block.timestamp));

    uint256 updatedIndex = startTokenId;

    for (uint256 i = 0; i < quantity; i++) {
      emit Transfer(address(0), to, updatedIndex);
      require(
        _checkOnERC721Received(address(0), to, updatedIndex, _data),
        "ERC721A: transfer to non ERC721Receiver implementer"
      );
      updatedIndex++;
    }

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

    bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr ||
      getApproved(tokenId) == _msgSender() ||
      isApprovedForAll(prevOwnership.addr, _msgSender()));

    require(
      isApprovedOrOwner,
      "ERC721A: transfer caller is not owner nor approved"
    );

    require(
      prevOwnership.addr == from,
      "ERC721A: transfer from incorrect owner"
    );
    require(to != address(0), "ERC721A: transfer to the zero address");

    _beforeTokenTransfers(from, to, tokenId, 1);

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

    _addressData[from].balance -= 1;
    _addressData[to].balance += 1;
    _ownerships[tokenId] = TokenOwnership(to, 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;
    if (_ownerships[nextTokenId].addr == address(0)) {
      if (_exists(nextTokenId)) {
        _ownerships[nextTokenId] = TokenOwnership(
          prevOwnership.addr,
          prevOwnership.startTimestamp
        );
      }
    }

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

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

  uint256 public nextOwnerToExplicitlySet = 0;

  /**
   * @dev Explicitly set `owners` to eliminate loops in future calls of ownerOf().
   */
  function _setOwnersExplicit(uint256 quantity) internal {
    uint256 oldNextOwnerToSet = nextOwnerToExplicitlySet;
    require(quantity > 0, "quantity must be nonzero");
    uint256 endIndex = oldNextOwnerToSet + quantity - 1;
    if (endIndex > collectionSize - 1) {
      endIndex = collectionSize - 1;
    }
    // We know if the last one in the group exists, all in the group exist, due to serial ordering.
    require(_exists(endIndex), "not enough minted yet for this cleanup");
    for (uint256 i = oldNextOwnerToSet; i <= endIndex; i++) {
      if (_ownerships[i].addr == address(0)) {
        TokenOwnership memory ownership = ownershipOf(i);
        _ownerships[i] = TokenOwnership(
          ownership.addr,
          ownership.startTimestamp
        );
      }
    }
    nextOwnerToExplicitlySet = endIndex + 1;
  }

  /**
   * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
   * The call is not executed if the target address is not a 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 _checkOnERC721Received(
    address from,
    address to,
    uint256 tokenId,
    bytes memory _data
  ) private returns (bool) {
    if (to.isContract()) {
      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("ERC721A: transfer to non ERC721Receiver implementer");
        } else {
          assembly {
            revert(add(32, reason), mload(reason))
          }
        }
      }
    } else {
      return true;
    }
  }

  /**
   * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
   *
   * 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`.
   */
  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.
   *
   * 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` and `to` are never both zero.
   */
  function _afterTokenTransfers(
    address from,
    address to,
    uint256 startTokenId,
    uint256 quantity
  ) internal virtual {}
}

// 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(), "You are 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);
    }
}

pragma solidity ^0.8.7;

contract Phoblintown is ERC721A, Ownable {
    uint256 public NFT_PRICE = 0.001 ether;
    uint256 public MAX_SUPPLY = 2000;
    uint256 public FREE_MAX_SUPPLY = 1000;
    uint256 public constant MAX_PER_TX_FREE = 10;
    uint256 public MAX_MINTS = 10;
    string public baseURI = "";
    string public baseExtension = ".json";
     bool public paused = true;   
    
    constructor() ERC721A("Phoblintown", "PHTWN", MAX_MINTS, MAX_SUPPLY) { 

    }
    

    function mint(uint256 numTokens) public payable {
        require(!paused, "Paused");
        require(numTokens > 0 && numTokens <= MAX_MINTS);
        require(totalSupply() + numTokens <= MAX_SUPPLY);
        if (FREE_MAX_SUPPLY >= totalSupply() + numTokens) {
            require(MAX_PER_TX_FREE >= numTokens, "Excess max per free tx");
        } else {
            require(MAX_MINTS >= numTokens, "Excess max per paid tx");
            require(msg.value >= numTokens * NFT_PRICE, "Invalid funds provided");
        }
        _safeMint(msg.sender, numTokens);
    }

    function pause(bool _state) public onlyOwner {
        paused = _state;
    }
    function setBaseURI(string memory newBaseURI) public onlyOwner {
        baseURI = newBaseURI;
    }
    function tokenURI(uint256 _tokenId)
        public
        view
        override
        returns (string memory)
    {
        require(_exists(_tokenId), "That token doesn't exist");
        return
            bytes(baseURI).length > 0
                ? string(
                    abi.encodePacked(
                        baseURI,
                        Strings.toString(_tokenId),
                        baseExtension
                    )
                )
                : "";
    }


    function setPrice(uint256 newPrice) public onlyOwner {
        NFT_PRICE = newPrice;
    }
    function setMaxFreeMints(uint256 newFreeMax) public onlyOwner {
        require(totalSupply() + newFreeMax <= MAX_SUPPLY);
        FREE_MAX_SUPPLY = newFreeMax;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
    }

    function withdraw() public onlyOwner {
        require(payable(msg.sender).send(address(this).balance));
    }
}