ETH Price: $2,534.46 (-0.19%)

Transaction Decoder

Block:
9821785 at Apr-07-2020 12:39:57 AM +UTC
Transaction Fee:
0.017083105 ETH $43.30
Gas Used:
3,416,621 Gas / 5 Gwei

Emitted Events:

84 Thing.MinterAdded( account=[Receiver] ThingFactory )
85 Thing.OwnershipTransferred( previousOwner=0x00000000...000000000, newOwner=[Receiver] ThingFactory )
86 Thing.OwnershipTransferred( previousOwner=[Receiver] ThingFactory, newOwner=[Sender] 0xd1898665a01a91ac10bd2c6cb1899336df34ac33 )
87 Thing.MinterAdded( account=[Sender] 0xd1898665a01a91ac10bd2c6cb1899336df34ac33 )
88 ThingFactory.StoreLaunch( store=Thing, name=BLANK, symbol=BLNK )

Account State Difference:

  Address   Before After State Difference Code
0x0e654137...41C7b7198
(Mintbase: Factory)
(Spark Pool)
37.869297021484153278 Eth37.886380126484153278 Eth0.017083105
0x6E1Df690...F974a3D91
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 4006216025823578786989406503508201899355268996741153289635546064144176852411717716567083442628130560207857507776905004883052091413203317461744695927990692545455537452585706093445425299663086742810286732217571079759321057608940105187489523887085561914129638664544005250720535128143182892706244242857276622176403735585269399388597600995631522160655141943961493925665833319071567666774169749105117606874280211192867177183463402353637836767531344055527267429302241411369425462313050450755525678898506759503295308105978831888596726968158454626402806698228162711505227946398652157075122575628579220420086312337716805978946431961788855282965872308797127087762231099992470420113179263605505750792504696551113958173035548228406301275072583012223076292260703059311085701376741977114032806719376887734042079479913709250218403780977634054615713754911779641909919505699866028135702530206347288079564983763426914388883812223145712062494056051955265804882188686885942953908153718951729386467306022584645756863544054699197948327280575351321215520639226423870136966379104337789004197373516752360591005827224406823063720473508528941303837763947193480446020747338467553343397004331105802962703630578941142349424447179363061500732017119448312173303961663503544438717029943475893263813467658671296542684751520718272938322421486951728454296390719748299385939781816179382092014715955099586509066734642099554232673492498980467443974245537536878211747664581939717734259047630552585068734472565255601198631426421000439071714498484825473370865192122942705611054357544898461581459195042558213713085268142737938724057362386006131318118883358073444755740328463255421421935703318880996009566307484388222182315316997876576419596343547731162557472608575652280693912890855487065532739925361585301129459997921911035631041320512270286778203062682645526695775056493812991641058420772173263657686724576516920059009828748661897942906978657614880743214355490286364812000113509537225536082023028149620482348596071046393347443287882883955519407080402736539191368443617282400634942689501922196819238929232382505658480187444532009290728510977502820595197910796841143686390927968502736152075224531084227321468131034803624971155210865490611275744426996485726043655603912748815451199320628760290737770153334062932620138568709205468481906248097753486795608323606345395082396710642246801030152241741847021860588315298661767470645175547056155825894183290097860141405556310816186047014105072987841197529774078298803314632475665392722169109299035061202702312101320912710958785795125036610970196107576368264306263838260356260456380946098568258908391478283716840496627845395006987939909616451135318259162124909019143579812493077160811333655331619920895478004803085962058637126164027914433080940356242679479041922101262307405525005029735856567828681068324535172997449724319065445964114101802216983683720668179593109974512860884850647591119571559112481441311976819508951291533509579111238447738594160268317127925608688744235360650542959248788774107850348191582572202699596641167591460220366058048172403143933959685125577798969820612742653054816580453582860164943592741918029856511131714656649038355412955130538720844281274331281371013366060246624645482502290317385262592065324337115615968783535871199313018250483089641627785884107173934115408226539539587288571646918986747940369710965392861571697692487082075389647469639939046332692029360810236421723104712876362351517561591369983283003509725226997860139474727000666935552717460714340347240499032719228659221754147128062888920024227007905439467520115374270491749242225938634010441338758905786668258995310472542279165170331828548234721195792254911476857238985744567139851321717580281511897375140931060523893282835095659983774839421186133789744329096439062797612195142409765511405691244010886052414077479336677375245272125907343824589788009851046346426782006272112589604621011078682181732793188634680640378901129883319139126656003016362988269507323670408520969698360251348341654648717076071323900519788884060171087869777972350317059631014523211037599005123921800321642275814641955788229338407524645365462433315493726741196201691186371419166261363689216746718206200523533132546418631260502038030587310803531333192799172909908912378867063698918600189276943741687151913606588087614545069700737189396036515255495887872033090088605182292012683382054588347342907477177571026819406070939047066338118198111699529635532735588010269438825493574979651892154287113579712383640690914221185856381190527805021252881246219557160278057442557572983337109329563965721781099461509297383633569178187277142397737322476013882135877391086922122379518632071256546421376185256184556420016716835358578483557616863695907425042328142857105564333106421528594298638691207423741560490873562902192235650530225123762553580360047197088105318579809410892599475722109877636997932521275665945670395068335648577162967250521671031334322202157546614210977349051489136839155960626221034678786713241059818084191204295364307047689266491315637735155339153848969237031512700546489443973321952868872673638159093526619136759480441071242065125700017261065986914014271007057896990064024270291925642704784207261107399371200096506142681481052649817781126382057601918325441129327164096354113399796364895908370254457790996117129524086636300603216519907583315718421575753203428349308669916517986411202518809392408784938103746400425061486670979488730550421568415047194947127642640269627399039380521357126840228572914447167664393782020624892350012762874213797552060149135673858140782075250146171800898229143853129173441347963356136608923428723018988979094288376341294452041204144072775149775992486237224833208240211287213323307226915221289566956375694656130279981938334987463517792468404470373133117457267623575389608980745705496662128340845456643964365790449406328260525533457318572149993958544399500682272353596473188634761477873198018152233860866551124412499250328141643897431314198491174832681322515400716769294299867955945644951978318867629747973302100739915551063388275996593608423443432488557555069836708789569588861028999478665687268909481285282483249854783375048324156267410951106062524623563844137662138245337552052730528181203103323182091386134133171935060193783671191930338109880523562722945702834664770686403424928943281991892655467696637012521783011021503949505669297927116725680915175392853507136444334332965951724188831515426731807501333356129056492945832112997152302230581978785613613646419832899510839816609200549371980220741012144379514147050879652663864503648914634061379916247592166453381456932222865525637829298811124830558301179797214246638445255898641735599585364105207703264342192966238708261648802880515608422964786967685921926936572057328450483050219781300394027608885841174449620939821332530539417481715383051812077254214612707541087419729878841908626561161279077106564663613618683137636280239626269037048115597245818936617308031014366839672671890547548167617842708788913750472138763134270949545961004159624963115745712486796844837439835290531930661554030547106002717892324727330158802929063130667676431400464701747213239551182046170709579655745515059616706241228829836566837502479403743270363190568651304126343305460738913441214960946093567780755649432035406807874665376400562827224166303287519782022095248519621542401040519116788857806229280670063086162483921738303385319753350516810821416828332278280347525083595761347114220663567223232202122715949287907668423654679550776916799913023688459557853451509315936325396955478460367066913424832538930822229233336062497612157954492671759991146562066684663756143906793751431911177646084343933222069512039346286545816095102034479103523566051929797905344300910663386742449884884955500924794234333578763368648273290709148527787395224582363646545605456905798346766613520280925538539695184073790107450452027612818674156239737510050462419714459529491803310518690122600690195022102820237915262047851291409682987632588858062855083391297543906725597893282281095218214232807416242626323715214311205872117197215490867240538789847193465620485840040981909691621948101273558521773750429032845414887642459789149875428071589448850654077884887467315794497616767122174764302915970644515252547577799523101921934871402149799532067822869021882557779907995881254410650573663500164448948936743621639304227466459049629387772636086878885629562030031889451928176251388472080656015044013804332251574483082065248112141788351094012757108619323273356158463591138116042222793700460502726017121777697289742602914172581330612605667521887621913717516786363648380827578290479426357403910148543138653237904447608243024925053808457579129797110135474941858200400836804546372519798996347182086066325418027685312738145479339069931682334333333415873140521982784196423251657030709396678518647868885081140497742534665936906525199634236892010564945255607268525987292096459867723409117021725534679619885043048315717387963014888930947991038283461050196562112345491105881008554298037706284602864310702139151694526301949132939535445864208593316209598641647929806451556149246840674604936594495250309829609933723347163952245924379459225898659597987316938767531945922833239318765613424157542377852258844876550866797998837156083254041573844490799028091521374539701526082941273729905863779245787811290241326812184450936010801607414418013675497982829373359922281993786707091285867232630572334739240622815956994012477198153131530556160661989100273007821368656091626028910127857341896744589679782334981133931451330146433655517018867425126163371646511714236544640410299451753370735878715666072192502844274520252889678170344146435156608767592210416257576803917321519824314498974255560027370868905809947862846598795858594702713885678215671311008944400497373447579509878694810378904422117388697034205012886329432915015537420373845343894716828228221364823780815472835632771276212079220246279881992006258900293864854818155483191845233421329965130950851233163563120108721055159947990394163057307149388228527278608395935952840240470159286585483140348697938087753877297898390323942419254993230556407432083880541628643678201747195808287398441550680044796372711317271076239701512770720429641622726816483977597783204284936351785775169627349826710698804233219501618055281330782319400304996708528904674793898507320782629757704763612270365878029431515598017323735265517932663610223571969029752078308304913330449617642097000001497825941179239625671458356897501165400111297089053452921773256534731979759387890063658975955948966349743833462901517306475104436581322413463629855818227105534276386287234716092040356205396922740223973455847240869495025927495504618579674637351689864134225228632640071918147281666977241798700379720499646221420517319367899975182724346329621755218429762172252579312884938815685118032984013503772475441272618916199986581886395734052076998746576351049053591252988296810761171367481844371257966235400405961626346956697486797361735912380224565923081124739398814321760418999032150973615319703618372798731646442389180542951719979350073508369905145328215713474263128318405134395522282049047179517341168812731419347851996066971225201394841153199561326551180248152455693295250387495464703631686641276147915423483905943634886390644503255597777112816234776880207263290694195986366573159432708638357139009828838624309522623276345596117408908123198488437745828042029529400408973155735074999031131069316786419378046669618847119974226445584234876396726615090315793642735033679181862754744200987930235443930441775863247870492146702202259385528784614817981881346190489215727036401807054204502650335052415360070015324596922009369646991377583680805606946413657623550711572205780200791267419074458785616129921896504685207185294673352855816190723128947173535843476579540937464719872941841984099625489883275626139788185485947243312328011017562823982795905664380677352150640270235127040728822782626202814472773255662616692178832614631952364159216711454716895085776701993371316059131873469749367771970032492253064405281019836019178290968413479062125678128662121987550079370296524184534259444498042138762723742947368805476718500954277726249473386091932366947089924776634327844832336744204975327988476595550724102693778857500093463091739175915280580912396640454691582556171639529319670498842965791452987968525264876696991522830642580996324871583326654264743572267826023958450540337906954971905401431783726279443060266103181133860427340961866844626861194581859860554524902958177050730057467706998284531273430031790700440769562860411774756241265841735963279126851065371845111124326537633108003569846264776047799244047514961603079000172123513005089690585997332931234405026211922426470642034092784342698084318279466155945808323721446404721645021746954010940522611863606249708550887017314761002028106217981317698902478478995336388019333827800033068971679025706036299544287620850072233829798838312927360641587388602070408141342717471619778045485118122642051278169972824968858060888238654268655086560987379281126771960985715183380470426797928496982580153184137808256919673602876303767114401023588994941389112339674259530049471895023655634321868712603581795775777775308032433337124012130669814110704084401341558406259805317864509589410639632258567211720864414974811247890096370953128982968145193258029180615481165403159568501381266935588418900637365401045317124644559244461288974867935757628714268281861101251148681021115274089866532238738735534913296653946869419101263977571500375720444731798663402318776371182308169618830071429926026807828023306752938043973277345018932845967930259075017072464931243024020658934583489996060226159500515727407097950539683725549504668063188440982837016883406372535225123979571013855070324615919453307652272201002286309388283452449913529046620556969556145503185978420798029586922285130392392401562847300245401739596497667613688155024704831845713579140797376915901406755982551423020325743481869143292997481289006542501213174317608825832471913479251293285744412833852494964416153687015734500448794291236225432355823394329465977047091393009569104585614229420931588339469779353086711082842466992443191174053541589216966807265424510116241358300595094116943200498932860279602009616283398050364508326624114450523217750340137747775612771035393979216990708982178430677024630469564004047183347682116822235739262796555637253730669103145447829442354064377251973294888253935399973319393108650216111168405132404712332242379057619709620010654195905041947601230775077446199987279438075732448664378414467340285636801750372474054502693873389703385603166032221093681886860149138435035192869710626418214208932602693182755343977073229723011001011812810583557815672187851469410427678802415290651935418341059784928827636112257159290299195171263874311792880383265510412257234070626252115962068883259230792489717479812482338489843377040441035953629857812285918700474730650951536389738054046243207439520204434726131759780025597810184854472954825924464949700617552101565496729235233555255835956356256525294170352419370679350637791917605605222149144072845064124674505576168655448287224003981006731381785776333491881628890003250993355827655305547298504975831603030033380339516386017430213692579417917292829801458829304695374397159978462450476725286484325802794383762036016042743719781010372950218558610587933752779849639838997526685175060509696928566832235728076832620500533290940899201895253743005753983054229096004687119375953670713073244566570634507129424614353174705922765194777404131307865753368010692142953155662953702753829629574663148176432992274152812374359359531311160725624115732387963280674041155181228506672549887811690108666356635310826790341144084791207533904956141494825264122625683841356081234931256617905249472061530275752736858399444075583063055658003940238802463780825169808030410506296393562044272892947719624936167887453403800283849510553974339683948939278963852136673457999385001215390191176716422164353618477634903552785577729032906949526425211440517456655087357871295768339982892880137917225746607600252452203803949385331315493288140636562355594025419445973280740489940005519844332965894237889712130008825258848463233676543599342594301460596984702858782198646401476716821994292317073127715401130390789700539933179319575282047870004203765817278676003004275299551198389960288296355601161044259030944171441172296863889024432560383143096894228402096431832139829428466101297186875367125068313087183718753387074678570161445289207641819217408063489933499027621541420712340859395585903703084290714690945731631999435933133898367614217168959895647913616857828287619556455416050609248258436110524402742107707937807557516923850627154131393956044410382855120341486503684497336508890819906717198689165185754155842934025700835952810883543792931067560635981915765217728973496012632819139567980285640854952098091177524219649659397080476615756677272362103005923526333914642676742714984833510248110490878478644877287609623444631893898490297541398417895906585158717505019376276455148692420529214378166941537339985052456188701449753903274948870869957843457451908944325401616883024992855152629385815054206288861014017636516864797122715433614103061518609233562400052484941019513757548035012247797932047759500989350789605500178418066128233256143739167497332980253699045713652871584415448259093129489505112722433558514714474089782797937418835885136441165614279321685993144228583248242057180038150452358033159164206745211529422093191248001699659817674014239289156522886077065533245795920369006477771006335464858220283049360469541978515224562688927802484729641091105286358541280903680028069715342773140546782020716981855974345395175451173318128967694354380827659370131375196918375719163763341733305490057121484452693088925761502049955729117114551571574573179229599640000155969245949269911482402043827948628498500744471679988165414892421733395411058015864205225788144706938136711033930161803390157767344739561946606244928458352188903595923484035593449217402550785594393209628203005972115379047031665425621632567928424993591537573017255087848661540813941088426080024239406958894289789086721351857879304467047028536009280207825450143215520104451725723291409856380720208948012549283568172805957119047748140350735055237470988782948836521694696999683979817152034840845981816809443943966455282841687294402916266548305708229078338057022377993538704666521169250881271383672995837108078101989352047682985512532769303611335319995792457539025312215346881012368538472017467692682932532889633624091831732704386282870430250082659220655635917266341561845237262589069078590627478250385623555215104420658956650830894502743891426696701004402858428565871034492096377603952882752211350043967815363816082243081054100815965342331208932751995308054917818435230189187677773326933582315789321354985382332671861528960129802015596564133373993489709988886417059088146185921284331446316701995550535115561794939708765955577738559229637197379513828035475288840417906909149169091056734513336888160755954203602449118212135355342902727640290045941200184294265400302669592803953001497691856959521530399438112519488983125360600363503482316104511312398061317174442037905429574666989208948843417830636591487079317988631471509693618454020972692486437153813303428244393874053797058090083073241550382260096735958291253210037503998516192877397453606617493910409277698082671321167354270278926235708770560988323919114183692340950396351885198861336372338997938491338019003312547390274177406335583076975094896593780889658051390543908055990687909842250955275639829932958316601545451099553624204761778257587668700487270017429742224736527318108118732174552117836646278251862252877455200908528289958435086530473065328413005587563689798744954257266523873866222175238658685110271748758269523867281240590478437805215612053070398797782742391220647423171377141893303160237053088620372719671964770558666105944054263039408882015165892387060401112300687895964753056479283827046464752651681841101578986385949288309477428000234819814386555433138688650921427859014114937207965445247067600954504473307955168511804963153773329148448540662593000751070158731301721305422635270135418140578659917835911557229105092436412657203308773028940512022628875529793676819212143105197351985988498384249804743537957694114790366641224693270268362852115212104902340917158146824357223401669496384286502746564911436129687491096202209625355290399365821547568029050890522512129663714913921102977913962253699719867128220926653857828479752138301825853079345283873213869782003636918228378004301107691806539487935661520593526104784396917189874358359494455123979986454829180210010732342119332805060654953053064613781086284652576487374557288789888966676143944963473644192827229160393847142136572486048989915350575676204681714955775941425867100072487088666800226514626640194048808995064313470087254360324028180073089476095551243511716243377887465035394925990182235490422855428018338737903006855208155581897939327797889798713537822731056683056901705663481582833275869792056745975169691850192579635272592064590649150167242111458062199686877805745591449856410916150774403065233424359521326785212729872266618694137602380892761266715286661622424870281060063083512156727497899153001842191216507969901368763895679053376975776153553538439897086179884225392302694637161805822352093447701101398445990908886543366820130381583433846915165074837221689305888452864220888734910024883523551582186706499064481715896884040134750698784003623071526501717716638784191663279777031788107378711757021808463027311894363031853351358218631843439277333122588623300619426029852943573999858630033793546953140845677223396088136842903451663749756111451014355074668106682351495438452549761466300204969837243841871202650864138972453390719173364089749936194226478717303351534415631274079694470309643257753496884517310254569524005378262287060045117173987287988481264708997547669145837983312607108149605206312468142121720548881617687279964790954107921306613766454390216238265762247012253189682246287460842119630781863269207369914250814057335679272979487757288727234036565272414792972543480955272202781013701169238404543288084532905495478763133518647352840132768086303805399639509477622093604012694789744259689791243477572981602119079557197146966315087895088948406231568389015333418732892415518027929886013072585398278689323758016530265877753878083843598195802517145698311540238198780534145490687368800056651384125627388654564182307939779906829627427944522457317530049588518602532695825811894060830496594635561888741214796136729285481849493562422574308989311745417293795209728859280604607454956255737422091778567162891914827680545092000555929802872685213415755598352745651372160442436185452561246365849653928656870132592210822509126429694420138749070258419151485843287676368351628801030151306093034584880342765342631967820978219396547677108808241883083016693085167212723108546177821027027035153274396105341657624801922832315418833220840306282584633471216380642141412662120553062695150821962246352987377988886670131470546399094827250077641731243233814789594772380575331551336179225228890335692893262049937010919778185966397597342538071176982351374132113036489679680385677390262009215168177496128544052955522123114782582274904686268964292600308071266069808266267353868955662851909027695959776297426848835885755360032798198623564554276274089947619514255349241551966356801896221058193164687255029890980010843412989524834933900228076913362976195514880810278959512093948104362884772527718117344257692653044177486511507101202846204732307537704031388863457034812190823204252386655433535529742754480986200916661285310588319190755813426061108640881296245710433447076812052674521616861329647079011573912112092901241667375016057370306346417254636169189344688148210898061192747605613103357554940875751354803641622986327838779800104563156832576149531816240018454325856813717187870442367614994816988200487778903241703349219221160093558518607980932743575827391311393928750747450280381857373014884915345614086660803663151201689092625774633636375566352095608086139878543562560052076710380480204230834561556260368932095026289746366565946790549629309262600786970544643766719288324905043206135620380855092416942521296266659056304482355060806399750438764824410201642225780201989669098139514698838916897745317617648008265215618455115507082900644527724896005877690080332856298997662074138475958057564521425183458195382307071756975090548891513068895054411915785182846068197868438181360459142246629799074970745724930979200561284743313330398292585081992016712268064057084166885534883690889377815065197233806613680913791827685221479829051755059568994167008983837216468482602502362275576981680659690311724589451922700829029789070847864640872535044698250172526602844578059248825607353508194867833013212903387783043543453621359519838796766785394305490557763016820966581083464500148542365580964779273558410521512067728526326925638278895618617490119670523490851861164717336316145485103638502171592389316697946653907333770745784054438774575712476467046151412681245712359411621764427723271983519125348445773902774491497606064348471354242399978913371094103225520111249743707799648096270141384637993848429409459119752965653859507613535230067869306843617820335006539062405924834416202459417121149382580644726248429970161214192201983743517246317381670674681859459557265560383667884363784644540272298055424169205302614482254182140006806385630458851510787276913876759399469513342386428803953564312246903207742274979692031940841077683952831895603518858831982154378089917119758697428892084973992833922506067875201985601096162740748853359400524862034136711687403574457670255416186710087911580539662899470539735583025086701897289247024800738981608364088628122124548976345379003669932007408896862291395655507519745114127750299852210372015497280197804795300215117617663194005928536667174752629912627579247312354848000112252923939180182861162065290876059590813252343922798602976378857571662534887637609864549365847415668936498265809892530623146496859352412201865656361093961641571350644303955790259097408131998633135885550640585842222616281031116155993773897155107550808569697005884990006841677031487004605206231608788775657483972015566046401641417365161030726838929131279417997535524381438409346932191729000182707658924699375798209806617622145927010059752074911353931037378375373321084296314833374578533331715055963163100616250958352841490422475354617019612087038854746415403226603974049779534627056577077267408599420640709554485363771626685521825683682680709587977894839913605103024833039343595978882596627240578807681987906342088490574579967941173953543298586204591939898269338029067187202855484917530319172170488507442717061694432593741697803685413550890814183826799200409154568322445030917581559834746123496476662645493337508112398995448576506055098447769548744280512660724203419274714180474899422092526188246643841919674645111625089855756750464059701813123216486378981291600069952191694289219629468552603706191299541424989319752953990132136699661971951149649766528915051947691081092112403096492189186281733746490550880148982524006688395744924010500791085116416163642837206106830881071813298878749496649027410736532884106752614046006238138351176541977658408525159095032645098078128965003928233674536467585667877061341449678652544642834061077551601898945667904644592410176319334452835160027731389281662095516055341747081364209858394672170198536934823984963058905842133995828899035581603318285396912821158335251602311124153795651884000434789054758829811514620697838759516146473955475573219193146346906194435481035636430803461315248790873872072930559181153998611912732705279123097232546161127904573861111919599250607479887774882523874642808877364415308017787835711997049717390770993169999452679984996407729833832886566479054639657679217593556008371138846750014920190636979225164030181605505717703378033584238490589226217974651414799834508382048310168727143592571547501650594191233906875190261277304022538899296696469099459046847414396275860536266017198307250235860110673591220931831732474901223771159400635400703701229497245942966930354967188174176815174848356358426183958965209483594164660214010075485106678067396891246821076507518673852489841609287304325590984694949216706795677125755201785087289994709483895851690518908195189498457107427386815171203300757064217871885887705387448126987536079456966505721006987517016991891131809528906675482604135700938080349025025981107584416585822449343346554047570818117940461706903582662360884248994238022743388385183942273151875101667502408495616208695861775475210698671066617494748359188772871532990232246644191515802301182939135672622804660977786853181626177050913791835164711403542184600874342684303174815618446645189565106309088696816168134928506488630845546626590864985512371911516629865702750175199826485814511651933777046916456792980873154603179890502880213847839121097849699000830632770385880022779550832620291665327143419487285552965263251822744673241070618138198784032333776283071324892487904000918780410346807879252302429579866081083552356861878100485897148153437741421656689335009474700112729634841877535385408922768327843610761509571270043342000411003656561701820503729419236399880798454083456221524351780393455885338401172403094879210083886966161413588372559388241595007992456445858375499224860985217118689728419737685496964605705292765255258287523006601094860347406598716075091447000050396490178826727343028032205257469141311424004190454534595791368914557725655987313830434033315265807563853663324437130802711518026516800272616659212451920401298558324203490980025500973990880379282151531712465772141857971033538219623934538723379694100331127111357085236946322519145735127277828820493293631112906420009415721201145037446365715224742587166918928002454077857387178910794135987790815593305155617097888191920791730513540587862902940694123474166160323963488767686092840523992697626643487379941038004785933013827761381156020687442244335039857993848507484617525566989497107377600956148389559920459510358881380633480148924394844901109906498799096027607151581196650071236945634571530203330165096183794149777922557010440490956792423017112558222320809034265322144724007130078690459889073653909152529912697699973652719399089301753559519666664431846931858652522119520597259234956254134642864470915985146578785667837093317342049444496118873880328002614674645787839648175521194907518153458246942151576869684691098368096541121748706308613027999348931536552553267247756890060461659990174818892276325756880248247162283600909158008673818557986819831178504463566357738941288639367633720506008648478513861503516655501097481919362572506032845447834704812852504189530067685041959627872895009472259417918752453619757558172999855554380442696853753055683019480209637817651835538806870798136282871255533311243790638631155748529477809241992329840189276431026066459298782275737374931216463366636277946138163841657488491594271478358400031130795809392667348955643518892436286582234515833101926205631665994986274001878899708102802261105184711922927046712173820115243453207786522340410704299581642981416220051753624600509853022423103973854106079991342623386649790385232171952224680488901254057097698929002585576025360045561832217892732138415463680068506813315457607637335624880929086508637742882364434976673711559442480723603235901950436661460702809424098580139135709864826806469321964637665585470087408320713074473172609862343031219377248407905598499846346095416493602065361515229275368222945413429889175745867789436733382800046009597928354875443968957003652372679111004771153584206867383911719311085227763998721485639659719972616665060116148570277635585867248499848928996898519701472102262207476931926827820545253160861703451506598165046992469751296215905216962790227345547548368443644479412331129813716416380615291345191184626851278235846417810666746372778931014058902886035185730257829838195182979272733509260580621591263276595403319438667387125232037760154215342836957912926823600519407173311052053847803872624870599676506676680621649985033865709525563016734117402902300422613688402893472400544893649908571464541271257356426983084290481993702832202309563100710806571278260799540394502011383546765700074295269717023753743135991123383764955400417579007087678085209235122131920998030786549734966639385654292886581745852299535533480957915302064359262424823303360789790986164554680529965345808031868306340404052635823299981230073098281024379634049410178841157171196004168793862295689306462905464893614914511511474772513024161092194338056353448654540009927911488352341282830922464160701106855455047868153123690030689452858403608658656876477920475167606618862957061429040710898011392231344469063323127233043788880249393370911051011151322157417448209485118651649317727857559727370631020784966827013101650856611757642128744008976879716444490933845523811367030853646021455873948474642336251865312943720928288809767261001911734212521263621513981209680226380892968458147517273176922818472743673178246193723958007740842883249614113109869933025647271435916595471056323237902675530654044774255837742830180810944217830740368337464921456572943328032282105280084316429442477230268004493713861655541071614279331076254862492461959030307180506584234915802471328247994947050352630932700667667804784316016271992939494782696322892066477952831265923454986059508479927147697100400378011212929058986527826166992619332519922838765031199898017286264376658558148684457542379322973375411622830673791815198013885215545575470161193233161100397057684300344945716125288901240218506298158147541457190893560703356693503424100140208123046717855406481746473806535540497905134724400824223687647008373388064398534310434164541478578708249064476506561707174924703888561661940738539799535074890066045317699143717083362819337988971017829513052441640419990501205576439530127968515650201213950506594455049623771560662897359946479827177569909461858615636243108255902601366768300677068708964729500681639481133169178357310237750206108922072714384736027401775313770653322608320589756497207504891866038733671644372160779948229234514389277599249546896333217190945768845854319159504453285829566406895026706067497528404270438489278567617567481209592908802845867669677619755413186361102090141573495174694025294975956219641383718455081950406044001633446075413652001813089909001875605625824158096156330521249855442012755766576860890556631791587495484571396146052020428495079308764494520746203554712202024157840707350431211812986490232281469395795916247100691338223611132445070942574697323198630481738199683217431946522134482795120859608014439019292305749191371063818270482233285336178810824265428094664990542053110603466635676849690080056187827059719065024826336887076519976565890538277813290457548685857519886145555485616738104060520120117858803134750290823574753714730304852244131486413288866321781965006192041764077224470594111943320664672827913820903327840005926688139162526108684321067025774670362097589572647107940101290393358589097021454283138134567981351273426741546328646430274023246947613081531963755455662733531742222513838165349343288460236812028672701570976661127548085669465075066294660224815902948636584057627299681350330401643815579471908289298729176059252331283879468715979523102450701452382359946127441698283978375045297877031499395295305112993699843241609287443295986335458934261141122930997819718084694183147377457340051173876148989750245569655716615856702018938014341124070283647969930737352268681150545292102557139954723615412872850273088863210744061916020470057833647770926986142977734977523426397517931005824435004366598085327022075625065140543499507361119237610374469238897373022926316110582141876643878713356350394181533232355893372165645884588286292140532457248524225007994665726039494303002089555619526480040815239505741089472631837572922047182107452264821690336157024856022989514808137315475041558315307143077047276596181398967873559555689424487210663746014266400465335537451779655645700505015788845998300774140440086290656310036934499642275384139598839394452582404423366834140127318429860576236118746744947172120482331189919747685753139010241160430265649710703156020289062141042850041720097967470193124897677906958718795817
0xD1898665...6df34AC33
0.705421160357694365 Eth
Nonce: 235
0.688338055357694365 Eth
Nonce: 236
0.017083105

Execution Trace

ThingFactory.launchStore( name=BLANK, symbol=BLNK, uri=https://us-central1-thing-1d2be.cloudfunctions.net/getThing?thingId= ) => ( item=0x6E1Df69043E9fC2b190B790989b8E02F974a3D91 )
  • Thing.60806040( )
    File 1 of 2: ThingFactory
    // File: openzeppelin-solidity/contracts/GSN/Context.sol
    
    pragma solidity ^0.5.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 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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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;
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/math/SafeMath.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/utils/Address.sol
    
    pragma solidity ^0.5.5;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * This test is non-exhaustive, and there may be false-negatives: during the
         * execution of a contract's constructor, its address will be reported as
         * not containing 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.
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
    
            // 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 != 0x0 && codehash != accountHash);
        }
    
        /**
         * @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");
        }
    }
    
    // File: openzeppelin-solidity/contracts/drafts/Counters.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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 {
            counter._value += 1;
        }
    
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    
    // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    
    
    
    /**
     * @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 function 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;
            }
    
            bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data);
            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);
            }
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Metadata.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Metadata.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // Optional mapping for token URIs
        mapping(uint256 => string) private _tokenURIs;
    
        /*
         *     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) public {
            _name = name;
            _symbol = symbol;
    
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        }
    
        /**
         * @dev Gets the token name.
         * @return string representing the token name
         */
        function name() external view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Gets the token symbol.
         * @return string representing the token symbol
         */
        function symbol() external view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @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 _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 {
            require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
            _tokenURIs[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);
    
            // Clear metadata (if any)
            if (bytes(_tokenURIs[tokenId]).length != 0) {
                delete _tokenURIs[tokenId];
            }
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    /**
     * @title Full ERC721 Token
     * @dev This implementation includes all the required and some optional functionality of the ERC721 standard
     * Moreover, it includes approve all functionality using operator terminology.
     *
     * See https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
        constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) {
            // solhint-disable-previous-line no-empty-blocks
        }
    }
    
    // File: openzeppelin-solidity/contracts/access/Roles.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @title Roles
     * @dev Library for managing addresses assigned to a Role.
     */
    library Roles {
        struct Role {
            mapping (address => bool) bearer;
        }
    
        /**
         * @dev Give an account access to this role.
         */
        function add(Role storage role, address account) internal {
            require(!has(role, account), "Roles: account already has role");
            role.bearer[account] = true;
        }
    
        /**
         * @dev Remove an account's access to this role.
         */
        function remove(Role storage role, address account) internal {
            require(has(role, account), "Roles: account does not have role");
            role.bearer[account] = false;
        }
    
        /**
         * @dev Check if an account has this role.
         * @return bool
         */
        function has(Role storage role, address account) internal view returns (bool) {
            require(account != address(0), "Roles: account is the zero address");
            return role.bearer[account];
        }
    }
    
    // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
    
    pragma solidity ^0.5.0;
    
    
    
    contract MinterRole is Context {
        using Roles for Roles.Role;
    
        event MinterAdded(address indexed account);
        event MinterRemoved(address indexed account);
    
        Roles.Role private _minters;
    
        constructor () internal {
            _addMinter(_msgSender());
        }
    
        modifier onlyMinter() {
            require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
            _;
        }
    
        function isMinter(address account) public view returns (bool) {
            return _minters.has(account);
        }
    
        function addMinter(address account) public onlyMinter {
            _addMinter(account);
        }
    
        function renounceMinter() public {
            _removeMinter(_msgSender());
        }
    
        function _addMinter(address account) internal {
            _minters.add(account);
            emit MinterAdded(account);
        }
    
        function _removeMinter(address account) internal {
            _minters.remove(account);
            emit MinterRemoved(account);
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721MetadataMintable.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    /**
     * @title ERC721MetadataMintable
     * @dev ERC721 minting logic with metadata.
     */
    contract ERC721MetadataMintable is ERC721, ERC721Metadata, MinterRole {
        /**
         * @dev Function to mint tokens.
         * @param to The address that will receive the minted tokens.
         * @param tokenId The token id to mint.
         * @param tokenURI The token URI of the minted token.
         * @return A boolean that indicates if the operation was successful.
         */
        function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) {
            _mint(to, tokenId);
            _setTokenURI(tokenId, tokenURI);
            return true;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Burnable.sol
    
    pragma solidity ^0.5.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);
        }
    }
    
    // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
    
    pragma solidity ^0.5.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.
     *
     * 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 {
            _owner = _msgSender();
            emit OwnershipTransferred(address(0), _owner);
        }
    
        /**
         * @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;
        }
    }
    
    // File: contracts/Strings.sol
    
    pragma solidity ^0.5.7;
    
    library Strings {
      // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
      function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
          bytes memory _ba = bytes(_a);
          bytes memory _bb = bytes(_b);
          bytes memory _bc = bytes(_c);
          bytes memory _bd = bytes(_d);
          bytes memory _be = bytes(_e);
          string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
          bytes memory babcde = bytes(abcde);
          uint k = 0;
          for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
          for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
          for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
          for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
          for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
          return string(babcde);
        }
    
        function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
            return strConcat(_a, _b, _c, _d, "");
        }
    
        function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
            return strConcat(_a, _b, _c, "", "");
        }
    
        function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
            return strConcat(_a, _b, "", "", "");
        }
    
        function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
            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);
        }
    }
    
    // File: contracts/Thing.sol
    
    pragma solidity ^0.5.7;
    
    
    
    
    
    
    
    
    
    contract Thing is ERC721Full, ERC721MetadataMintable, ERC721Burnable, Ownable {
      using SafeMath for uint256;
      using Strings for string;
      
      enum TokenState { Pending, ForSale, Sold, Transferred }
    
      struct Price {
        uint256 tokenId;
        uint256 price;
        string metaId;
        TokenState state;
      }
    
      mapping(uint256 => Price) public items;
    
      uint256 public id;
      string public baseUri;
      address payable public maker;
      address payable feeAddress;
    
      constructor(
        string memory name,
        string memory symbol,
        string memory uri,
        address payable fee,
        address payable creator
      ) ERC721Full(name, symbol) public {
        maker = creator;
        feeAddress = fee;
        baseUri = uri;
        id = 0;
        transferOwnership(creator);
        _addMinter(creator);
    
      }
    
      event ErrorOut(string error, uint256 tokenId);
      event BatchTransfered(string metaId, address[] recipients, uint256[] ids);
      event Minted(uint256 id, string metaId);
      event BatchBurned(string metaId, uint256[] ids);
      event BatchForSale(uint256[] ids, string metaId);
      event Bought(uint256 tokenId, string metaId, uint256 value);
      event Destroy();
    
      function tokenURI(uint256 _tokenId) public view returns (string memory) {
        return Strings.strConcat(
            baseUri,
            items[_tokenId].metaId
        );
      }
    
      function setTokenState(uint256[] memory ids, bool isEnabled) public onlyMinter {
        for (uint256 i = 0; i < ids.length; i++) {
          if(isEnabled == true){
            items[ids[i]].state = TokenState.ForSale;
          } else {
            items[ids[i]].state = TokenState.Pending;
          }
        }
         emit BatchForSale(ids, items[ids[0]].metaId);
      }
    
      function setTokenPrice(uint256[] memory ids, uint256 setPrice) public onlyMinter {
        for (uint256 i = 0; i < ids.length; i++) {
          items[ids[i]].price = setPrice;
        }
      }
    
      function mintbaseFee(uint256 amount) internal pure returns (uint256) {
        uint256 toOwner = SafeMath.mul(amount, 2);
    
        return SafeMath.div(toOwner, 100);
      }
    
      function buyThing(uint256 _tokenId) public payable returns (bool) {
    
        require(msg.value >= items[_tokenId].price, "Price issue");
        require(TokenState.ForSale == items[_tokenId].state, "No Sale");
    
        if(items[_tokenId].price >= 0) {
          uint256 fee = mintbaseFee(msg.value);
          uint256 withFee = SafeMath.sub(msg.value, fee);
    
          maker.transfer(withFee);
          feeAddress.transfer(fee);
        }
    
        _transferFrom(maker, msg.sender, _tokenId);
        items[_tokenId].state = TokenState.Sold;
    
        emit Bought(_tokenId, items[_tokenId].metaId, msg.value);
      }
    
      function destroyAndSend() public onlyOwner {
        emit Destroy();
        selfdestruct(maker);
      }
    
      function batchTransfer(address giver, address[] memory recipients, uint256[] memory values) public {
    
        for (uint256 i = 0; i < values.length; i++) {
          transferFrom(giver, recipients[i], values[i]);
         items[values[i]].state = TokenState.Transferred;
        }
        emit BatchTransfered(items[values[0]].metaId, recipients, values);
      }
    
      function batchMint(address to, uint256 amountToMint, string memory metaId, uint256 setPrice, bool isForSale) public onlyMinter {
    
        require(amountToMint <= 40, "Over 40");
    
        for (uint256 i = 0; i < amountToMint; i++) {
          id = id.add(1);
          items[id].price = setPrice;
          items[id].metaId = metaId;
          if(isForSale == true){
            items[id].state = TokenState.ForSale;
            
          } else {
            items[id].state = TokenState.Pending;
          }
          _mint(to, id);
          emit Minted(id, metaId);
        }
       
      }
    
      function batchBurn(uint256[] memory tokenIds) public onlyMinter {
        for (uint256 i = 0; i < tokenIds.length; i++) {
          _burn(tokenIds[i]);
        }
        emit BatchBurned(items[tokenIds[0]].metaId, tokenIds);
      }
    
      function tokensOfOwner(address owner) public view returns (uint256[] memory) {
        return _tokensOfOwner(owner);
      }
    }
    
    // File: contracts/ThingFactory.sol
    
    pragma solidity ^0.5.7;
    
    
    contract ThingFactory {
        address[] public addressList;
        address payable public mintbase;
    
        event StoreLaunch(
            address indexed store,
            string name,
            string symbol
        );
    
        constructor() public {
            mintbase = msg.sender;
        }
        
    
        function launchStore(
          string memory name,
          string memory symbol,
          string memory uri
        ) public returns (address item) {
            address newStore = address(new Thing(name, symbol, uri, mintbase, msg.sender));
            addressList.push(newStore);
            emit StoreLaunch(newStore, name, symbol);
            return newStore;
        }
    
        function getCount() public view returns (uint exchangeCount) {
            return addressList.length;
        }
    }

    File 2 of 2: Thing
    // File: openzeppelin-solidity/contracts/GSN/Context.sol
    
    pragma solidity ^0.5.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 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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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;
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/math/SafeMath.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/utils/Address.sol
    
    pragma solidity ^0.5.5;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * This test is non-exhaustive, and there may be false-negatives: during the
         * execution of a contract's constructor, its address will be reported as
         * not containing 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.
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
    
            // 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 != 0x0 && codehash != accountHash);
        }
    
        /**
         * @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");
        }
    }
    
    // File: openzeppelin-solidity/contracts/drafts/Counters.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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 {
            counter._value += 1;
        }
    
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    
    // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    
    
    
    /**
     * @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 function 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;
            }
    
            bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data);
            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);
            }
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    /**
     * @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;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Metadata.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Metadata.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // Optional mapping for token URIs
        mapping(uint256 => string) private _tokenURIs;
    
        /*
         *     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) public {
            _name = name;
            _symbol = symbol;
    
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        }
    
        /**
         * @dev Gets the token name.
         * @return string representing the token name
         */
        function name() external view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Gets the token symbol.
         * @return string representing the token symbol
         */
        function symbol() external view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @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 _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 {
            require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
            _tokenURIs[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);
    
            // Clear metadata (if any)
            if (bytes(_tokenURIs[tokenId]).length != 0) {
                delete _tokenURIs[tokenId];
            }
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    /**
     * @title Full ERC721 Token
     * @dev This implementation includes all the required and some optional functionality of the ERC721 standard
     * Moreover, it includes approve all functionality using operator terminology.
     *
     * See https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
        constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) {
            // solhint-disable-previous-line no-empty-blocks
        }
    }
    
    // File: openzeppelin-solidity/contracts/access/Roles.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @title Roles
     * @dev Library for managing addresses assigned to a Role.
     */
    library Roles {
        struct Role {
            mapping (address => bool) bearer;
        }
    
        /**
         * @dev Give an account access to this role.
         */
        function add(Role storage role, address account) internal {
            require(!has(role, account), "Roles: account already has role");
            role.bearer[account] = true;
        }
    
        /**
         * @dev Remove an account's access to this role.
         */
        function remove(Role storage role, address account) internal {
            require(has(role, account), "Roles: account does not have role");
            role.bearer[account] = false;
        }
    
        /**
         * @dev Check if an account has this role.
         * @return bool
         */
        function has(Role storage role, address account) internal view returns (bool) {
            require(account != address(0), "Roles: account is the zero address");
            return role.bearer[account];
        }
    }
    
    // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
    
    pragma solidity ^0.5.0;
    
    
    
    contract MinterRole is Context {
        using Roles for Roles.Role;
    
        event MinterAdded(address indexed account);
        event MinterRemoved(address indexed account);
    
        Roles.Role private _minters;
    
        constructor () internal {
            _addMinter(_msgSender());
        }
    
        modifier onlyMinter() {
            require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
            _;
        }
    
        function isMinter(address account) public view returns (bool) {
            return _minters.has(account);
        }
    
        function addMinter(address account) public onlyMinter {
            _addMinter(account);
        }
    
        function renounceMinter() public {
            _removeMinter(_msgSender());
        }
    
        function _addMinter(address account) internal {
            _minters.add(account);
            emit MinterAdded(account);
        }
    
        function _removeMinter(address account) internal {
            _minters.remove(account);
            emit MinterRemoved(account);
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721MetadataMintable.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    /**
     * @title ERC721MetadataMintable
     * @dev ERC721 minting logic with metadata.
     */
    contract ERC721MetadataMintable is ERC721, ERC721Metadata, MinterRole {
        /**
         * @dev Function to mint tokens.
         * @param to The address that will receive the minted tokens.
         * @param tokenId The token id to mint.
         * @param tokenURI The token URI of the minted token.
         * @return A boolean that indicates if the operation was successful.
         */
        function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) {
            _mint(to, tokenId);
            _setTokenURI(tokenId, tokenURI);
            return true;
        }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Burnable.sol
    
    pragma solidity ^0.5.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);
        }
    }
    
    // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
    
    pragma solidity ^0.5.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.
     *
     * 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 {
            _owner = _msgSender();
            emit OwnershipTransferred(address(0), _owner);
        }
    
        /**
         * @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;
        }
    }
    
    // File: contracts/Strings.sol
    
    pragma solidity ^0.5.7;
    
    library Strings {
      // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
      function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
          bytes memory _ba = bytes(_a);
          bytes memory _bb = bytes(_b);
          bytes memory _bc = bytes(_c);
          bytes memory _bd = bytes(_d);
          bytes memory _be = bytes(_e);
          string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
          bytes memory babcde = bytes(abcde);
          uint k = 0;
          for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
          for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
          for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
          for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
          for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
          return string(babcde);
        }
    
        function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
            return strConcat(_a, _b, _c, _d, "");
        }
    
        function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
            return strConcat(_a, _b, _c, "", "");
        }
    
        function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
            return strConcat(_a, _b, "", "", "");
        }
    
        function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
            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);
        }
    }
    
    // File: contracts/Thing.sol
    
    pragma solidity ^0.5.7;
    
    
    
    
    
    
    
    
    
    contract Thing is ERC721Full, ERC721MetadataMintable, ERC721Burnable, Ownable {
      using SafeMath for uint256;
      using Strings for string;
      
      enum TokenState { Pending, ForSale, Sold, Transferred }
    
      struct Price {
        uint256 tokenId;
        uint256 price;
        string metaId;
        TokenState state;
      }
    
      mapping(uint256 => Price) public items;
    
      uint256 public id;
      string public baseUri;
      address payable public maker;
      address payable feeAddress;
    
      constructor(
        string memory name,
        string memory symbol,
        string memory uri,
        address payable fee,
        address payable creator
      ) ERC721Full(name, symbol) public {
        maker = creator;
        feeAddress = fee;
        baseUri = uri;
        id = 0;
        transferOwnership(creator);
        _addMinter(creator);
    
      }
    
      event ErrorOut(string error, uint256 tokenId);
      event BatchTransfered(string metaId, address[] recipients, uint256[] ids);
      event Minted(uint256 id, string metaId);
      event BatchBurned(string metaId, uint256[] ids);
      event BatchForSale(uint256[] ids, string metaId);
      event Bought(uint256 tokenId, string metaId, uint256 value);
      event Destroy();
    
      function tokenURI(uint256 _tokenId) public view returns (string memory) {
        return Strings.strConcat(
            baseUri,
            items[_tokenId].metaId
        );
      }
    
      function setTokenState(uint256[] memory ids, bool isEnabled) public onlyMinter {
        for (uint256 i = 0; i < ids.length; i++) {
          if(isEnabled == true){
            items[ids[i]].state = TokenState.ForSale;
          } else {
            items[ids[i]].state = TokenState.Pending;
          }
        }
         emit BatchForSale(ids, items[ids[0]].metaId);
      }
    
      function setTokenPrice(uint256[] memory ids, uint256 setPrice) public onlyMinter {
        for (uint256 i = 0; i < ids.length; i++) {
          items[ids[i]].price = setPrice;
        }
      }
    
      function mintbaseFee(uint256 amount) internal pure returns (uint256) {
        uint256 toOwner = SafeMath.mul(amount, 2);
    
        return SafeMath.div(toOwner, 100);
      }
    
      function buyThing(uint256 _tokenId) public payable returns (bool) {
    
        require(msg.value >= items[_tokenId].price, "Price issue");
        require(TokenState.ForSale == items[_tokenId].state, "No Sale");
    
        if(items[_tokenId].price >= 0) {
          uint256 fee = mintbaseFee(msg.value);
          uint256 withFee = SafeMath.sub(msg.value, fee);
    
          maker.transfer(withFee);
          feeAddress.transfer(fee);
        }
    
        _transferFrom(maker, msg.sender, _tokenId);
        items[_tokenId].state = TokenState.Sold;
    
        emit Bought(_tokenId, items[_tokenId].metaId, msg.value);
      }
    
      function destroyAndSend() public onlyOwner {
        emit Destroy();
        selfdestruct(maker);
      }
    
      function batchTransfer(address giver, address[] memory recipients, uint256[] memory values) public {
    
        for (uint256 i = 0; i < values.length; i++) {
          transferFrom(giver, recipients[i], values[i]);
         items[values[i]].state = TokenState.Transferred;
        }
        emit BatchTransfered(items[values[0]].metaId, recipients, values);
      }
    
      function batchMint(address to, uint256 amountToMint, string memory metaId, uint256 setPrice, bool isForSale) public onlyMinter {
    
        require(amountToMint <= 40, "Over 40");
    
        for (uint256 i = 0; i < amountToMint; i++) {
          id = id.add(1);
          items[id].price = setPrice;
          items[id].metaId = metaId;
          if(isForSale == true){
            items[id].state = TokenState.ForSale;
            
          } else {
            items[id].state = TokenState.Pending;
          }
          _mint(to, id);
          emit Minted(id, metaId);
        }
       
      }
    
      function batchBurn(uint256[] memory tokenIds) public onlyMinter {
        for (uint256 i = 0; i < tokenIds.length; i++) {
          _burn(tokenIds[i]);
        }
        emit BatchBurned(items[tokenIds[0]].metaId, tokenIds);
      }
    
      function tokensOfOwner(address owner) public view returns (uint256[] memory) {
        return _tokensOfOwner(owner);
      }
    }