ETH Price: $2,576.58 (-3.39%)

Transaction Decoder

Block:
9399248 at Feb-01-2020 10:31:44 PM +UTC
Transaction Fee:
0.0114866 ETH $29.60
Gas Used:
2,297,320 Gas / 5 Gwei

Account State Difference:

  Address   Before After State Difference Code
(zhizhu.top)
1,125.354404742001727521 Eth1,125.365891342001727521 Eth0.0114866
0xD1898665...6df34AC33
0.509650156818268194 Eth
Nonce: 133
0.498163556818268194 Eth
Nonce: 134
0.0114866
0xef944e2A...E15001176
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 65267030757227565528866848156437914569821038448126372139344058892862406461976455499626640805228232750430786284503578330725134135415163180136509947454231616935308957876325202912844980212711877539821639209991486511814572758419512169520465351938238688468603531634614682100804672545836931531059789822986030173787362751333082874914202250120229834940488734279883281240884434262290786353835614880436218763253828722815630040938905092256111531602580228611752459409718687813346948654189845494681492625931342843220465039045987158596274849492118874875427050082681405928969953546710384917411181895325973887365154059897393833554817099014231362826347528733922358060492306778565124739620749764669558324941114210699449660745739338537359579264130031205506856848615085401571772538820753249853487127171500352927443912200004187423750201187601010032717534942619575894460940483798705645451574787885688112406720244233766321250974050869290899062269806221622279202718716370514892961404555093046001083439647162839530183850490781348143114241836985092679636118220771254349245692036293269645117290127874542512224907832929617290477267346105109501540667794213864605793631554776350510118725887842980814704287096302036224129010951590480714537391569083613255159482329323583912305018444776853989358113658860498970691599309471298378147213593400409860456008848655574556498447173523232981508200820332782333190541457130792309678029543841991271239147919719147465580245997318948862856978850077165673395368557438501244258415428599422323103791071143735286442072088618185794711080385605747832527145259626761213499112282392963734859986004038687584968694859639049823603492238170312123674944192635523385119785987353757278772636289816602023432300753793467462265564968886872698336744393500524758974829754991155720963894124386254243467666555617276272042185507970446921602703097505170054726425969346282995023896636621538702188425814150086206396848081795779830010680453245309814396213601825766330737048674557107965458736540495873517853856986032532230562398663871972215867901928841890752864428415449261158172633213847490593212996310861847859072592635993244932046718482011078354932183105700968757609848147726132135226919179069166914196666251814093617169361092693191069912745898596447680309578180274295213094054497367970907394388382654345941559946986138431634318356345377642345124939955135686450981747856394054241910472042180076722535339253010472841355432639299920922477633738264854663276645861699171399871336663821031163800167868509155378505111341869272579760640106728285892120070899224944293644430002380547343729545035809530135999719358685099454184899774796996436361150701767368791847012398543904035212766409957287787921057919698865558039306336302151143894643866485197441355807269269993699378671673981835975795119413576787887533451908240240263957693500120976191623035310641925701512730880231389490905727009153323356376580605056201390987860438780244332506620006505362808092568157735454756298293055587140404997387516301182948493276965539893002637383457563025772112265154297729777427272286455209743071196772440817412529332744144727540024925780989488755640835521798278519844201007307361613544177813348643367447174935594603070597933929593649728210690756076890558240613119450659411309667163676008978457563563577006211731143166641598317175753753151158257812080103089874588643829742113586484927279408320808718813919479662364242059293869870314254583991231905276240262390909229878538132366214356506661493352245382792264616796044084376836135755550498481843879650386381958472338891957120264213198679388932331554785224034013301715231878172507033049145681579012602176584981249253504403111872514670792171601057459939729774456068948333420734424182382495516661185349457783855402914524195825639678293416685917331661769320974679370163529199770136045170447082347381922761570733066385247509075889476386831593305383510065777895169823133177779375538165982235753483420320044791952495294886773919413525845481092518732315086119250989874625742127106500232725842309213401835017424892231894720653786078463452583317425914141402866615147608849238253402987850818638229700586383921355458743477813459595893680840626523708487602662381727134737133796385572468223329295907370454139844238626253156555153753491788263859909136670571740081910766537870747342484938402374512751366170425069778720014066333915326866091308767012111869771560795999024241372377851631137832608384048449995963000081712457115790648003344289929156034451382920437713478844446879991139887019089246867642952225283801711017035699079049317869561729537191937229921016659010979889958544000081309113173690515264440245754007818394217589565770631884482872111441077365773480804745372321657124536143020553547146516490870102108184650231321281754790215780848164962960945406249659568645656963499715976991248693366814690030263709352294418613772800514017935199504636260420776290528279894424379448676455975012162424265320657136652406141996134468725116148821682427763852211412933029101242088466001776140193537472211865914531116380596719146387215096033699040901662289103928699533390619391497704180908963414825968983337479457597747638413190615918124723259543655555573242631538992352043026020517153822734562155600105261858062077907214582313749034716451626493775471033748995694945199701715664794762882028649285139860451111240778915986581142254393569557439301965234080509794869164695651748948376327263412334727237834989256660096729057245140897375213055377904223002296840391216701979232412150440826632558547050556639422141179001537479219659826994712156429823010309885616739872431876010426738768109774156844338564043477881490053840972317529536548631900515510967412496425871121148577210029878002536685926049049903840404947742709245243945085349880906819001325977304881026504220017384439352646647223407414900346345582140030062307154290499941813068361066832261694580071356383540607399856064904268989500197895453223062404665282793610299378127059490086985725656411076706175986674249426286534546404877469567856266538589366437625936583182256790528500367263121187789439968696759533189117032846542539442214715967052723908059821751827471829504508242806690241991778000581220672885388370349126029481941200045977986841197409462880527912943254503413129424430887115116518704770277012380128327617955073709825761945350529553626490821230525087239737854783724466361949748480382365215859054190794578424289265894594707409986886632951715338503213528297023970045276351379857623258991805476870362018674321236660400850589366163416239210170437387743743639056608226718585419982579146632664887236486441964647809860883358200946992288202308118840678266952305510285316935790231599891809222034090744420581592310082800983180798511621923643187205863380945120103212154092971601059332125055497367516122189621519005657179742177680749097087310929514870205997239841681417436071076671956822636620854470534129164266085880679908396236776361342430650351055158249497393446997919804466259948202704725098343186669241725437704876194589931679415512840921458883242372396354343505238012154948344683529541011420668912806298606852364949805234569886101168972297350605108766830838111862652535802534046678701772119270607117425765573210008532913816075539540790244601032992347752042844095941032368091539152382405931910215965744432755666485779400760215105581279385777947660178047476525783307183636729681553144969521529396071702982665174759625636979533642343379743094429813327828997501989272800709656851645644004992711084103207791583670890259096752087730033193570982626077442419041918776359854272987773255206586103533204151853896805313151533869258221929541111922130530551024593137097681334991030823985718508673064494793978254950697082501422885249851984159855160930304358511715175484336761162972495118061455041297559709345311515840341702390357538402623678591175756919327893255963738262546001415245788738617593782699349755301752935383473091881414505295500429459494296314813554309644898495657551523210567046749007079868082304338895879406152933276060101691713950870680664947587460253552167733961525922734769540701206213207097471406251136384023641573081793455953779986411886364862551160375653979875329954216763051127866947926545099967506399547103932730824263686591634388539062009761453241902361714765881860832583208219575320119415194017202136933709383260458243825138010073279257668281699763538423793710044780515327006103179880130979869994323115321121216862225815958971907900773681632656890883047362074562938767507714720969429512016250526665391428030067623766248533676212642456322618332045547156292149913754175717356983827679826299193418494090693224926412382986907986429328498038166519971228432356895752537263355324499242333137479320747708264555991471229915938870947342303914107606305924331375750823241174099404271874670358004913825336264430675420516436411205521813890737604650956019769153630928365650798415771399151995218491545080073094597303319368791413582147491265616976454740598851278488484281897989841771035176202770567988345316443235094718920999392368178214212107151289291323766266708691151141285647417790093055462919434385232199801635886660184779738616523538650552195746013594878068696313890855649960438077918274599842881281943928965049566915946504911218619171663481157464080340110493108403692694172599650036150502881384136193932649871056018382378659975973051766959844693183234755883536825653570984835729855410773191096019183530187019113273554921503897038825927207193580717079144281096954529397963393014611519458735578085055060624697065856676963698579687945451004930005793010073526544351167864424843584082223785726256026202572286009737266317898751060635902057261907660814997183861409405009863003705915418669829678399966300682772257116734873531353719354366170763148947907122286232698992025895872079181195835124010821770196728862446008816700935603721717623123044895315912694405367548253102084351839846139497207676943537938096469757333653131547856081752641866406317561230522746112436377406381966181251072755841213443914361395912890453873349420508395409401505150897475609131621772216827337317506283303869472470060106287248719800567531239622215378687904596729578745705842570231994003780148930857937748142690116031579761975129264580433499144975157307182514902399734670095284555296001791418401963131822476456158242195691855638686852770771935674961018954377841993548670709505210168178053210425493943173175888360902525606079137180684415017427711195700193452435946779027463191156805212855918111761691522780961722078378277621807262170671395771115892342446187960712146272506487949143744096747762455264328557054364191601342527102595707745225684283983719375226073774775046081804758221799391526452843926668395708897107994062787474050752940972677033181712316548825177611672881637320280813106283781529730818956902628674866081655815167955854110804197324348794567072248057910521730703813215881073954677827317774258340467130405684346263920073950093951528852766728125526832364734966710257354002651721416067610314070721889455050941675688088838024075907604241967356307241353291656435741578596730582676956877181400269428245270674513065578028949222276004045259230845936891973549617375598831563472020895728041822325696266782862352340588946231368061692388529288545313373100720611087928641717102715481734246256989743013063730284041199611070116874390356797625322665001281095684609652635802122129363426056575845539178036262187292594288601878740107779143714494627053851730397204225291763305869851303070974518021807167441156460608506245914986495391889675751631220311760538709000385821825058973500625076068643994281595611046382380116129245977236072361642822390471724787402698635551919941196953898331787008599141504010536147467693798844276593998426144330789179743492801325714474721249146810448189373960576832730766667029684876919320051541061960712738227994581875383890328451586446390293120178608773354982305730457003926614575002840600933769585327051084933387411163408784853980391615857623510699387452947321170448145301209954073322246155886498092967367975672143927132909760643227283476955476162878993611084149945735102070240767215271779704138748367253912854057817619182852891901072464274175443501117061437876866489847051589288786428437883942050591619300247852139254528681008440522812697722252203925458811325701350402525892953636582177648625083632462394977156664139479163217555496131843221266166872570754526334873911896681224269284626671590726782416135328893827096076107751202270621951956185507294770805043885683629538168514320245238355650696675359888209709289022922668213454549537535656958250911807812798804814983686058434538073719138596970353179796646950852918995341892355408782902933323030434209163444151226417782701904503550103843118431556506230925469805890833350087657506171252886244005915985628679988770458853971342099675513211785694110706318848663176696239595442457714753209275126123938604764146493877645163426486702455386321671836523102330297524614941505406184329085342487523014195824959455014008599084589635495653076684078866357782793471568799855387312889928270684962269243715086674858760763704227814634199949900719333073128047794042249856477663174131882687823822407215436884775526139740046428561884258862721314065977679505488123339543782790584313314465419978557856633639738159131872830689151414482606758716304454247831845600172372916919896893627342245693226707288040902780974112417019844403186804938129259131149437699298199033062906367610623391537690172487588959340430475154137474767816161808240761492204091975232776275055797513630922458093432004668578156265976384560962071056390515128756709738420378617196607487554831306126998373269020360467127810616524480719145043994455089101521333061775590059584101954411703963338092940348249475834242778895013427386406803429964978682217810420209536817841422795548969392737390418735290656348087260372987944144510108677202498156968403739721073640113359521518039983548174766961984386444940170618834409769455577877733568573535630080845848228632354113467940799325144474936201888761265465506199048593609622935501395836089604664839375597614136435971269162872630994679189244589702962415945404947835202350352981163805861427660892468943328435662052668282041780763157504311588698142996720921275910420472209494174037255426717456391405648413116531135264736861761092953805065006092827867533919056498588206309631156200004057641080454246360397345531066498175810842698748987402977588686673447155255760408669414333735141038713131184866332218289687698059205589418856181354546052865475922171058915193705159528555423046679765000142229137448322147352391498928392652233106193157095247588287666411935827228318928723943828694277191288330771745347570751534636884708891597968214994334989048387473340501343941269994962007306990032414392883984537931772302556911861367793090940031969856822751538649362343933701915286016693259324259966972920518696012078831587060452521204816787905694521746517789734249227256996795327798422571701922067898037345678096855858088706028293859257803256997784548632636864221677220610864724730435067147566632891062205475191557176573336917316487181135612364090207262445178668801440311911796758950538446712785620916985479952460938401539944219061288647212600133535921144981671201109459145151057542169754873711828849295638101899492589157629582711341466288706115862926125653355160402523924433390837145381046612949681593709048743519115051982823071117459948920086845573537551999685430115293859491763443205032561364478042130158488593633982513139265200229350110947855607631649678048394596743936542200396542934150268296038111410946063205803322277647808113952484439468129935416438863428488430031862257416851646198591221386238643323216938690121303649663610109878012452839468126388771211273226428759548030215461658555657234281736014991049428640228426158227124974306623813357837841703384540790244605497935718993216978768516810907657298023159351311179679483308755161515188495631629395453355861282093284026362488409029739457660655080287571903038089688872748314296162466876034215323840955958589201243214189010699608867729892719728572134073185651854731674536366468306894828703837425676903340929332777400083040072418220129287733309010280335996813688247078817763308668845250364559142088494154877064205447122605307069158666771337655709860044876944714193773098192722725681927150727937209795331315218032605524303036639239638001856677076292184324129906830617366146734808900929637757425600670732112248904577437975476859607370290243915123854896370748954417121596576452678526945254603115382523118492482528525503285288419777164816716653304326441929455195752285753626680977674666305802402990933110187527913992104667151254344885763580478555982346508880239681341858736917834070702996200126373676365641068293608504680262938015133029249434935146685440694589823110871040115477413135219515635924443886588743858218870610325142033254301354025006725231765668780662483610656204030600188084301983685774148244128535429551267242127661877814266425047010110394458069018158806822869580790703372422386924900371813705742322703514509641450582157682830992885451702340412352310753388276112862936522216709246867534499888235077862551019714140816535392601522221208248617831509885224379163509250923380001022830452198508958661497334316911000277353126818104104289495996744276503763376597163177551132608177642207490925276656975385570541632150560400731252848171320975413038064871248848588624873651402727363048454118152074030060045286475969293719002586090671100595170699517815459597759651846029591360565471749497913225408695413386196879040541701005106723764317295781826802348725532761345713124613725665270526178059634678027508682240248955670586308337402403962654071493306423498248815647040639118577912939091746562781612210390442942836747017406341721167796622375949051454680689463189490034310746524252367405103115906524057200365115360578089258298448612423878300224918287122847488579082156004271911608596738324149472871943136389710796571093120256950364599458011290739818326954250462246444287535972971457815167688446999221637163907628286889794682519949516378889373641679564287087982334092211124027982565014229335108782618648420114421857821262829746690711571713586588345373353824454632359239345675183501428946884614921927268901919361466073111344000083971460572150184172478435806397914253747098344598503614499615625922371035118909422531132841007972879522317666665060970532074258096711491773718654799374068389983203105855600104031720833696344254825838877585333789154941580549928271888091874986275195405503225536757426107062478850180893415024927627083159069583709339598849450684307782574570389212224736790248596162842352525115186605385337814657211098612132397470545798669203336495902246314668105617676798065343028959935389524888618205699121291584852998213879822505444316653908821912126299129607820608866533622182778401634547705016189577274150294520754749144816444908760540451712383203126946433446265814283127086968997939623259527404146153775815216699739807390979327237991153683434797119558694850161112028151936244115150739473779257835307119911440386806964213238211019691306376280065112186634082297667961854218402719557767109927444448312511053649031293498340369874631024328435931625578613259414412098432784857612634375461069137287144208410112235902816916360141692158029261050677467536309499780823094441714660045055142360903863008130554145666348255190475233873368114064126534054612208677685423374299260418573316972441457377830248625578607064196773272660885973406285501342347861845791842356443133403314268221867918564716163938168577263135409038974614198414676760436769329516828252543084593657948548092038171762659704455443639971108163329262084944703537222514811090545952304769804355468564254148807803044629658665402553299114746656764734982665459997475590085843766388762364111222420746882457520282397950047327581912926750682027156007574232550029168431166188721540537509263183658702074352971895690969403365353581191657196655528499480311274086788998877447823684873467694876555144956181476434813186969792151806588260101681150999665949638683688938285816653839275357824202973121242007330172699260803187745639424850325027578026293205982222500407927773292781941681938579615127840249457996522319259726635061087303181642940918507092736980041251820066774761917309715317302660425661230794606571408938797514345396321968687182325390961522276477759680789686543521651613674294586486886024490027365620189509643394418222312857133281346220525255986632541784676697252121538386822625067226462207606879756241208833356791218626795948656132554929461268436472221919995721080181430687149736987528007480102420028256242046289574756097698675966688067053374591922641519271757537489969382237127729892494076176873479107094952304529470274293820241624624455533893870999904399206676531658569620521475272995575097326007895306156987382190912153135579807999949576355782590411783124074706153586316781430948129739099440661575160179373884171962305535773408378160301923487556724007447382726488061832122916162276328366748018665475995655536339061220967835831040864647484165843043951940966111101296489635394815059606974673611097053536629154499814326910322649896161247571394635827892988478981812369654207681636628993324936361287475778891461493622375746348063173604057850425728351674760738443436463196851052714714688412386642429468302776087314458432733139857259423555594502953363088931050546298467744114913329394479578113948673905622409291974813026322221581160873741299573738636204378295592327016052145653032886494638572453062270249870234872265839974413957224253355914523931982953484992049055231365110036781060724748987774838403474947628818681266620690014305539771232290272969864867986474020315727132161965423164720154125560595492966556490810598191242101484240427140000906238405789724290857659395749224933947978658697386108430158895512173276238278110751539197070465739264834971744460408963269541556286127890758002410575825436697218906657841874402846790594486064055052336994713523931810885547975305208394397709385761864035348140882725540460251635827527452634016344465973659320067433898130632247671597900870792247523038796351163176829507049870660524438002288890909724198502790648884358633084296776591495807350430087808070723279196861310259186606404161767249127867792171056073546778668706143918537985361366519185404026940971426282953726056476277870328650859283798685040656763939652329625556730005704955035895288587410330857822751515168576634930

Execution Trace

MintableOwnableToken.60806040( )
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 aplied to your functions to restrict their use to
 * the owner.
 */
contract Ownable {
    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 = msg.sender;
        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 msg.sender == _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;
    }
}

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

contract SignerRole {
    using Roles for Roles.Role;

    event SignerAdded(address indexed account);
    event SignerRemoved(address indexed account);

    Roles.Role private _signers;

    constructor () internal {
        _addSigner(msg.sender);
    }

    modifier onlySigner() {
        require(isSigner(msg.sender), "SignerRole: caller does not have the Signer role");
        _;
    }

    function isSigner(address account) public view returns (bool) {
        return _signers.has(account);
    }

    function addSigner(address account) public onlySigner {
        _addSigner(account);
    }

    function renounceSigner() public {
        _removeSigner(msg.sender);
    }

    function _addSigner(address account) internal {
        _signers.add(account);
        emit SignerAdded(account);
    }

    function _removeSigner(address account) internal {
        _signers.remove(account);
        emit SignerRemoved(account);
    }
}

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * [EIP](https://eips.ethereum.org/EIPS/eip-165).
 *
 * 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
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

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

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

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

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


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

/**
 * @title 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 `safeTransfer`. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.
     * Note: the ERC721 contract address is always the message sender.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

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

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        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-solidity/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) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        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) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

/**
 * @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.
     *
     * > 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.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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);
    }
}

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

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

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

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

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

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721 is 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)')) == 0xe985e9c
     *     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(msg.sender == owner || isApprovedForAll(owner, msg.sender),
            "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 != msg.sender, "ERC721: approve to caller");

        _operatorApprovals[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, 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(msg.sender, 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 `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 `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) public {
        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 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(uint256) 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 `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(msg.sender, 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);
        }
    }
}

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

/**
 * @title ERC721 Burnable Token
 * @dev ERC721 Token that can be irreversibly burned (destroyed).
 */
contract ERC721Burnable is 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(msg.sender, tokenId), "ERC721Burnable: caller is not owner nor approved");
        _burn(tokenId);
    }
}

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

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

/**
 * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
contract ERC721Enumerable is 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 _burn(uint256) 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;
    }
}

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

    // Token symbol
    string public symbol;

    //Token URI prefix
    string public tokenURIPrefix;

    // 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, string memory _tokenURIPrefix) public {
        name = _name;
        symbol = _symbol;
        tokenURIPrefix = _tokenURIPrefix;

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

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

    /**
     * @dev Returns an URI for a given token ID.
     * Throws if the token ID does not exist. May return an empty string.
     * @param tokenId uint256 ID of the token to query
     */
    function tokenURI(uint256 tokenId) external view returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        return strConcat(tokenURIPrefix, _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];
        }
    }

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

/**
 * @title MintableOwnableToken
 * @dev only owner can mint token.
 */
contract MintableOwnableToken is Ownable, ERC721, IERC721Metadata, ERC721Burnable, ERC721Base, SignerRole {

    event Create(address indexed creator, string name, string symbol);

    constructor (string memory name, string memory symbol, string memory tokenURIPrefix, address signer) public ERC721Base(name, symbol, tokenURIPrefix) {
        emit Create(msg.sender, name, symbol);
        _addSigner(signer);
    }

    function mint(uint256 tokenId, uint8 v, bytes32 r, bytes32 s, string memory tokenURI) onlyOwner public {
        require(isSigner(ecrecover(keccak256(abi.encodePacked(tokenId)), v, r, s)), "signer should sign tokenId");
        _mint(msg.sender, tokenId);
        _setTokenURI(tokenId, tokenURI);
    }

    function addSigner(address account) public onlyOwner {
        _addSigner(account);
    }

    function removeSigner(address account) public onlyOwner {
        _removeSigner(account);
    }

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