ETH Price: $3,047.53 (+0.32%)

Transaction Decoder

Block:
10147580 at May-27-2020 11:37:59 AM +UTC
Transaction Fee:
0.120547995 ETH $367.37
Gas Used:
2,940,195 Gas / 41 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x3482549f...16eA1dcC1
(Rarible: Deployer)
0.511152914052760736 Eth
Nonce: 48
0.390604919052760736 Eth
Nonce: 49
0.120547995
(Spark Pool)
20.683522918275056776 Eth20.804070913275056776 Eth0.120547995
0x60F80121...054aa5eE5
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 173222246359121529826147451848987094643447197994862948129855325028586103923835547374325823218508226276758668375958605393334911909687875468614025441289858384149779220606968321511852532091104510051727920225399912899760175294772859245888946182673925425025803554204784188946200490037087236926308395228357662980102627280984044128137182242163267074363732181699370160478720331530797300902275406354204247931584640341006759012915282096112389344024875306562404180820523380117692535877384904545655668414551129613858753102655622344994004678835303908997451592110350283504655930180944493584541536707087545213015930708814368036949006000296661910171082028581850475748629118318259131035863907881058163632146715051395384191161236025049876192338742199143552966061344884525123057866334890602379892035373996910599050425157279494565643086577741573062933261674159919689443844048366973852348297873828323010359339849574347627042359749942131370777998332377491526220252186266025893006883998626604258366931250920006976042549932997662125439409081860468878228780976188778766682175706945281481241505106328975775620846694806219256883534697821568601095571921834251858299995247362626345131970266890343277682994815727608563744614833624576897693203674205829481556873876409672524226079232963654591915897671402498577175530126439709089612275286814210017620450048307593125072900763547617654785270953072424690655560250056184982725144177461805962433911205051277566581245845981009791958217269303816037404660773960009419852644376848292102587922122170373093657993621607746912222225605549858736479465573005370062642808818510471324239132092547220424778345515335367743560269908775678500984889468652740225031158823588693139985266272053922237849578177977895561673654968757377539891489397640440222475630261491191369661683431701932220529923664329826715446285648577458825036361977671350607243885174505314590581521342035640976610278379885903688059998635589763256736183586844510675040981984998913818576710842655865356980149974546082001749801200930047545706311899609820409907090581478600217227312126679811029405678421854244709792730852815870281706021162852454959664857911059109690286626966027264972425633547543385972488613302577450228225511982937832091115695450069141365786189889901424672620261918856324501368220858422853632671438068166750547936285191501058270897500270899285240578492003649777668875184999491109537890222669374130723985185373763303424094553492059483106636278302282436341510492115421332555348691461286848859443110392457058921914973712825718060576011454532275576738612845679595969541388414497069000793313139640255071924025489770129193642762246114266672201444417889594073014485796007711153562767334160928401318871310248463990918873573261460835644351225068744238072473342364190083068108322012734211426378054105699058986315824731188574019386583236150773604729506191659187420007813925331094016060390138659651716903672860345842764601202302352054250081055393356972167508594671634560429831100312906308049177513407213910914275112082171581125992811824677357240766299952961330931868832086533313465989700473382724239466134280781844567510356608495557653092437378853529678489949029512537767904835725101826264970351792685116364276752027081133202869036496671977679118674902904699775102987442222921637742235751233525360456775334856611384030281723852671532184507889065538617557825365107309562917182512113130679348675747550027989340358343073978313366214669729256681921615874811420478230691966657302386145674237028429930269474373154150303154852016896048690724138930849580001357512850499016479109011995701678843985194298613173729293846710373408979781066995245688060600597455111492485348728735986637487119317550872442351699124782311889454828738880064212552425882295218427597972008362356935328516773734010239201918100346641903883072177899570120696031032995027261449463269922579014751363508786440087004297871816832680630261574009735126071567549592850330170306629450408996789322059795349083110508470559071837505951818541155979695481462513917748846535206698393498008957350664897131518109427934189772996927516779131073431790292861799251417644144345420412398456926476667888745449848898140949882854481563261206360182491420353973296150962945219409266893716885383004758394003467250434411545618624773599306923737785055803385034468957061093498134384059431245738192709196262536876311751369945391538699090379390083172317537297167523207848492375074592261360335484918005944816012018597234104456754075284085252793926973647821424996551609365424091277604587651242177761417784800171200399607994751155037722266956781503261926328258906013960112670833141399079075053470690797425811288853743445625620079030769059869501647792893555900257005306841881907933696696925984603378117227830031739276801876032752228771242178572841507294127479935452792428962851884022116057621857724446283509641497836791974101842980542022643135639665207396639432696254126809633669527371690651794920765859103447887936744142808839337808540392740193888992595377399594300287571888078588445704515011813732573580864795460162846616229196581831260252726550444173736596949711740193960594575095947903903159468542364827771050591381046684622422418828872613738315633572536474552010884845792131213522304556362142470297585149793995459330944856566972553102875994290501751268490654254927078691055625441677966937365680738743947872232459773709470559324102203301479140867619886684398884614598045585619582135923686435385105390231761672152921341151218009429628737743933502172842289407514907371931644016661311753956844861356533806660791482287150777228819329080209468776411823670329837501308647318483253582425544544336064341807541384608126636742230859067470048723841517627404189644488736479306647035363855111601060745513566817761611040443102361423016589564468198662462207794871504435533950219462891986938772227539474874741856825498819270293413858519929386776890425418127968152441900300621243897561660846542243216038824090130432889772733935127095544166815178506209376758952725937070926814574969229890829474565470657600265606149777769961211365685592872658674107550201584120431746609994571180939040337396815834582074206909193688104905889848053907380734947521349209484647165137319062151655087384550707427784241636099649914704707214324518680971907420657011615820345578749874627949563214896770687317369815250103722114303036694781134590470139945862733434439507432659192297368214395668464784588256409397497229435103837787402209079100680584971103680830986034181077204930526223420387556083307554279065247693590905735938226209149820209034895003994570551459248520820709949247403009376296066035069229726826222550235401643612691064754125432579008517314103575264026850447564010695307010417124213242135025611552060260328568873234065707490126383239158241940558962512306499119836079657223342962317105733172506990112274467694547559350576894330816752365465626954966290916080986245303606532305000397149813428875356039911274265551317270584004361094940495638115624093349860741817219522190832939811618155815509628449679082750628221223442120846155773626468686958336554610323442960569000749275425443591363789262945286106332383808148900275096431191638013869662710761992670420424835535492716487658064364610765496955959678981625713966485255387274503001342737926338461780040174485627363992303890176636438456873917158406666104676150949777890468694231311465207524532380472651078377881618349236056403967862940709116097305723359694989925041987268954428803457928391143889657533473079806092281298120334800957720577998658820310912264098080610654517417849788192159898143334729911024808169445154190544073960203388794344615311730789859060837452486594310205248553219934801773085733074885345369138828903956904163123635614918707504030992336786894574403857807344116328871950385013694560509343272079119090688245905111986164484877802244535243703515163577457288740173187240411810549581896734952245392482053951280675020486111360942708216675396218412991107620425790750533165401605232579868299764115319936737713223956277861329580929139577411092697189126284294264367866112960653458977793326947035866672338823158307109406543539193887583531104773256853730973114157422556111986409948398000053956595052685985859167295092375283551421027416852740066229620184462067087712446794719872534569742049604296443047541653732969917057898766229152896079827831214035880015860543261105492236151595217175783923684293199381361877430433197280392798569895307061184541044275482104281498652686015046154540950283893910437374331072000525249981037606671618251450539194249756524219800426690998183385764772793081646260577246627459019446779568627487294498411306231024558402447067440247817900764169838941183792301322248266577602730520478463693973788013654132550208958388313825626664238007252919019595087364827017936837576409905316949966433345567731307399912477520561865307402831456580411901815194410206687102004894789088145573696446887992299790298808064449809957502774433391978140581797147062676192367133317598178341658658752701410178597983870667489632652932516829356495209361154540166390322469556782294595760565612399601847859209248370541967608614232863199462811680638055164560766781474983907104704508760789658772618348083802140376338884418034361513696189994610659633918010406086077413933507463370966787883860354974243568283166847415378958757798983920668095404881013827643962461545782804413906837470948257833739895737442824788489318273455675910469312436086318777819016155681695446338844862654103500527846946043231604157473173169146431945641020032345333894090841146653582290359283021157786552563955061043724354434488889939789456433640064589373081058094619195388380916892128620709339624317166500841307268914708896442889697881437858143915108130961219859759872289550200834086393901669618137615734044746823400894309248821754903628807007549867726681980477873485115064755244276796689430003700118384060575983212986719114099221845123742315766539127754547550532318757972640457422203755296385335557668396008725061599361605384571785854407712020119914355742831474698482147831244547386870126728318295882623724054034927955744926257839056921210638776722108888681216285361879611159240269314338821062296118790043861479161810212244711783105585834578586369574095461924054146600235316386124843597419323360008332611107747949763241821643748211903069518792229139518690231559917856622711147615518858538885941372964868419046070460231104746145178542173000423808334745249014226048864947924775921087228080245888173221362862671679071313241624900828767476537068424326750425110011641365978135378358942417289783576126443296526470371011848809924303081575966967962513883938873082575286424324832013218240715422982844315887780438764186450127874522254191423948814553264049972214136726454980595319713169344449486227103307733634099475570434818798261479683080764744590464870819192554024892325885461372523292041906139430624105987995951638429105656129862869926490693125464219655694074350487891316354452574233163987574100269268794928428863176509502805940775541388904275616382398908134237262282665462639584661681558144808244306010819853352031325573903768760489926274443395351646471746570227487154803003883399524957068611389432738721447077110119649457885310359940204664386466871507590609747450120693758731485702822628918861298353163226111914572061452538000540443128565325370591571722131718644449152263309638015509564040854254323846084250077368090039712867264684947109161204425216417905372984961014969130648749243664170356856334070444780324742706537619310058716473748912802174655499086454833154377103756817915005226721490183216679253242970362295259269080284224568437134407300807221089266734475121850583665861895170164123698825792062374265524199822082583028963391113116009111211161371722702409179273451819321779662226401401799663295297780838757423773203936581059933463904075669718366364152421094767437297742733865779026739559418655084245258296808439718315696227292817187797898616700338421844853657384675167166555093184417521191783945923280846450680956038646068345639215330883468807988549421542660463744092641684018081834307624316063896502244916681681527017850665536485786624224610984114638129164431088783274823977954628290856262425958175568332263530435516349432350563154894893194483983280799181295360716961828708021934982977463714349827334350951473699535720217847155746386632989672425929609200361143161460350414769910913815902810703980654809973119644860287582721373028669848206744249013878062630892327257518678381206749136361922881960920350839536309831136350641081531942923011304431829192024232185927679049435426001311542329066936468707103515096738055713440964178299727871739234677185236900886195408389815731450682114751113788611789751082476545185357630327102006594749855131413201867081582377661385542099124796388764686476715627905651439604196104053402565293743407308581303706384605394509497613083854844111266186438383136844736100372105157487037084389659252810311736077032944759062659411391902459327356071248549683664657291288678062135404292975386396433516818224739393719762986903606680076120179669476819452159658535392012147636487112451091615953037523835898692990800050139914084109026387847844116042579044248169197040686471252318443540283708683233006829426775449550645588553289741918281074639977498406623443026928171399198029732311641909776130448157687681576901910654372423501193321344351386676020314521084076580920111625179164479952004050148917732357119698879848920889342202881618214297886842422813348370616810046175545498575248375414219834975944914547999872260167091188175574041528468132015192176844141189104331437286019893780872854984096716861984783895229801361067074393757120306413852763253971854813571673424221488745787196422914531062868814551141342564928607999040323747405020645330716061512720225017385831847139494074076067361293336083288585345634064630369466336786130955496149420256479108201411208492182560244872480408666680870124457738773484753112223620347147161651059995926335332279580443141762497511478561440619680035324008400388320338254594142081453087250355679413178110719427089257137501568302170124179034446992494765466282199580807501263867449435265972628078489818342751068824103597566034457553625833658599306239074883819738519580300404561839466721694849790804669639929252850677417100364155139033086226888653851241494969386534134256464976997300753445267851027648976281260544513183590921368862025096453996809832184437275262648537041208883968680293037430241620795798274467976586510496237799507378826921327443062311532445944419241775950014457881491097253328396899064267899790744848806342487323951850411242788739340488559855349027525005246990944650998374530637122009954333551973166982548255687671707791204209636033838761369892426217746121736499279346070230847168693488330738703690617633276395194463603194289271470544765208315383033922875875097570639054159700887307725171664231432423054708617454002486157793764488032152177223201308990510474009448650010409204485224054601356593698007399363275148219342019199847654104064234153056828655387413126210403603107263916917239665922398374183561718034150848868388583207700117903844982887730030515619112484912017453475656976839514188590217757931199876477856957404368904288317306573936162846557638784308214521982256747213472329937950812726589638624898149697354110769524670100606568918590603311089835186367361651532052907346414650007060082419375293145751241314831431861781141784135803984664041278188566831462189770172003291555740150297084475718597819171084881964539653685037081495386297751400427155666364110969561566783660881781086063794381305693626757276886875055959138885050322203656204915545063409730785797265309505773232482234627938878167057178905355067169944948028703730307163107080237414257519495678883413598145644722254274357717976755234230536874694847302627158810941655022819368104192115043748367045328606270980541676038323695327452320746177629375417634816848467436774556517590880503281275207271360283074250639512815125945253926748477059919585578647528479972545044297074211713268594621353085861072888865858559164203782156584495526443489498017096929907344316040823422421544286854140564212949129306989963420701190960539405483319189506927218792009619273880921514019083877787263731166759432133034776666244046754453397120528688944894271881766989373630728415035031284352061074187222009641688304845597096275935779712484736361856293086258072899691315020366124926854605934924521429626237618120930181461740283354853053556100070505452592343309630086345781931161193044051717876014679962185837022049085988271492838529698429934804582633643545938707839636953987617109615204600286949800907353440923160523533295115868852943719560774460518227450023304414029438626710153356422149231509967044113748662206723084293429683590617144343068831202684363183676334833335122190481492402826774325569259982708067876296308999464235360363546077534747822414970788776696925853058949047878938386238770646327972583458966205562881843228666303239902955353090458935953326122455231557575815341692469176358770241815199243295131204323632335911453378702281007910573429551954519747580441164449800329193011083293629143907087784401611074003003988785606846367655903539298788043842922183339563892736860310992423950580203904925662397692907355353006617630182067500478919754745801613121688678853113234301411706442638461055799990794245975305448624245354482983509405163219485236906556655286945597686376266992287719805650263819957335774006453123624444075518372972407459427508115287537403809357290362127162670674781777623615157365805501267732760017396106328955505332444101751407142180613020629178571328474448050324478839597655973144493235587468309207378791588085539270448012303130998143941573202710766683315785512563021424382887794678729977220066122619819196982701008416392104225377730503873987680596874787087985154257478982505587670442679218743436726016178917547516703146394424086342708248718356541603601254296754472197667680008187626229631871246918449513633046824245214061769891548597854489886846944522841127242376359455752945772475396654513614393070562927603612308089008625860613386005498505048869722742707711644448887721335473166329063753752144244223801362200399229231772070925888310720038735730759036315390666103322585789311007671956872594491118678756651639730358641688612273867978839200165565723258550460130236411161481231262303550349964788359178900457655218491933730875791934174405398709002468601773568911638925757640261576222415183377997423068484149345678359986296474004107717940108808727334942525481678276790458663274229310895733496750100991782200206534223601429651180362070130925204741226255818662670604064608665349398198697702520088035306530750862475648733744099391244647670850543960972484529209215616818619663424661653538104627875187841678698252054462903869639346994796522086190626913387940315308478363672496145036693109185470059307629525672163487305633480130748941122822549926929955212269792466205676286952190036136141092184919196549433040337959498551436444991207142644434214273603467520480596693458762495243339228536249315292663600853197273466884196731528099413370105382125909232052258437486860436780483776744431627630737325543820356659334961329971538528371024837829971486054994374504605195491610654401898878472638621866844498928579517958698866639758239654606797656330631761616447036198063472009279049009465785665860205139390765862029637694912081713437794621330707668209829746091559096469140707608316442629793701781693192513859470991130447007913241863043934312995683055373402163722144502272403260115094160040335283906703182336921523649604094376065760906722376172229714986578193071084897925645185064447477998658032289495764240524151826424859306401936673672845710241995941559031865570253125903271357876256529377972761063189243473077099411958673303970643894572945547855760586238899458309829105744079140909284371852725020187419158682598192540572110337534544524087574370423110504714481531295879645668093219675153760428075110612152556547105597090673228590635427210255881243883014440580882780580359150148658261278185142902830635363636254272102782270662774173468243509619704141852498669834388301652693296294054093191380571029037644671488996801324431286951181403534170771189266792847176236601144618185121858339177234091540996266735520178833417908426105530411720162199475320956718127964882018538279811297060835823707388414392840731006301555040857116285680189914357751662053792631360391661713445954218799174814415362694375501081007512758081177917867989479321345297903298638453998772472578096466922555992658199099612656947324926165162095265375752780451592825146037654122334862415801971476674876670569694736003538640314059592601079722562209985614471363211631954541101560367901631652210292343144114320316047444603533737942106896330857192323539838218107702439868778188255409686670192424853965173967518951843114604997387166390198837981755548099456733658046379905891021491689144535084738587768244490492995158942905961876316395290961701228861080409850778777993384019312308914876907535436195396099017150767070282120918284055673439039845875884829256214612155575249066444925774315297287175618752516995760985778613305637661419625457490654570159472782987495083767749163593410268773785703473492415105104290593165695164110167809630280509850980447310854926827080045646255136739896482732314890177112620550267094652964038969404603127890679643975603694734745892761110336909116779064554206879951886681946904576131076918455713825503769855910372185370683844397148005298679872610138105931454558275034979331564420708745876746346568599601088166997879142654219645779514554091276499952573330096004561100044613091655201014765344436948930474723300446138645406923890656333919851387826623042613977638029500589782355181232381842974493819250501070412231975246418463349868661761324610072392475031413033204918287546155281649706307028693673411304293087556140743085355141626566508071759405556621356458248316991290018886006186316383477255906255134001610797592499653055656204788933055842080589654879300973081584993691092848018394927706095594432908574770741102685670300615099410474318475286668843246324474636538849233625215264348972554658053132816818232209047919701416032794605160090782804352857379666948254558680864960622612777358437909845304255791583288250005363903261208139783670266615926669984665883222297536139966431170614340800801327864934316753556606627061135024742232630749743772720279336284402890975849011472293175979446273769137310645391705759702452217262450456421034045282885401215805907690744996247916964032511494952659778357629271460942765859147955367204917488950101876546314248749682043421047769175096177874774923831645994910115921970240914514439964087344561013055971694866850995097608016282025862344939069458698241429991159483988125154329527416089309914663333548712684447329477012682442416216821361907825615841619630429359950009557162842259422299968246519365444805262238099765761072758298562967583040469510497172967416318831983079528071157783133194877302137517247523261331631183578647831351116346028870948057864214968068297048499027820086972478798982081296679314902427680795013172076988768802053121932612115022247592420836825365195752019198956288070134364309219077863013806568190021681129246230138712560022259942737371442286653314679474410493112159507072488473217357562905877335627146568617848728205103805064099820663454390434420553653375421703202285739024310811713442760528788535102663715679845492300488065721162296612962009171957054465000637125614228017049967325898916899305785418289234363542496066925396016138577724097993595926315976501174674938433205163312019559164451711071001588899199724384069301050577890035064596666660571629043662785793536530477975924955552665917823484596198843217039614170053632388844096276119477973044870074349087013471057565221479885362159816362628661304716310526283835006543718632303668590058477727092591325294248442733911429621504961291659088454446449213949573077299782020866568989182634000628464116954486424087250964776527615336277373939407961798789128762889669571122125289786453592756292704108971776216844177138293471806376871476664337195935988674052022413849289433184692499955410719303186817840010266136519280827649297301758138836906356325072849915465751443472566576119221525936609311629835902593852618948341327304412840709310502767448493660535360113021050121151115720219922348819900556325944173493886967740983337686495949303622318586808106695844642652659261724171145960453497133392933223675339572980452486747933503119345121359710458922720036928066632334887675991634944607285633720748558630216848337945968412559154862142149406280279243776926908482355533252653577602279879494240148949443239613768538004140500154268407751981670856086323196632557737703185691689404094732510289943292304762131974642196485865105399023635054097690197854546483610537388157405317237404844365835532274115407110693281397242410430609938053418584048780701335249521907061442391986521022352642276903266391293357365608496302378189130870086946314649722873305444632327148393661273518126685556547920599773663409770669906752577944962361196332646391590925168766495355839040185050195313220793726029413859904321777001000416031301293084058160901557543171612732220374756486836678759848338224442511858707866265094910347328667851789153412120235530625654594765537759324323713554892975653347300388468977194348098736461339024561929059337983568546380220372375564815778098543380256105656496039531030112310377742020372593644254958486811803745475533054529781778671925344101791929872972147930371668846277609061720873796964873863989175832093374840292166337228035447706718985839298207534033934733585395501994680701787116122799302042282786927832219175116093255819893229561736054038072352148839054614593598803945822733825067859713632377528555837502191244211575603424258063145905705076271959018689268696341776713143931230190779055496796518738471089260802655720107481495648255086773378898975542240631228797186055992275837402961327421021464889866577555906901364894357548742920521524169911116870299250680550797260261331333313042656515440398206549567727899820048038496080200796271210032540879794800534417229126602376291541274660205429016438580147512062773648843827874121352602337380995488570505474313625861949130000070650321946859316343040437046904341240025456072326155161855508884684841803086761676993941339309520129459084949078836162841310358227665483644987549545395979057793891240598182610836527947492454611219083972366457517720834330158811162198580730353653410933420447521917060952673679314019919489563089056522747253465981230646772360373907504040898245285533028283289809194765503875762471626408317629869927617116869061110492305412962015609662871353105452622459398901303768771487748813010011263213747457235670405078924533361209798052253309358207605566952620142552277897733728746430463800706276310933302694586946863367222259233063082600633815005927803736149653903225704333451024404604158570384740231816876316116108065652914136928237752141669033049776736676144847704536467574137991843602370926640214469010714276215228331722205262037145296062138956161134639667421088623564964082892330568550214406249314715564684369626485563093054993238775114820491420629540634621756667823122478495739864169460181247466170705144552136599834409204714937806091252790429570529349523310474841583750251681607795094594182626586368633209192980628562399764668343361501580960907957320847172547716616516890268965398427089874815714283795543120514658582665131566546816906392781960694510453615713245681241881889327280907905875734294247180002260553401824608319839794545643571277343764973848134870635141097253748243510400549746814130550130407315460690735765673998839373036957845040506151573596879356338580298745913446865811315204199954244557252833091351523740603801919545142785219995455938953571095925927998401204287401177968163671500758858385318618843744636624714488310697617287312433259204739182120798485777268773239764498713234753862231823071236962388523933677503238353638959875743126121392726689103138524139912032729981269721844788176942660950647314884776437979951123951295533045493742301602464953635742529477436001033241374951761548675928504841669907061718066571576416797518018644238785777261153447735777437511402861608585743131896069938089377491222678698299048928733011737268168194838415238695308914723312927418608624326557006376724341492128500760880377745069218774632176598123048792907819091692600838057798794486194191443300916765781701440218279166453523019612098954215676081287578097774159370664042568604474568253220692274226063481003783972411765388068918301926622405366681785802860204403207627151610104039765948669343014669022411629608872772843352776759942649299134806175820826653967254742483722456155644461003126682721878868032

Execution Trace

MintableToken.60806040( )
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

/**
 * @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.
 *
 * 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.
 */
contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _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 onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

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

    /**
     * @dev Returns the owner of the NFT specified by `tokenId`.
     */
    function ownerOf(uint256 tokenId) public view returns (address owner);

    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     *
     *
     * Requirements:
     * - `from`, `to` cannot be zero.
     * - `tokenId` must be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this
     * NFT by either {approve} or {setApprovalForAll}.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public;
    /**
     * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
     * another (`to`).
     *
     * Requirements:
     * - If the caller is not `from`, it must be approved to move this NFT by
     * either {approve} or {setApprovalForAll}.
     */
    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);


    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721Metadata is IERC721 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the ERC721 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

/**
 * @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) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @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].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is Context, ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from token ID to owner
    mapping (uint256 => address) private _tokenOwner;

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

    // Mapping from owner to number of owned token
    mapping (address => Counters.Counter) private _ownedTokensCount;

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

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev Gets the balance of the specified address.
     * @param owner address to query the balance of
     * @return uint256 representing the amount owned by the passed address
     */
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _ownedTokensCount[owner].current();
    }

    /**
     * @dev Gets the owner of the specified token ID.
     * @param tokenId uint256 ID of the token to query the owner of
     * @return address currently marked as the owner of the given token ID
     */
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");

        return owner;
    }

    /**
     * @dev Approves another address to transfer the given token ID
     * The zero address indicates there is no approved address.
     * There can only be one approved address per token at a given time.
     * Can only be called by the token owner or an approved operator.
     * @param to address to be approved for the given token ID
     * @param tokenId uint256 ID of the token to be approved
     */
    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

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

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Gets the approved address for a token ID, or zero if no address set
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to query the approval of
     * @return address currently approved for the given token ID
     */
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Sets or unsets the approval of a given operator
     * An operator is allowed to transfer all tokens of the sender on their behalf.
     * @param to operator address to set the approval
     * @param approved representing the status of the approval to be set
     */
    function setApprovalForAll(address to, bool approved) public {
        require(to != _msgSender(), "ERC721: approve to caller");

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

    /**
     * @dev Tells whether an operator is approved by a given owner.
     * @param owner owner address which you want to query the approval of
     * @param operator operator address which you want to query the approval of
     * @return bool whether the given operator is approved by the given owner
     */
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev Transfers the ownership of a given token ID to another address.
     * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     * Requires the msg.sender to be the owner, approved, or operator.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the _msgSender() to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransferFrom(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers the ownership of a given token ID to another address
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * Requires the msg.sender to be the owner, approved, or operator
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
        _transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether the specified token exists.
     * @param tokenId uint256 ID of the token to query the existence of
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    /**
     * @dev Returns whether the given spender can transfer a given token ID.
     * @param spender address of the spender to query
     * @param tokenId uint256 ID of the token to be transferred
     * @return bool whether the msg.sender is approved for the given token ID,
     * is an operator of the owner, or is the owner of the token
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Internal function to safely mint a new token.
     * Reverts if the given token ID already exists.
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _safeMint(address to, uint256 tokenId) internal {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Internal function to safely mint a new token.
     * Reverts if the given token ID already exists.
     * If the target address is a contract, it must implement `onERC721Received`,
     * which is called upon a safe transfer, and return the magic value
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * the transfer is reverted.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     * @param _data bytes data to send along with a safe transfer check
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * This is an internal detail of the `ERC721` contract and its use is deprecated.
     * @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)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
            IERC721Receiver(to).onERC721Received.selector,
            _msgSender(),
            from,
            tokenId,
            _data
        ));
        if (!success) {
            if (returndata.length > 0) {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert("ERC721: transfer to non ERC721Receiver implementer");
            }
        } else {
            bytes4 retval = abi.decode(returndata, (bytes4));
            return (retval == _ERC721_RECEIVED);
        }
    }

    /**
     * @dev Private function to clear current approval of a given token ID.
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}

/**
 * @title ERC721 Burnable Token
 * @dev ERC721 Token that can be irreversibly burned (destroyed).
 */
contract ERC721Burnable is Context, ERC721 {
    /**
     * @dev Burns a specific ERC721 token.
     * @param tokenId uint256 id of the ERC721 token to be burned.
     */
    function burn(uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
        _burn(tokenId);
    }
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract IERC721Enumerable is IERC721 {
    function totalSupply() public view returns (uint256);
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);

    function tokenByIndex(uint256 index) public view returns (uint256);
}

/**
 * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => uint256[]) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

    /**
     * @dev Constructor function.
     */
    constructor () public {
        // register the supported interface to conform to ERC721Enumerable via ERC165
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

    /**
     * @dev Gets the token ID at a given index of the tokens list of the requested owner.
     * @param owner address owning the tokens list to be accessed
     * @param index uint256 representing the index to be accessed of the requested tokens list
     * @return uint256 token ID at the given index of the tokens list owned by the requested address
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
        require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev Gets the total amount of tokens stored by the contract.
     * @return uint256 representing the total amount of tokens
     */
    function totalSupply() public view returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev Gets the token ID at a given index of all the tokens in this contract
     * Reverts if the index is greater or equal to the total number of tokens.
     * @param index uint256 representing the index to be accessed of the tokens list
     * @return uint256 token ID at the given index of the tokens list
     */
    function tokenByIndex(uint256 index) public view returns (uint256) {
        require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Internal function to transfer ownership of a given token ID to another address.
     * As opposed to transferFrom, this imposes no restrictions on msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        super._transferFrom(from, to, tokenId);

        _removeTokenFromOwnerEnumeration(from, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);
    }

    /**
     * @dev Internal function to mint a new token.
     * Reverts if the given token ID already exists.
     * @param to address the beneficiary that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        super._mint(to, tokenId);

        _addTokenToOwnerEnumeration(to, tokenId);

        _addTokenToAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use {ERC721-_burn} instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        super._burn(owner, tokenId);

        _removeTokenFromOwnerEnumeration(owner, tokenId);
        // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
        _ownedTokensIndex[tokenId] = 0;

        _removeTokenFromAllTokensEnumeration(tokenId);
    }

    /**
     * @dev Gets the list of token IDs of the requested owner.
     * @param owner address owning the tokens
     * @return uint256[] List of token IDs owned by the requested address
     */
    function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
        return _ownedTokens[owner];
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
        _ownedTokens[to].push(tokenId);
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        _ownedTokens[from].length--;

        // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
        // lastTokenId, or just over the end of the array if the token was the last one).
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length.sub(1);
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        _allTokens.length--;
        _allTokensIndex[tokenId] = 0;
    }
}

library UintLibrary {
    function toString(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
}

library StringLibrary {
    using UintLibrary for uint256;

    function append(string memory _a, string memory _b) internal pure returns (string memory) {
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        bytes memory bab = new bytes(_ba.length + _bb.length);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i];
        for (uint i = 0; i < _bb.length; i++) bab[k++] = _bb[i];
        return string(bab);
    }

    function append(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
        bytes memory _ba = bytes(_a);
        bytes memory _bb = bytes(_b);
        bytes memory _bc = bytes(_c);
        bytes memory bbb = new bytes(_ba.length + _bb.length + _bc.length);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) bbb[k++] = _ba[i];
        for (uint i = 0; i < _bb.length; i++) bbb[k++] = _bb[i];
        for (uint i = 0; i < _bc.length; i++) bbb[k++] = _bc[i];
        return string(bbb);
    }

    function recover(string memory message, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        bytes memory msgBytes = bytes(message);
        bytes memory fullMessage = concat(
            bytes("\x19Ethereum Signed Message:\n"),
            bytes(msgBytes.length.toString()),
            msgBytes,
            new bytes(0), new bytes(0), new bytes(0), new bytes(0)
        );
        return ecrecover(keccak256(fullMessage), v, r, s);
    }

    function concat(bytes memory _ba, bytes memory _bb, bytes memory _bc, bytes memory _bd, bytes memory _be, bytes memory _bf, bytes memory _bg) internal pure returns (bytes memory) {
        bytes memory resultBytes = new bytes(_ba.length + _bb.length + _bc.length + _bd.length + _be.length + _bf.length + _bg.length);
        uint k = 0;
        for (uint i = 0; i < _ba.length; i++) resultBytes[k++] = _ba[i];
        for (uint i = 0; i < _bb.length; i++) resultBytes[k++] = _bb[i];
        for (uint i = 0; i < _bc.length; i++) resultBytes[k++] = _bc[i];
        for (uint i = 0; i < _bd.length; i++) resultBytes[k++] = _bd[i];
        for (uint i = 0; i < _be.length; i++) resultBytes[k++] = _be[i];
        for (uint i = 0; i < _bf.length; i++) resultBytes[k++] = _bf[i];
        for (uint i = 0; i < _bg.length; i++) resultBytes[k++] = _bg[i];
        return resultBytes;
    }
}

contract HasContractURI is ERC165 {

    string public contractURI;

    /*
     * bytes4(keccak256('contractURI()')) == 0xe8a3d485
     */
    bytes4 private constant _INTERFACE_ID_CONTRACT_URI = 0xe8a3d485;

    constructor(string memory _contractURI) public {
        contractURI = _contractURI;
        _registerInterface(_INTERFACE_ID_CONTRACT_URI);
    }

    /**
     * @dev Internal function to set the contract URI
     * @param _contractURI string URI prefix to assign
     */
    function _setContractURI(string memory _contractURI) internal {
        contractURI = _contractURI;
    }
}

contract HasTokenURI {
    using StringLibrary for string;

    //Token URI prefix
    string public tokenURIPrefix;

    // Optional mapping for token URIs
    mapping(uint256 => string) private _tokenURIs;

    constructor(string memory _tokenURIPrefix) public {
        tokenURIPrefix = _tokenURIPrefix;
    }

    /**
     * @dev Returns an URI for a given token ID.
     * Throws if the token ID does not exist. May return an empty string.
     * @param tokenId uint256 ID of the token to query
     */
    function _tokenURI(uint256 tokenId) internal view returns (string memory) {
        return tokenURIPrefix.append(_tokenURIs[tokenId]);
    }

    /**
     * @dev Internal function to set the token URI for a given token.
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to set its URI
     * @param uri string URI to assign
     */
    function _setTokenURI(uint256 tokenId, string memory uri) internal {
        _tokenURIs[tokenId] = uri;
    }

    /**
     * @dev Internal function to set the token URI prefix.
     * @param _tokenURIPrefix string URI prefix to assign
     */
    function _setTokenURIPrefix(string memory _tokenURIPrefix) internal {
        tokenURIPrefix = _tokenURIPrefix;
    }

    function _clearTokenURI(uint256 tokenId) internal {
        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }
    }
}

contract HasSecondarySaleFees is ERC165 {

    event SecondarySaleFees(uint256 tokenId, address[] recipients, uint[] bps);

    /*
     * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
     * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
     *
     * => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584
     */
    bytes4 private constant _INTERFACE_ID_FEES = 0xb7799584;

    constructor() public {
        _registerInterface(_INTERFACE_ID_FEES);
    }

    function getFeeRecipients(uint256 id) public view returns (address payable[] memory);
    function getFeeBps(uint256 id) public view returns (uint[] memory);
}

/**
 * @title Full ERC721 Token with support for tokenURIPrefix
 * This implementation includes all the required and some optional functionality of the ERC721 standard
 * Moreover, it includes approve all functionality using operator terminology
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721Base is HasSecondarySaleFees, ERC721, HasContractURI, HasTokenURI, ERC721Enumerable {
    // Token name
    string public name;

    // Token symbol
    string public symbol;

    struct Fee {
        address payable recipient;
        uint256 value;
    }

    // id => fees
    mapping (uint256 => Fee[]) public fees;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /**
     * @dev Constructor function
     */
    constructor (string memory _name, string memory _symbol, string memory contractURI, string memory _tokenURIPrefix) HasContractURI(contractURI) HasTokenURI(_tokenURIPrefix) public {
        name = _name;
        symbol = _symbol;

        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
    }

    function getFeeRecipients(uint256 id) public view returns (address payable[] memory) {
        Fee[] memory _fees = fees[id];
        address payable[] memory result = new address payable[](_fees.length);
        for (uint i = 0; i < _fees.length; i++) {
            result[i] = _fees[i].recipient;
        }
        return result;
    }

    function getFeeBps(uint256 id) public view returns (uint[] memory) {
        Fee[] memory _fees = fees[id];
        uint[] memory result = new uint[](_fees.length);
        for (uint i = 0; i < _fees.length; i++) {
            result[i] = _fees[i].value;
        }
        return result;
    }

    function _mint(address to, uint256 tokenId, Fee[] memory _fees) internal {
        _mint(to, tokenId);
        address[] memory recipients = new address[](_fees.length);
        uint[] memory bps = new uint[](_fees.length);
        for (uint i = 0; i < _fees.length; i++) {
            require(_fees[i].recipient != address(0x0), "Recipient should be present");
            require(_fees[i].value != 0, "Fee value should be positive");
            fees[tokenId].push(_fees[i]);
            recipients[i] = _fees[i].recipient;
            bps[i] = _fees[i].value;
        }
        if (_fees.length > 0) {
            emit SecondarySaleFees(tokenId, recipients, bps);
        }
    }

    /**
     * @dev Returns an URI for a given token ID.
     * Throws if the token ID does not exist. May return an empty string.
     * @param tokenId uint256 ID of the token to query
     */
    function tokenURI(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        return super._tokenURI(tokenId);
    }

    /**
     * @dev Internal function to set the token URI for a given token.
     * Reverts if the token ID does not exist.
     * @param tokenId uint256 ID of the token to set its URI
     * @param uri string URI to assign
     */
    function _setTokenURI(uint256 tokenId, string memory uri) internal {
        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
        super._setTokenURI(tokenId, uri);
    }

    /**
     * @dev Internal function to burn a specific token.
     * Reverts if the token does not exist.
     * Deprecated, use _burn(uint256) instead.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned by the msg.sender
     */
    function _burn(address owner, uint256 tokenId) internal {
        super._burn(owner, tokenId);
        _clearTokenURI(tokenId);
    }
}







/**
 * @title MintableToken
 * @dev anyone can mint token.
 */
contract MintableToken is Ownable, IERC721, IERC721Metadata, ERC721Burnable, ERC721Base {

    constructor (string memory name, string memory symbol, address newOwner, string memory contractURI, string memory tokenURIPrefix) public ERC721Base(name, symbol, contractURI, tokenURIPrefix) {
        _registerInterface(bytes4(keccak256('MINT_WITH_ADDRESS')));
        transferOwnership(newOwner);
    }

    function mint(uint256 tokenId, uint8 v, bytes32 r, bytes32 s, Fee[] memory _fees, string memory tokenURI) public {
        require(owner() == ecrecover(keccak256(abi.encodePacked(this, tokenId)), v, r, s), "owner should sign tokenId");
        _mint(msg.sender, tokenId, _fees);
        _setTokenURI(tokenId, tokenURI);
    }

    function setTokenURIPrefix(string memory tokenURIPrefix) public onlyOwner {
        _setTokenURIPrefix(tokenURIPrefix);
    }

    function setContractURI(string memory contractURI) public onlyOwner {
        _setContractURI(contractURI);
    }
}