ETH Price: $1,893.34 (-1.86%)

Transaction Decoder

Block:
11020730 at Oct-09-2020 10:38:54 AM +UTC
Transaction Fee:
0.34613628 ETH $655.35
Gas Used:
2,884,469 Gas / 120 Gwei

Emitted Events:

5 Mooniswap.OwnershipTransferred( previousOwner=0x00000000...000000000, newOwner=[Receiver] MooniFactory )
6 Mooniswap.OwnershipTransferred( previousOwner=[Receiver] MooniFactory, newOwner=0x68a17B58...3A46De6b5 )
7 MooniFactory.Deployed( mooniswap=Mooniswap, token1=0x00000000...000000000, token2=VotingToken )

Account State Difference:

  Address   Before After State Difference Code
0x3Ed2654C...9D369c027
49.89024787537762405 Eth
Nonce: 378
49.54411159537762405 Eth
Nonce: 379
0.34613628
(Spark Pool)
21.685018705975877847 Eth22.031154985975877847 Eth0.34613628
0x71CD6666...D3ee7D303
0xAa5Bac68...4a2984ae5
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 271356427519541413846999962730279820740308448786030201675242734670340554316814477625843920761890920665752589633539320418804348954670096864276493207693415459794655784105467231129459858979486073878055646006908446717922983055050511250179162256942107713701500347931636816560539487996396029661835739162323074280874835292120209660266914789638428990593359217663479415351915621508937710572531728279587699374460534437305437169894461120245293366363960546247203977393347828312270657468570715852216110796604889326609441199314804233696499523679727807386487235111055421829631812269436150657303708871500856162305191022335979097408082653096415739001400255494959705682191230283672951655205610670885097857977401269204082596763662171537576762440719508918115396393080876540928452798594113497960523555148058914315579716239230112359380696461600740756934911249147523867598205742199271169492688973166504464957907310490599537046134353261526555332104555950516744718003290986953457310557234797284764645409726711286740825419746193040519960170505315924799294334521398579594975424744173440746089629027782190493066911253467854855700707266049324048768411274423430957016848568855086052889911713343380652215552652605874423260609566160303413114679189791249294087209716535736511110766687043689698643062532432336211618285949712303264446269607234077466083920986878341223071874184626272023752276844130927214758986744362158289423279587070548594677140008356566224608113987373196665387098167253780853485185803490841332217841202149941220018964624574825617718901293665379441006844354406111040571443988788899144628627080330224842910878177153673986517431971646547366929872038416981790989683998961859470379644533880177297922145431698679887781966219812525448237634859171659214889258962623231383577425752235879603788588217550499676258673079374022778397147752164271486941205029126569018726034359148088228038320325856547092912884752295596065855081390011879990084240533768559722520241256216873941063436833321778749568083146212353682705902810492830968040788681102360880645326065287908111211642677262338181108059931017546824193826424515177521421096581829230781822270306436384937231107387554827567897548280581854729029982527772249962911206673677623994265611220514185475120244994313189173303631358886590368707057415363016125250246181808601664112986873487298096814872260379229256687216517398727093472711756151016066002898821909168821718825139241582226730261733514235641826617038756444985632969280437772160576799797539178338867719426849266993335466562149049205461240013985533710632816026266743158936634176416248563619040792832274040960279774866189856125709232990810241239880933486890628558154780032699397758891791256300031388103825312866681292720879373664309494618810755149817461410215861758789438654210344473787119049150955514557879046100585417750273377983246947242739051438817803069652230288269098834539768234812180126911661886530160384662511428060186041591277813718716529475636273203301564732808311021186140596108303038900124657580255809132750453330939363454185722466097542487564643810916619673713804347615152471089454990361393705041178898690700416322676259714725695186602171210979454793401728281302782393936911122221081964378792004226022438085049796307694527704842626329163088605196544954213525372981259891206493713510564098154836973786688938947728913689608957002518331418462050300792891882978361255829994769306555444900726046227584705488966159051871983469952523973596013801786194243069822806486112179796897985942475693962201755856036526160275212349661725692495044398213178596877482589949672535687111685829163757569042253107511006219843186831721134892623345557653912353747368043287580611614265301886982396259755297499540997590096777218816858136416497836159738228221429041631637399941085075901693185771335920759010419502479804657382870665974959299663528316462626210781857683896518457913538162892999329560831174054575866165201466366315073072501270597122507431687392975335280816686163143614765367225859481368856031574401213700017559030933311121855092713222725140084823133379213171232952352795534853571207908686934871645374088517525490600046556587473413706880761546081486035879502321888701643782643548861145875005771324489988716895878328717291057962021619057043786329443720600272886741578479721095805124431892174123785496801098988493755304853464824712203849720322884422752591027732166588655560935017123849404358628685481984069732314019720389839770863829358451725765892902870013877983832939584213328049810379331792900907665952043185720157410509789751291231988361687150696987165620756916046852895378922449233244163942166064775061036816627374547629101441246449488339768930063716444674407844811532831173732527571893556709474696713946355897375596653545384487171854342724606528270169725187454230486329441852937993540932927142199590799763246688810163378641000098675355754848802304050570958760973609255993053670970612701863107354865507282468366451695273262540472876949145552584961295952289878655414428498867399074133302487400515893523065710785007724905890094588845625820044945282030102545885075993112597780916544321638236682303736536289648500391799612052148046553590505751691303658215403308549801282358867654209744615419467109456616019489267419258885122949822266474264816592728237349624952937366855586822297966557245563917239084590197336496950265492080228671816531461464120334607455798742323136389168225332855220063022198189613896434133606677643501918303386324004345682407470301793825771811742743193100878514223774364991475130825779999619375117162454027769319026683732330001645466113337276535896465894958874926189847703350019361851206518677487486654370536114836076111842201133681310425789443059378119158401062501422799113279401344440709200873405145517538393754619572543654838262258138704829191771868347155823055465502644012324054341519919061409214381963653871565706505486489862962512392729357473441154611435984997476353761829175899691668800424222431120599789308354906326103839988379054931030866764975258824072701623457228237837453442173021190296011907073910289969920920177476091802965742647791744288321661820985140274784253922419316392690062206881473956457503724420749035404176718877461805200999327403018169043463703772644881304103317283349177058679976635667380074979761118262079995798677045587668860791443953402802297852058487656782806676743238130721143098476747079051889221656927129419298939016015607390390152513605031035677048617084641054797740825816290071863713190429608017679829464132733647261802229464534326649185166042368585553317317161899541132002489210419403101378523761580566530537890161044545416639384197018739873785771030320349253192195407751027067535858915640756282067724438645828326765136782895750259827124635642213418231793085815725521437363899877145571489457095991733854656694052699053602119080166212825966673411903844295156463814044500956861636213432291755790751106075393431403708824906230358604985201613222452575364018506981176491983403644652376866321135651532432476501215709271535743268714549514613254216434700750477523590295103521132157409717899540075393446122959176015892240635464484155596924827336968008020364821900066024649261963507437279107299222837255382637484849252292979031498130970363327735767255161893588814210428848142922263637047194258290477559265064949642584390700832725612092240301789653693100837396028496058408097930422701969607791049869411616844293397791094323111922818326248802017392275001061170524821134980995081132241050762552153372888035393760249281494152531128468139254961342006614513538920092869000013603109242017405396052591346814218755106606375997212215028269186319897686032272234567414727565750321938282953858345444508677725230709362034106027460226200395209282125331423200101615171267658857089315267092106768641059461543980601360348378640231637691367065304965970670411665094513561705139754586139576721664560097239196885020165181530060119501611147119855507351680678988234159957261550326766364008269419922325964566624865593571693594602639748020592513885787370879445418717271243593927534555844458193358904818991494346210529668023181945508214963321973297822862302319128223246734760792185242425628744502006900262337390021031614367772319801997878166530963613458152003985723068817203693667456824687455996859108124163918444487406726405421303358645072634922875067574875376039949963251773313667128818102378470004059016545085128422189809694938395923102437082033985377452826056641095325678368834569938602194487152059468947666299449713707388658740959449905855842433761530499395170884251523411945909088232872302308180274462946461960386117605088557047567763648668388313469624733563191250143577545805151808361016696697965738624814488981582538117059413831377111405173771666588020822156610262010056993208786054571299878523078349677596093350934293346012475727586427873974555624057216277632221630745511426727594851023451603712371862878478930799128653988290070551207593200880521604016540049526559307850206629414851081401016458591553341680506240297705825997735891547450632841443003761927661390660457797845371495549605795776747010198267515431491652096364813623936269250242386904907410990884741772135466853043460167889397736995338257496868569984267669160014244883071716550021475158403083951617195635702867158149740490568549566619603411801234453026459268192419650103173246455518294529409274662211040092306217208098871165819559271710873151391345056144904147122094536790983093280487920698651365337926623471721680173463846728433063332780653610512206924453558468960876122799646740093067588361364722790525823483405746384850209167048238669798624219548534244672612130162468904167206823269190002946167636324766904177853976777507944915851795403535805916053152598746087886654967078382537847525382943601371009501565682540017075641333554207691110722336910203093840521160229028514290385851875328936009270245078212725580500421801293976821045081197841632867100564852782176028731582687569874517507943801080982550950524184925754397325568566501013622617388533358290255070406778344695415950864048221678969307945279213179021959325480897412845054259575486246724673323783144443712113415433287848411506100041329668100990611238907100990669989826848933516240598051947475641221934305629630697724563739938715062671462279227050863112681236747878926775964570292971713034569813815694310575009758831674307813970663540672489798795714649893487046463499015047966106920770575248412414367043223906691520334375375442235807254554140133618611729473987599067160783956979082847367489975770283933831099839815828252569872963106484785530354805818122107775359623375568554436732633143187345503322189965915367415722782617128638921335213557261611452417790671761503395547461043696788224129109613392718322502898581451042194132393545062500879086515945589903468059860243584749951293786480792443930383829564808632735469511261796439728826591645726338755463226568344577024905521370407607988899622792150951220557277738643000221970777786057241625110336796744757994904343663434750953181547148201259074714024904332454393729596424224449725460685941313087165619818117486428456031200843067130643004541468223865329515902095373707560093379142743334343188756179146523660695465443268602384696993511099251462286694845497489250296547255817847474382692979873589552247750996468651652183921454545944278661343377275662266414368719040920544860410298637658276266668793339846773775796642939840674897164316389414172060079786452187695256725841757629548385831569047855187482963083741293760578162669379101808687717853635825090975572971710787625532130932935447796772180728201648143265969945047766290416678964932719622534328648065647751431562826170677350075146549449448641509380496919703711230218227212862413085745279633881845288017475270010893176091188832995392399256815519792152830562378017099909801781937102506511363361106305312346299443787857555463417112241458074176237073675004965904603777070217636849073960132717905796748629545076904401309911693161328712185004122351486625074243524293998102859984538498754024461321273213166584110007175150924599329278242092638680176762616547899904254679959562643669161523219245470904815589625649188793092848535613677013244459644082552002973997664320709298313455655568934402919353780614904687774118812929306608142216956518480096479273231037657068309313591409884544082364749670344885783418081379286088507708808447866021813233948182047191027512104459349784199245502780854102931598962142881946707191383441374157982540497668109657059583216367070962289089154965539171049363908274111462315358955027545920727070493589765746099985739859030038162321640153378613819032980975249342328307926787953590638830137711750818333556082195490284962011401117106593350969003103134244326905304055750616539325363933010261551621470637210665366933722167032981304774989224613853273809279131530797350896796180381919778118053106252423108642358599762823080897075917569394021710484602719071267068088619496688730449426460339247371304272940233770632572870984887535445457936898208432289799715452500870774572564305972961851607241927449719501442007083446518896803612052243996502913423752823548223398747672502887472736285137596690248511778736188619157655050220914686378377074193288266877995059525070533800203634711939569590884953827807767786210461003711071653220566334495198424104477962742127428495705350469072114347038097271475233572189947501767731600242359412429667155582376296772873233421924537197935046438851335204083892889341386881069471631308442545959262485079137626265291048184568107381518919610269621082524109053019215711129456716586917206863077845014009823680634714263479151641922171100940383760543547314498505233055828673031456063240787153664923890439439186573793193581508123998143665332682158781926920083444957342785758118873004004624908286187452541152050663074383356019956220245868981744912194977524368807046744127994027485852982293142172650941651371217132480447221378248064545433466973673708395640933133513079122261968583062078258558153619735168872088242010692924684053560357565294684874244457437442718574479401495550720080138504405325882052992740079287755947114232671797659773578842717632033888599745679081197780527180027211036747311058894745929892239295919206744279969533517315925297560707325579050900769974679422075074126804543498704046753556416945409139513785579938181217929389079791339131095357234682475064837660435550934862484588437874873295777262458070708846519082640680466120360906435382482396893417241193116943133252566895669015041993271310568071218156195983415385603057388893153512505227412212132696015340852125467124353014429615162678866649607634031662856545199672591947347205689626344041655716224414566361092558601485285666494277196687408644436975482312485853266964820044618309439040407872380683442725993898491385226530350035259210063179338720015561499310251034425482440391380851548485137940722718456294220193314302864672672504693040544392156694318358034758347649351033755070023878181575996991637211739596296218794224126478797555013930604847679292916231359313652550011928083371026945201746210953583248709142759630877314997197976163666504553120702631114421184092038396095824360570296963893590139945893074539320423236021033339585170403965008798888653103628723758912696859649991297081348457050328829113512546965529503754470096996291788395246212087292739139040875000926867318039571557856669955046020358582424151229962631027614883370246600702767764402040569800557435183166475042420895101080681393173314203205692637149405922737052075430886372055364155690652954705878856602894639616286719009390236904303990849138499087869024877858174548167996478181202251964296095562400519567696631108677560542218856544290381182007164322003076488771496610976426817271015041857524359217130319351475722233519534530742183565957774851284973657664907123915240591253805750495988360496558801213924576655134260119475598322414186737993862380634510297783648397229396804853547672617608355365829567287360358373082977549828557082724750977302568947870663814203153029263072453588265922198590151780672993767512183896946746739431210351164454201745639693190702419109730540989876004711588598993686733758176856105325596811808128689972382395075110455358651774116145347679330202169736939814442589850836125795881277493711874567684262511175400783448363941693053158220323707841588394781504184839785160300128076372782227598436663563269042150990525936741963542388679006981041440667294790722622267321244769012773304458589438761908303928597176554812529188001447297149829234250265706080414753147473306310785582498693942149451842543973269467495937844651471761837172414261954107130567323093787194360747864733714681173213157001000263582323533083074863221348051425793805557019697102708694604500649823153735332646814107216905303104405087149051566376218188567656286896673215412580036203193369695967369513252532676916923775128676763428857572024689860947706357576461488192514698664023443556987035294971864641589687247544652556907195638288783210099436682029143137492890704560312099887566303782681296709824531238160003825184192214981527994719408957385273807541674376154310140862365088202754579566996053873436316696224557093293203637904065626607586285011656117730495775468829301021279653917714927152006492666939979073239372326263459102694888381431955160658627956171510974296706516634147521422836355414315957344098671797913155117634149998525408564265992994072586740606820099039251394014644763651483463788686079781395058899098486433471908215724295544223620477183725781036985405667293256061073968808254602909616788517759505130886663478112366257729267209025348708629783942458086382701818227822105132334957240653116196516842532473199483267403350147686115327947756813680319684329287053368566430598397577284510067690513358352798435274213166449832920002392286091916019229370573573971329304965152659791103450266246737256658652450296954647174995677537737361018153660525247183695741595534513322920329741853871388531435989792031569337891098037096145076482966965786505435345557769892391467532337946503444618509777878258669009134534392483470979723352085827854851960580160689336176596445652035381091966042187732472537698027644222419587721565412717594729752668692753048759770568815547703166075617470258654884839723941607758752672868983718782509819863071393047625106344194527572732675053763023044681907706399678214719726950557443760711587543941310447915121593752007378393876760315662729454339222744737832336836190295551373388963204595155400477413504934101362946284057961273887233498002903061355630246133483228446887364462363879906622231704415907293226819330610627025655097788665879920317876256017226680706155726095358893064826106839370367043838592470139202597407666536145126331024134657112584956459478793237597241640996736764163327070809161351345104132172614097262948883858103804836926885568311711563110950578161311327365475134367574763584811062350046334785816488497676866667895111874589195380885799387720037372932791486452025174979666062189740420006449182674780076547804181759734899583740855476147753778332716769352332872668300524939108490712603289900361237753544240771493557602672720296281878009052663650095395642622777662448702829863314451810300916185519027711384788084770078767135628524264267754418377571221277297424239662513361149078901492155294699316791535575217464668415964811664895724838583093764389122807126012381219087197393674379705828167829556618365606655311705532383207793808920115412628518305494045608049173795733680115022044176779417329469348285258215088526312527718697036901755590900153074296727513671814183066230006616647906054165689816934803796464302369738297727903099096812969483192521967581407222105853926877104595078700172872035740562030304221384738727538762175503443901639927725590463433736664794495532518758493169499111706262019176340053138542577259915448128709917216175637951505635757542388878282681915082629898749651904976039304614777252471370991392948373825522315544908352697915850759778057882654815324832733348905829564633406157501481599330382107715998136641499176059391017537076893296419436771089857598717978132230544384902276178284962609403285224949436655329472545186674848927816780577467766317010689277826696079725178167875726694887947149593753730070120057415588962539162681997022380106753636194077387322755328372278715696152695756288007796495921759836354647365316922127906115055092494918873517205994246347636729067184221902146266550530230812429724881393027002440755793048199795986433580218158237248505842527372052896348033831816843596799263053793760169231573144516833659815674708518284018568883567097549689969116525732686252167221256508408988132881147665001908042410542817562004686845494748195670667511405753745369362771250893647927161122501009417356993372307191687867665223501929941157262345516128490117047835768400786097252716079199503687001523915650149073150669152174407467555424080660546221038833460544445500143680322167106927742827758858910096901757628291237231425055367277948849326621887830328826100673700629219032702177886459050230312729581651406329118331331785116243029971266986377883839443851309300455505178116524979169246369893686345303411222212844630470734829945767284177990057497762832488580004465674212935519251783430697874889741193061288744760891717016884468023942298606918976228771199768568570942384986854697947386535821541217801558253975363113877816402110413641342915607135173299583868435660806322648816068407369392756213423122083314353736216600802622829929209839897333200413412530974578544970111789138676914115091469291981570686632265063429635392093388492396661670893962339422587748947921580948096813325917177535092968299800649787927893285057618355013959711000771735785259029184441685434827402161338433167348777217011298908528325485268206895396666912916761106832371854307337094226493234142098414165375563104113816038138141981137195664198192937416153838940359808314554292999861844196523534238903309730396977271581074240979863217660519428302323812889512609444234173483400226846600690944147288776122669287181301057433083359113028951537688999564086617799185125056700058434094097553215329222930848013042194648422031889617493236746709605966819138324631986952022894642507251005452647512782080855686515493293270108366219327275869253601366855692461672213725858739358641291574386370595250718979180132530880699545499306652697874715344910945173550541743087199788968570306021515553777188148163769642050869520898629664638996363184504710458156864060849946966175977376632927511264284816574420484153756230461200159751535183135798647263492973251916226346976047850274028923452954234622531176039887187671355760193203396250743834160031476448762865980702033161268810951968891265100555772222627986936288754261779038309497449465933349408652521470625942767847789879688125176443260462034377595715358349348282359684934154949522488450538614251010406761528282565396511453853855756034468118931872772008734204009523917712878991722592203888061250563367039909617462205273664100468119527568825082832040463069319564641000177975930202458458172307345139423082625848593347500946653525410469189622935842481254084356837174638912515645217566251105472832077847999788706979828212119645541372839721579836666881458133543214820382898822853068381881908040971226348289979372983165114315761335446907715424192463421269295829012551043004078173394090411054695986701283080434725299807705260873532106332697330336674875353967492499547033626723625492166508333403838693771672343582271848682410342296969412408943905681525624961060926867747897273463471617946058034882955900227271153160839544662253011628587728474492879480006033694531371644630594076032432087117575030599119161010085492451545816100932443186801197877418121210520657175781966640025335763838940314143451521007669495511433824082314141288301999830821635696971769399775441906040393486873125323573788865191773115500150132414229890583347225308944077677226897470504330892248412590549816485822971364380172736292498756447071216840668345890830440932177589471154118349912178754400815844142077683143461145277485837534160765896356277044027565964620562713485825833423174052034421027734048046833384651187860720517961622752159080977353054461129022809486427770734083288733727610955561086825834181160369273166146062214325681082487386712028077085727976842992513726916072663204781061016997402931635389540475505229385892698283727312244013877377026929073227059124243215291240849560633818267731195898456288774989281123910116613521745280155787713458356403668489312009379226967180349601466864047083403606213859138442435350404727549340672046983357682006994797466837419819364840102449733359949539663823753804327000109468480900833315013512100982860079189405616256825184778361809765155081072645477636965962038988859763747926945949627518565571449227813428396091227700087533078812167730181184995845976658799266327759396974019571125297359680069649147834599971902990217167785621610950369613437001924218438073497469405091281790192439772820469215461800634822507305469349118949200585103474313659832189977915232501406496410142217128425507411085482472428783626270043567535175045319726618761377775748948041473212159557671212315749629698399513525305430917211604318980346917678935396746766660734343773999625891742355568509561204761614643547606124454337468014166770722343308536838957855646879368729636045761555854093844006346371193537073903579074934196632639512360750021914247377241082283350046379617358141040568554647391134657990182506091977092534851370537935202334809059242545762717019804283337316925008846477165312701412906067587067196070612503208260999670115359105405488097707726377158224928321716795223261504694813534255131823125451590282073482089286574059055502769003267920866994220500902374151867516881243343910680560788726560948247463046511011812768043079207337937400445159530278615948793273177142652637224294444280115543845663910230250845760379959060029736483156021319076839962193254603153635877849493172919346846228136452099064402414219365258215246387818315411834201055316124021932428513682928110738011074146120744604457564427216001037530724433926292923301727157889537167045690098200635828946720030783434122137271423271424562826139364614155408212324838571978450003746183758964862935543967805247300993421504385123727626587188348026006251390302952582437255035051170822664184947818760595486951019148919308085510287754840957147867084354457029773460806550048113335841506002259444258516177580956308685050119954516768473893341607697161580971829783325338811411419826704912661249203066618180968278347773730985378596300038322424043547100486319664490622400357977788307123181585535314518339637381887610941744940222828204698031577838164872277892163169537240807535927521199471602481527089654184156600875342772129796405038717041194458671579725751152236979628712350615082337792760963328512843954045374635059289688500224454713748794580951866019870826007432655048307528477880965398121005182196565459599237947340914064861159802362904048509511811593437031915080190901476613274470617154690688196604763269721685037977776434283507431160392796324536474886794396621871172630874677250696482028294593284792950748377510052504306730089714086751214249781089595241023862193271421176617277630361672047293255095773757749538839390030270013814743254752225657534549679836513116241937560615371468968081291815628244928163449372896375351562904216507169491582666702870331506035049939541899128966864587546124068383964229704860067790553918983934034771581590473599509405171415502658708652693500757777295231479279993612908051542991806664489426945357409261534339831049280536723384288131963695868780198045493524719724944009549890217753652203329948323803287148347004809666373248671935018642716136134260232302411362732554638370662710120898372955571721130562681197468793445940459153208225238843503099024468725399523864821891711568037881393864001334137281557314972749207843008647274920909790098237097149309776836085353896851462718720935302234898653655064921634618279100072095553623986677842286716435027852510167688382886172024665143095277367013915199024942429981783202411045780597442537044742630026569027105269720480589423917347270664049027250923071507566345612765324593914765635805398200411867356310557160317664772196471305030325399064742299028457892313178398619767612979930050577089954020693935552833554622114499091529814325404677412850357785302993958808077088136978896945443609135845353258715240323451656139397088055826502116602870284448398757829180333952218468610927781001267522521561641334301410278280891945179946025100689370784764427233752818516278673742131136709897367058089034490675211846328682812561383006411767291484131139133814591316054915559566631423492734811653315448154620874838982459961705996650455770603429412450508020333736426200190391708532461127017451637437497797011181968760986795958042304799246453780536504581555265766038802258346925623802219746855044098970866964992397575165736201907047029305277291564078319449831633999096493295413964120898265399335970075656671548601508177228921011270930157055571643101168685211744224167251370664813102351877978974476864764674230592196518194682527898846558548528086066896959823488109288567970676920774201897590043244111907907017042325813462694093261539699245000059958031828240901030153622964306965014399418970855482070453085029557403893077437218819715118942709118918163423816816953373812093198392724598518574310241596813535446362519521311525938852802362721498778552011632847851483478269985094368102745782111758479949013236307827923411076015744288918473825798364318259441956546298549395878028435241470808631615556683979083062452460850800605138666622164754422296484270158182545144865812228044611815011123220115580324132966752183805761525242945940703896846436177144278554245228454796993239914950356177769539521601790670085751068223572945153067815801999920243062458667037294847913933489683474983279958560922667846523509172579987950341434757951359395807844805888991603400268319206574270923789414447622117740835207301128305855537996071764853524676511486448808311681058648656862169354842256084819706535673116713021287852821086787641469283765766819518888949559993757198849352591158210776639064725043828854271464575459326279250485105583106755056468333035017969464678627977168847840779258307352316253757341580976155277878161243769390855514149417616546485724411009273652897648670172240766036959490229803054607743456872714781391189163094869732296405992773557362370915557671531648956037333043

Execution Trace

MooniFactory.deploy( tokenA=0x0000000000000000000000000000000000000000, tokenB=0x9E78b8274e1D6a76a0dBbf90418894DF27cBCEb5 ) => ( pool=0xAa5Bac68C9C655FE7779030031A79084a2984ae5 )
  • VotingToken.STATICCALL( )
  • Mooniswap.60806040( )
  • Mooniswap.transferOwnership( newOwner=0x68a17B587CAF4f9329f0e372e3A78D23A46De6b5 )
    File 1 of 3: MooniFactory
    /*
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNXK0OxdoollccccclodkOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0kdlc;'..      .,:loxkk0KXNWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNKkoc,..        .':ox0XNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOd:'.          .;lxKNWMMMMMMMMMMMMMMMWWNNNNNNNNWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo:.           .,lkXWMMMMMMMMMWXKOxddol:;;,''.....'',,;:cldxO0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXxc'            .;d0NMMMMMMMWXOxl:,..                            ..,:ldOKNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXx:.            .;dKWMMMMMWN0dc,.                                          .,cdOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNkc.             'l0NMMMMMN0d:'.                                                   .:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMW0o'             .;xXMMMMMNOo,.              .....''',,'''....                           .'lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMNOc.             .:kNMMMMW0o,         ..,:loxk0KKXXNNNWWWNNNNXKK0kxol:,..                      .cONMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMNk;.             .;ONMMMMXx;.      .,cdkKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKOdc;.                    ,oKWMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMNk;               ,kNMMMW0l.     ':dOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOd:'                  .cOWMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMWO:               .dXMMMW0c.   .;oONWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;.                .:ONMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMWKc.               :0WMMWKl.  .;dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNWMMMMMMMMMMWKx:.               .:OWMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMNx.               .dNMMMXd.  ,o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0kxOXWMMMMMMMMWKd;.              .cKWMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMW0:                ,OWMMWO, .:kNMMMMMMMMMMMMMMMMMMMMMMWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMWXxc,:d0NMMMMMMMMNOc.              .xNMMMMMMMMMMMMMM
    MMMMMMMMMMMMMNx.                :KMMMXo..c0WMMMMMMMMMMMMMMMMMMMMXxl:;,;;:codkKNMMMMMMMMMMMMMMMMMMMMMMNk;..,o0WMMMMMMMWKo.              :KMMMMMMMMMMMMM
    MMMMMMMMMMMMXl.                cXMMW0:.c0WMMMMMMMMMMMMWWNNXXXNNWXd'..;;'..   .,lkNMMW00NMMMMMMMMMMMMMMMNk;  .;dKWMMMMMMWKo.             'kWMMMMMMMMMMM
    MMMMMMMMMMMK:                 cXMMWk;;OWMMMMMMMMMN0xoc;,'.....';cll'.oKNX0xol,   ,xXNc.,xXMMMMMMMMMMMMMMMNx'   .l0WMMMMMMWKl.            .dNMMMMMMMMMM
    MMMMMMMMMM0;                 cXMMWk:dXMMMMMMMMW0o,.  ..,:clllllcc:;,..;0WMMMMNO:.  ;Ol.  ;0MMMMMMMMMMMMMMMMXl.   .:OWMMMMMMWO;            .lNMMMMMMMMM
    MMMMMMMMM0,                 ;KMMWklkNWMMMMMMMKl.     .';coxOXWMMMMWNKOdxKWMMMMMWk,  .:l:  ,0MMMMMMMMMMMMMMMMWO,    .c0WMMMMMMXo.            lXMMMMMMMM
    MMMMMMMM0,                 '0MMNx,''lXMMMMMWk'   .,cdxkkkxdxxOKXWMMMMMMWNXNMMMMMM0,  .kK;  cNMMMMMMN0XMMMMMMMMKc     .oXMMMMMMWO,            lNMMMMMMM
    MMMMMMM0;                 .xWMKc. . .kWMMMNd.  .l0NMMMMMMMMMMWNXNWMMMMMMMWNNWMMMMMk. 'OWd. .OMMMMXx:oXMMMMMMMMMNo.     ,kWMMMMMMK:           .dWMMMMMM
    MMMMMMX:                  cXM0; .l0o..:ool,  .lKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX; ;XMO. .dWWKo'.:KMMMMMMMMMMMWx.     .oXMMMMMMXc           .kWMMMMM
    MMMMMNl                  .OMX: .oNMWOc'...':dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc.dWMO.  lOl.  ,0MMMMMMMMMMMMMWx.      :KMMMMMMXl           ;KMMMMM
    MMMMWx.                  lNMx. ;XMMMMMNXKXNWMWNWMMMMMMMMMMMMMMMXO0WMMMMMMMMMMMMMMMK::XMWx.  ...'.'OMMMMMMMMMMMMMMMWd.      ;0MMMMMMXc           oWMMMM
    MMMMK,                  .kMNl  cNMMMMMMMWNX0kxONMMMMMMMMMMMMMMWd..,cok0NWMMMMMMMMM0xKMMX;   .cd;'kWMMMMMMMMMMMMMMMMNo       ,0MMMMMMK:          '0MMMM
    MMMWo                   .cl:. .,ooolllllc::ld0WMMMMMMMMMMMMMMMNl      .':oOXNMMMMMWMMWO:  ;d00:.xWMMMMMMMMMMMMMMMMMMX:       ;KMMMMMM0'          oWMMM
    MMM0'                    .':ok0KKK0OkxxkOKNWMMMMMMMMMMMMMMMMMMWo          ..;OWMMMMWO:.  ,OWK:.dWMMMMMMMMMMMMMMMMMMMMO'       :XMMMMMWd.         ,KMMM
    MMWo                   .l0NWMMMMMMMMMMMMMMMMMMMMMMMMWXKWMMMMW0o'             .kWMWO:. .cOOOO:.oNMMMMMMMMMNXWMMMMMMMMMWo       .oWMMMMMX:         .kMMM
    MMK,                   .OMMMMMMMMMMMMMMMMMMMMMMMMN0d:.cXMMMKc.                .ok:. ..;KMMX:.lNMMMMMMMMMWxlKMMMMMMMMMM0,       'OMMMMMWk.         oWMM
    MMx.                   'OXXNMMMMMMMMMMMMMMMMMWXkl,.   lWMWO'                       ,O0dd0Kc .kMMMMMMMMMWk' cXMMMMMMMMMWl        lNMMMMMX;         cNMM
    MNl                    .dOKNMMMMMMMMMMMMMMWKxc.       lWM0,                        'xXWN0:   ;0MMMWN0xl,.   'cdOXWMMMMMk.       'OMMMMMWd.        ;XMM
    MX;                    ;XMMMMMMMMNOkXMMWKx;.          ,KWo                           .:c,     ;KMMWN0ko;.   'cdOXWMMMMMK,        dWMMMMMO.        ,KMM
    M0'                    ,KMMMMXKN0:.oWW0c.              ;d;                                     lNMMMMMMWO'.dNMMMMMMMMMMNc        :XMMMMMK,        ;KMM
    MO.                    '0MMM0lkO, 'ONd.                                                        .oNMMMMMMWkdNMMMMMMMMMMMWo        ,KMMMMMX:        ;XMM
    Mk.                    .OMM0,,x;  ;Ol                                     ..',.                 ;KMMMMMMMNNMMMMMMMMMMMMWo        '0MMMMMNc        cNMM
    Mx.                    .dW0, ,:.  ,c.                                      .:0Xk:.              lNMMMMMMMMMMMMMMMMMMMMMWo        .OMMMMMNc        oWMM
    Mk.                     c0:  ..    .                                      .,xOd0NO;            '0MMMMMMMMMMMMMWWMMMMMMMWo        .OMMMMMN:       .kMMM
    Mk.                     .:.                     .,.                       .cx: .lKXl           lWMMMMMMMMMMMWNxlONMMMMMNc        '0MMMMMX;       ;XMMM
    M0'                                           .:c.                      .. .,:;,,l0Xl         .xMMMMMMMMMMMWNk,.:ONMMMMX;        ;XMMMMM0'      .dWMMM
    MK;                                          'dl.                        .....''',:k0d;.       oWMMMMMMMMMMMMWOo0MMMMMMO.        oWMMMMMx.      ,KMMMM
    MNc                                         :kl.                           ......   ,c;.       :XMMMMMMMMMMMMMWWWMMMMMWo        .kMMMMMNc      .dWMMMM
    MWd.                                       c0l.                                                .OMMMMMMMMMMMMMMMMMMMMMK;        :XMMMMMO'      :XMMMMM
    MM0'                                      :0d.                                         .        lNMMMMMMMMMMMMMMMMMMMWd.       .kMMMMMNl      '0MMMMMM
    MMNl                                     '0k.                    ..                    'c.      .OMMMMMMMMMMMMMMMMMMM0,        lNMMMMMO.     .kWMMMMMM
    MMMO.                                   .dK;                    ;0O;                    :d'      ;KMMMMMMMMMMMMMMMMMNl        ,KMMMMMX:     .xWMMMWXNM
    MMMNc                                   ,0d.                   .OMMNk:.                 .x0xo,    cXMMMMMMMMMMMMMMMWd.       'OMMMMMNo     .dWMMMWOkNM
    MMMMO'                                  c0;                   .dWMMMMW0l.                ;dooxl.   :0WMMMMMMMMMMMMWk.       .kWMMMMWx.    .xWMMMWxc0MM
    MMMMWd.                                 ok.                   :XMMMMMMMWO,                  .:dc    'OWMMMMMMMMMMWO'       .kWMMMMWk.    'kWMMMNo,dWMM
    MMMMMX:                                 cd.                  .kWMMMMMMMMWk.         ..      .,cc.    :XMMMMMMMMMWk'       'OWMMMMWk.    :0MMMMKc.cXMMM
    MMMMMM0,                                .'.                  :XMMMMMMMMMMNc      'c;ll.       ..     .OMMMMMMMMWx.       :KMMMMMNx.   .oNMMMWO, ;KMMMM
    MMMMMMWO'                                                   .xWMMMMMMMMMMMk:.    ,0KOOc              .OMMMMMMMNo.      .oXMMMMMXo.   ;OWMMMXl. 'OMMMMM
    MMMMMMMWk.                                                  ,0MMMMMMMMMMMMX0:     .:d00l.            lNMMMMMW0:       ;OWMMMMW0:   'xNMMMNk,  'OWMMMMM
    MMMMMMMMWx.                                                 :XMMMMMNNMMMMMMWk.       .',.          'xNMMMMMNx.      ,xNMMMMMNx.  .oXMMMWO:.  'OWMMMMMM
    MMMMMMMMMWk.                                                cNMMMMNdxNMMMMMMWO:.                .;xXMMMMMWO:      'dXMMMMMWO;  .oKWMMW0c.   'OWMMMMMMM
    MMMMMMMMMMWO,                                               cNWNKk:..:kKNWMMMMWKxc'.         .,oONMMMMMW0c.    .;xXMMMMMWKl..,dXWMMNOc.    ;0WMMMMMMMM
    MMMMMMMMMMMMK:                                              cNWN0o'  'oONWMMMMMMMWN0dc;''';lxKNMMMMMMW0l.    .cONMMMMMWKl'.ckNMMMNk;.     cKMMMMMMMMMM
    MMMMMMMMMMMMMXo.                                            cNMMMMKccKMMMMMMMMMMMMMMMMWNNNWMMMMMMMMNOc.   .:xXWMMMMMWOl;:dKWMMW0o'      .dNMMMMMMMMMMM
    MMMMMMMMMMMMMMWk'                                           lNMMMMMXXMMMMMMMMMMMMMMMMMMMMMMMMMMMWKx;. .,lkXWMMMMMWXOdoxKWMMWKd;.       ;OWMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMKl.                                         oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkc,';lxKNMMMMMMMWX0OOXWMMN0d;.        .oXMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMWk;                                        lXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOxdxOXWMMMMMMMMMMMWNWMMWKxl,.         .:0WMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMXd'                                       .:ok0NWMMMMMMMMMMMMMMMMMMMMMMMWNWWMMMMMMMMMMMMMMMMWX0xl,.            ,kNMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMXo.                                         .':ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKOdc;..              'xNMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMWKo'                                             .';ccldxO0KXXNWWWWWWWWWNNXKKOkxol:,..                  ,xXMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMWXd,                                                    ....',,,,,,,,,'....                        .;kNMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMNk:.                                                                                          .l0WMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKo,.                                                                                    .:xXWMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo,                                                                               .;dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;.                                                                        .:xKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'.                                                                .;oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0xl;.                                                       .':oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOdl;'.                                           ..,cokKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKOxoc;,...                          ..';:ldk0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWXK0Okxdollcccc:::cccclloddkO0KXNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
        ███╗   ███╗ ██████╗  ██████╗ ███╗   ██╗██╗███████╗██╗    ██╗ █████╗ ██████╗ ███████╗██╗  ██╗ ██████╗██╗  ██╗ █████╗ ███╗   ██╗ ██████╗ ███████╗
        ████╗ ████║██╔═══██╗██╔═══██╗████╗  ██║██║██╔════╝██║    ██║██╔══██╗██╔══██╗██╔════╝╚██╗██╔╝██╔════╝██║  ██║██╔══██╗████╗  ██║██╔════╝ ██╔════╝
        ██╔████╔██║██║   ██║██║   ██║██╔██╗ ██║██║███████╗██║ █╗ ██║███████║██████╔╝█████╗   ╚███╔╝ ██║     ███████║███████║██╔██╗ ██║██║  ███╗█████╗
        ██║╚██╔╝██║██║   ██║██║   ██║██║╚██╗██║██║╚════██║██║███╗██║██╔══██║██╔═══╝ ██╔══╝   ██╔██╗ ██║     ██╔══██║██╔══██║██║╚██╗██║██║   ██║██╔══╝
        ██║ ╚═╝ ██║╚██████╔╝╚██████╔╝██║ ╚████║██║███████║╚███╔███╔╝██║  ██║██║██╗  ███████╗██╔╝ ██╗╚██████╗██║  ██║██║  ██║██║ ╚████║╚██████╔╝███████╗
        ╚═╝     ╚═╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚═╝╚══════╝ ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝╚═╝  ╚══════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝
    
                                                        ██████╗ ██╗   ██╗     ██╗██╗███╗   ██╗ ██████╗██╗  ██╗
                                                        ██╔══██╗╚██╗ ██╔╝    ███║██║████╗  ██║██╔════╝██║  ██║
                                                        ██████╔╝ ╚████╔╝     ╚██║██║██╔██╗ ██║██║     ███████║
                                                        ██╔══██╗  ╚██╔╝       ██║██║██║╚██╗██║██║     ██╔══██║
                                                        ██████╔╝   ██║        ██║██║██║ ╚████║╚██████╗██║  ██║
                                                        ╚═════╝    ╚═╝        ╚═╝╚═╝╚═╝  ╚═══╝ ╚═════╝╚═╝  ╚═╝
    */
    // File: @openzeppelin/contracts/GSN/Context.sol
    
    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.6.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.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    // File: @openzeppelin/contracts/access/Ownable.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            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 virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    
    pragma solidity ^0.6.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.
         */
        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.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            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.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    
    pragma solidity ^0.6.2;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
    
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
    
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
    
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
    
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
    
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
    
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    
    // File: contracts/libraries/UniERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    library UniERC20 {
        using SafeMath for uint256;
        using SafeERC20 for IERC20;
    
        function isETH(IERC20 token) internal pure returns(bool) {
            return (address(token) == address(0));
        }
    
        function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) {
            if (isETH(token)) {
                return account.balance;
            } else {
                return token.balanceOf(account);
            }
        }
    
        function uniTransfer(IERC20 token, address payable to, uint256 amount) internal {
            if (amount > 0) {
                if (isETH(token)) {
                    to.transfer(amount);
                } else {
                    token.safeTransfer(to, amount);
                }
            }
        }
    
        function uniTransferFromSenderToThis(IERC20 token, uint256 amount) internal {
            if (amount > 0) {
                if (isETH(token)) {
                    require(msg.value >= amount, "UniERC20: not enough value");
                    if (msg.value > amount) {
                        // Return remainder if exist
                        msg.sender.transfer(msg.value.sub(amount));
                    }
                } else {
                    token.safeTransferFrom(msg.sender, address(this), amount);
                }
            }
        }
    
        function uniSymbol(IERC20 token) internal view returns(string memory) {
            if (isETH(token)) {
                return "ETH";
            }
    
            (bool success, bytes memory data) = address(token).staticcall{ gas: 20000 }(
                abi.encodeWithSignature("symbol()")
            );
            if (!success) {
                (success, data) = address(token).staticcall{ gas: 20000 }(
                    abi.encodeWithSignature("SYMBOL()")
                );
            }
    
            if (success && data.length >= 96) {
                (uint256 offset, uint256 len) = abi.decode(data, (uint256, uint256));
                if (offset == 0x20 && len > 0 && len <= 256) {
                    return string(abi.decode(data, (bytes)));
                }
            }
    
            if (success && data.length == 32) {
                uint len = 0;
                while (len < data.length && data[len] >= 0x20 && data[len] <= 0x7E) {
                    len++;
                }
    
                if (len > 0) {
                    bytes memory result = new bytes(len);
                    for (uint i = 0; i < len; i++) {
                        result[i] = data[i];
                    }
                    return string(result);
                }
            }
    
            return _toHex(address(token));
        }
    
        function _toHex(address account) private pure returns(string memory) {
            return _toHex(abi.encodePacked(account));
        }
    
        function _toHex(bytes memory data) private pure returns(string memory) {
            bytes memory str = new bytes(2 + data.length * 2);
            str[0] = "0";
            str[1] = "x";
            uint j = 2;
            for (uint i = 0; i < data.length; i++) {
                uint a = uint8(data[i]) >> 4;
                uint b = uint8(data[i]) & 0x0f;
                str[j++] = byte(uint8(a + 48 + (a/10)*39));
                str[j++] = byte(uint8(b + 48 + (b/10)*39));
            }
    
            return string(str);
        }
    }
    
    // File: @openzeppelin/contracts/utils/ReentrancyGuard.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
    
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
    
        uint256 private _status;
    
        constructor () internal {
            _status = _NOT_ENTERED;
        }
    
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and make it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            // On the first call to nonReentrant, _notEntered will be true
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
    
            // Any calls to nonReentrant after this point will fail
            _status = _ENTERED;
    
            _;
    
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = _NOT_ENTERED;
        }
    }
    
    // File: @openzeppelin/contracts/math/Math.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a >= b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/ERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    /**
     * @dev Implementation of the {IERC20} interface.
     *
     * This implementation is agnostic to the way tokens are created. This means
     * that a supply mechanism has to be added in a derived contract using {_mint}.
     * For a generic mechanism see {ERC20PresetMinterPauser}.
     *
     * TIP: For a detailed writeup see our guide
     * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * We have followed general OpenZeppelin guidelines: functions revert instead
     * of returning `false` on failure. This behavior is nonetheless conventional
     * and does not conflict with the expectations of ERC20 applications.
     *
     * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
     * This allows applications to reconstruct the allowance for all accounts just
     * by listening to said events. Other implementations of the EIP may not emit
     * these events, as it isn't required by the specification.
     *
     * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
     * functions have been added to mitigate the well-known issues around setting
     * allowances. See {IERC20-approve}.
     */
    contract ERC20 is Context, IERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        mapping (address => uint256) private _balances;
    
        mapping (address => mapping (address => uint256)) private _allowances;
    
        uint256 private _totalSupply;
    
        string private _name;
        string private _symbol;
        uint8 private _decimals;
    
        /**
         * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
         * a default value of 18.
         *
         * To select a different value for {decimals}, use {_setupDecimals}.
         *
         * All three of these values are immutable: they can only be set once during
         * construction.
         */
        constructor (string memory name, string memory symbol) public {
            _name = name;
            _symbol = symbol;
            _decimals = 18;
        }
    
        /**
         * @dev Returns the name of the token.
         */
        function name() public view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev Returns the number of decimals used to get its user representation.
         * For example, if `decimals` equals `2`, a balance of `505` tokens should
         * be displayed to a user as `5,05` (`505 / 10 ** 2`).
         *
         * Tokens usually opt for a value of 18, imitating the relationship between
         * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
         * called.
         *
         * NOTE: This information is only used for _display_ purposes: it in
         * no way affects any of the arithmetic of the contract, including
         * {IERC20-balanceOf} and {IERC20-transfer}.
         */
        function decimals() public view returns (uint8) {
            return _decimals;
        }
    
        /**
         * @dev See {IERC20-totalSupply}.
         */
        function totalSupply() public view override returns (uint256) {
            return _totalSupply;
        }
    
        /**
         * @dev See {IERC20-balanceOf}.
         */
        function balanceOf(address account) public view override returns (uint256) {
            return _balances[account];
        }
    
        /**
         * @dev See {IERC20-transfer}.
         *
         * Requirements:
         *
         * - `recipient` cannot be the zero address.
         * - the caller must have a balance of at least `amount`.
         */
        function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-allowance}.
         */
        function allowance(address owner, address spender) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        /**
         * @dev See {IERC20-approve}.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-transferFrom}.
         *
         * Emits an {Approval} event indicating the updated allowance. This is not
         * required by the EIP. See the note at the beginning of {ERC20};
         *
         * Requirements:
         * - `sender` and `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         * - the caller must have allowance for ``sender``'s tokens of at least
         * `amount`.
         */
        function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
    
        /**
         * @dev Atomically increases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
            return true;
        }
    
        /**
         * @dev Atomically decreases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         * - `spender` must have allowance for the caller of at least
         * `subtractedValue`.
         */
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
            return true;
        }
    
        /**
         * @dev Moves tokens `amount` from `sender` to `recipient`.
         *
         * This is internal function is equivalent to {transfer}, and can be used to
         * e.g. implement automatic token fees, slashing mechanisms, etc.
         *
         * Emits a {Transfer} event.
         *
         * Requirements:
         *
         * - `sender` cannot be the zero address.
         * - `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         */
        function _transfer(address sender, address recipient, uint256 amount) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
    
            _beforeTokenTransfer(sender, recipient, amount);
    
            _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
    
        /** @dev Creates `amount` tokens and assigns them to `account`, increasing
         * the total supply.
         *
         * Emits a {Transfer} event with `from` set to the zero address.
         *
         * Requirements
         *
         * - `to` cannot be the zero address.
         */
        function _mint(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: mint to the zero address");
    
            _beforeTokenTransfer(address(0), account, amount);
    
            _totalSupply = _totalSupply.add(amount);
            _balances[account] = _balances[account].add(amount);
            emit Transfer(address(0), account, amount);
        }
    
        /**
         * @dev Destroys `amount` tokens from `account`, reducing the
         * total supply.
         *
         * Emits a {Transfer} event with `to` set to the zero address.
         *
         * Requirements
         *
         * - `account` cannot be the zero address.
         * - `account` must have at least `amount` tokens.
         */
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
    
            _beforeTokenTransfer(account, address(0), amount);
    
            _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
            _totalSupply = _totalSupply.sub(amount);
            emit Transfer(account, address(0), amount);
        }
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
         *
         * This is internal function is equivalent to `approve`, and can be used to
         * e.g. set automatic allowances for certain subsystems, etc.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `owner` cannot be the zero address.
         * - `spender` cannot be the zero address.
         */
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        /**
         * @dev Sets {decimals} to a value other than the default one of 18.
         *
         * WARNING: This function should only be called from the constructor. Most
         * applications that interact with token contracts will not expect
         * {decimals} to ever change, and may work incorrectly if it does.
         */
        function _setupDecimals(uint8 decimals_) internal {
            _decimals = decimals_;
        }
    
        /**
         * @dev Hook that is called before any transfer of tokens. This includes
         * minting and burning.
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * will be to transferred to `to`.
         * - when `from` is zero, `amount` tokens will be minted for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
         * - `from` and `to` are never both zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    }
    
    // File: contracts/libraries/Sqrt.sol
    
    
    pragma solidity ^0.6.0;
    
    
    library Sqrt {
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint256 y) internal pure returns (uint256) {
            if (y > 3) {
                uint256 z = y;
                uint256 x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
                return z;
            } else if (y != 0) {
                return 1;
            } else {
                return 0;
            }
        }
    }
    
    // File: contracts/Mooniswap.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    
    
    
    
    interface IFactory {
        function fee() external view returns(uint256);
    }
    
    
    library VirtualBalance {
        using SafeMath for uint256;
    
        struct Data {
            uint216 balance;
            uint40 time;
        }
    
        uint256 public constant DECAY_PERIOD = 5 minutes;
    
        function set(VirtualBalance.Data storage self, uint256 balance) internal {
            self.balance = uint216(balance);
            self.time = uint40(block.timestamp);
        }
    
        function update(VirtualBalance.Data storage self, uint256 realBalance) internal {
            set(self, current(self, realBalance));
        }
    
        function scale(VirtualBalance.Data storage self, uint256 realBalance, uint256 num, uint256 denom) internal {
            set(self, current(self, realBalance).mul(num).add(denom.sub(1)).div(denom));
        }
    
        function current(VirtualBalance.Data memory self, uint256 realBalance) internal view returns(uint256) {
            uint256 timePassed = Math.min(DECAY_PERIOD, block.timestamp.sub(self.time));
            uint256 timeRemain = DECAY_PERIOD.sub(timePassed);
            return uint256(self.balance).mul(timeRemain).add(
                realBalance.mul(timePassed)
            ).div(DECAY_PERIOD);
        }
    }
    
    
    contract Mooniswap is ERC20, ReentrancyGuard, Ownable {
        using Sqrt for uint256;
        using SafeMath for uint256;
        using UniERC20 for IERC20;
        using VirtualBalance for VirtualBalance.Data;
    
        struct Balances {
            uint256 src;
            uint256 dst;
        }
    
        struct SwapVolumes {
            uint128 confirmed;
            uint128 result;
        }
    
        event Deposited(
            address indexed account,
            uint256 amount
        );
    
        event Withdrawn(
            address indexed account,
            uint256 amount
        );
    
        event Swapped(
            address indexed account,
            address indexed src,
            address indexed dst,
            uint256 amount,
            uint256 result,
            uint256 srcBalance,
            uint256 dstBalance,
            uint256 totalSupply,
            address referral
        );
    
        uint256 public constant REFERRAL_SHARE = 20; // 1/share = 5% of LPs revenue
        uint256 public constant BASE_SUPPLY = 1000;  // Total supply on first deposit
        uint256 public constant FEE_DENOMINATOR = 1e18;
    
        IFactory public factory;
        IERC20[] public tokens;
        mapping(IERC20 => bool) public isToken;
        mapping(IERC20 => SwapVolumes) public volumes;
        mapping(IERC20 => VirtualBalance.Data) public virtualBalancesForAddition;
        mapping(IERC20 => VirtualBalance.Data) public virtualBalancesForRemoval;
    
        constructor(IERC20[] memory assets, string memory name, string memory symbol) public ERC20(name, symbol) {
            require(bytes(name).length > 0, "Mooniswap: name is empty");
            require(bytes(symbol).length > 0, "Mooniswap: symbol is empty");
            require(assets.length == 2, "Mooniswap: only 2 tokens allowed");
    
            factory = IFactory(msg.sender);
            tokens = assets;
            for (uint i = 0; i < assets.length; i++) {
                require(!isToken[assets[i]], "Mooniswap: duplicate tokens");
                isToken[assets[i]] = true;
            }
        }
    
        function fee() public view returns(uint256) {
            return factory.fee();
        }
    
        function getTokens() external view returns(IERC20[] memory) {
            return tokens;
        }
    
        function decayPeriod() external pure returns(uint256) {
            return VirtualBalance.DECAY_PERIOD;
        }
    
        function getBalanceForAddition(IERC20 token) public view returns(uint256) {
            uint256 balance = token.uniBalanceOf(address(this));
            return Math.max(virtualBalancesForAddition[token].current(balance), balance);
        }
    
        function getBalanceForRemoval(IERC20 token) public view returns(uint256) {
            uint256 balance = token.uniBalanceOf(address(this));
            return Math.min(virtualBalancesForRemoval[token].current(balance), balance);
        }
    
        function getReturn(IERC20 src, IERC20 dst, uint256 amount) external view returns(uint256) {
            return _getReturn(src, dst, amount, getBalanceForAddition(src), getBalanceForRemoval(dst));
        }
    
        function deposit(uint256[] calldata amounts, uint256[] calldata minAmounts) external payable nonReentrant returns(uint256 fairSupply) {
            IERC20[] memory _tokens = tokens;
            require(amounts.length == _tokens.length, "Mooniswap: wrong amounts length");
            require(msg.value == (_tokens[0].isETH() ? amounts[0] : (_tokens[1].isETH() ? amounts[1] : 0)), "Mooniswap: wrong value usage");
    
            uint256[] memory realBalances = new uint256[](amounts.length);
            for (uint i = 0; i < realBalances.length; i++) {
                realBalances[i] = _tokens[i].uniBalanceOf(address(this)).sub(_tokens[i].isETH() ? msg.value : 0);
            }
    
            uint256 totalSupply = totalSupply();
            if (totalSupply == 0) {
                fairSupply = BASE_SUPPLY.mul(99);
                _mint(address(this), BASE_SUPPLY); // Donate up to 1%
    
                // Use the greatest token amount but not less than 99k for the initial supply
                for (uint i = 0; i < amounts.length; i++) {
                    fairSupply = Math.max(fairSupply, amounts[i]);
                }
            }
            else {
                // Pre-compute fair supply
                fairSupply = type(uint256).max;
                for (uint i = 0; i < amounts.length; i++) {
                    fairSupply = Math.min(fairSupply, totalSupply.mul(amounts[i]).div(realBalances[i]));
                }
            }
    
            uint256 fairSupplyCached = fairSupply;
            for (uint i = 0; i < amounts.length; i++) {
                require(amounts[i] > 0, "Mooniswap: amount is zero");
                uint256 amount = (totalSupply == 0) ? amounts[i] :
                    realBalances[i].mul(fairSupplyCached).add(totalSupply - 1).div(totalSupply);
                require(amount >= minAmounts[i], "Mooniswap: minAmount not reached");
    
                _tokens[i].uniTransferFromSenderToThis(amount);
                if (totalSupply > 0) {
                    uint256 confirmed = _tokens[i].uniBalanceOf(address(this)).sub(realBalances[i]);
                    fairSupply = Math.min(fairSupply, totalSupply.mul(confirmed).div(realBalances[i]));
                }
            }
    
            if (totalSupply > 0) {
                for (uint i = 0; i < amounts.length; i++) {
                    virtualBalancesForRemoval[_tokens[i]].scale(realBalances[i], totalSupply.add(fairSupply), totalSupply);
                    virtualBalancesForAddition[_tokens[i]].scale(realBalances[i], totalSupply.add(fairSupply), totalSupply);
                }
            }
    
            require(fairSupply > 0, "Mooniswap: result is not enough");
            _mint(msg.sender, fairSupply);
    
            emit Deposited(msg.sender, fairSupply);
        }
    
        function withdraw(uint256 amount, uint256[] memory minReturns) external nonReentrant {
            uint256 totalSupply = totalSupply();
            _burn(msg.sender, amount);
    
            for (uint i = 0; i < tokens.length; i++) {
                IERC20 token = tokens[i];
    
                uint256 preBalance = token.uniBalanceOf(address(this));
                uint256 value = preBalance.mul(amount).div(totalSupply);
                token.uniTransfer(msg.sender, value);
                require(i >= minReturns.length || value >= minReturns[i], "Mooniswap: result is not enough");
    
                virtualBalancesForAddition[token].scale(preBalance, totalSupply.sub(amount), totalSupply);
                virtualBalancesForRemoval[token].scale(preBalance, totalSupply.sub(amount), totalSupply);
            }
    
            emit Withdrawn(msg.sender, amount);
        }
    
        function swap(IERC20 src, IERC20 dst, uint256 amount, uint256 minReturn, address referral) external payable nonReentrant returns(uint256 result) {
            require(msg.value == (src.isETH() ? amount : 0), "Mooniswap: wrong value usage");
    
            Balances memory balances = Balances({
                src: src.uniBalanceOf(address(this)).sub(src.isETH() ? msg.value : 0),
                dst: dst.uniBalanceOf(address(this))
            });
    
            // catch possible airdrops and external balance changes for deflationary tokens
            uint256 srcAdditionBalance = Math.max(virtualBalancesForAddition[src].current(balances.src), balances.src);
            uint256 dstRemovalBalance = Math.min(virtualBalancesForRemoval[dst].current(balances.dst), balances.dst);
    
            src.uniTransferFromSenderToThis(amount);
            uint256 confirmed = src.uniBalanceOf(address(this)).sub(balances.src);
            result = _getReturn(src, dst, confirmed, srcAdditionBalance, dstRemovalBalance);
            require(result > 0 && result >= minReturn, "Mooniswap: return is not enough");
            dst.uniTransfer(msg.sender, result);
    
            // Update virtual balances to the same direction only at imbalanced state
            if (srcAdditionBalance != balances.src) {
                virtualBalancesForAddition[src].set(srcAdditionBalance.add(confirmed));
            }
            if (dstRemovalBalance != balances.dst) {
                virtualBalancesForRemoval[dst].set(dstRemovalBalance.sub(result));
            }
    
            // Update virtual balances to the opposite direction
            virtualBalancesForRemoval[src].update(balances.src);
            virtualBalancesForAddition[dst].update(balances.dst);
    
            if (referral != address(0)) {
                uint256 invariantRatio = uint256(1e36);
                invariantRatio = invariantRatio.mul(balances.src.add(confirmed)).div(balances.src);
                invariantRatio = invariantRatio.mul(balances.dst.sub(result)).div(balances.dst);
                if (invariantRatio > 1e36) {
                    // calculate share only if invariant increased
                    uint256 referralShare = invariantRatio.sqrt().sub(1e18).mul(totalSupply()).div(1e18).div(REFERRAL_SHARE);
                    if (referralShare > 0) {
                        _mint(referral, referralShare);
                    }
                }
            }
    
            emit Swapped(msg.sender, address(src), address(dst), confirmed, result, balances.src, balances.dst, totalSupply(), referral);
    
            // Overflow of uint128 is desired
            volumes[src].confirmed += uint128(confirmed);
            volumes[src].result += uint128(result);
        }
    
        function rescueFunds(IERC20 token, uint256 amount) external nonReentrant onlyOwner {
            uint256[] memory balances = new uint256[](tokens.length);
            for (uint i = 0; i < balances.length; i++) {
                balances[i] = tokens[i].uniBalanceOf(address(this));
            }
    
            token.uniTransfer(msg.sender, amount);
    
            for (uint i = 0; i < balances.length; i++) {
                require(tokens[i].uniBalanceOf(address(this)) >= balances[i], "Mooniswap: access denied");
            }
            require(balanceOf(address(this)) >= BASE_SUPPLY, "Mooniswap: access denied");
        }
    
        function _getReturn(IERC20 src, IERC20 dst, uint256 amount, uint256 srcBalance, uint256 dstBalance) internal view returns(uint256) {
            if (isToken[src] && isToken[dst] && src != dst && amount > 0) {
                uint256 taxedAmount = amount.sub(amount.mul(fee()).div(FEE_DENOMINATOR));
                return taxedAmount.mul(dstBalance).div(srcBalance.add(taxedAmount));
            }
        }
    }
    
    // File: contracts/MooniFactory.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    contract MooniFactory is Ownable {
        using UniERC20 for IERC20;
    
        event Deployed(
            address indexed mooniswap,
            address indexed token1,
            address indexed token2
        );
    
        uint256 public constant MAX_FEE = 0.003e18; // 0.3%
    
        uint256 public fee;
        Mooniswap[] public allPools;
        mapping(Mooniswap => bool) public isPool;
        mapping(IERC20 => mapping(IERC20 => Mooniswap)) public pools;
    
        function getAllPools() external view returns(Mooniswap[] memory) {
            return allPools;
        }
    
        function setFee(uint256 newFee) external onlyOwner {
            require(newFee <= MAX_FEE, "Factory: fee should be <= 0.3%");
            fee = newFee;
        }
    
        function deploy(IERC20 tokenA, IERC20 tokenB) public returns(Mooniswap pool) {
            require(tokenA != tokenB, "Factory: not support same tokens");
            require(pools[tokenA][tokenB] == Mooniswap(0), "Factory: pool already exists");
    
            (IERC20 token1, IERC20 token2) = sortTokens(tokenA, tokenB);
            IERC20[] memory tokens = new IERC20[](2);
            tokens[0] = token1;
            tokens[1] = token2;
    
            string memory symbol1 = token1.uniSymbol();
            string memory symbol2 = token2.uniSymbol();
    
            pool = new Mooniswap(
                tokens,
                string(abi.encodePacked("Mooniswap V1 (", symbol1, "-", symbol2, ")")),
                string(abi.encodePacked("MOON-V1-", symbol1, "-", symbol2))
            );
    
            pool.transferOwnership(owner());
            pools[token1][token2] = pool;
            pools[token2][token1] = pool;
            allPools.push(pool);
            isPool[pool] = true;
    
            emit Deployed(
                address(pool),
                address(token1),
                address(token2)
            );
        }
    
        function sortTokens(IERC20 tokenA, IERC20 tokenB) public pure returns(IERC20, IERC20) {
            if (tokenA < tokenB) {
                return (tokenA, tokenB);
            }
            return (tokenB, tokenA);
        }
    }

    File 2 of 3: Mooniswap
    /*
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNXK0OxdoollccccclodkOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0kdlc;'..      .,:loxkk0KXNWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNKkoc,..        .':ox0XNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOd:'.          .;lxKNWMMMMMMMMMMMMMMMWWNNNNNNNNWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo:.           .,lkXWMMMMMMMMMWXKOxddol:;;,''.....'',,;:cldxO0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXxc'            .;d0NMMMMMMMWXOxl:,..                            ..,:ldOKNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXx:.            .;dKWMMMMMWN0dc,.                                          .,cdOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNkc.             'l0NMMMMMN0d:'.                                                   .:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMW0o'             .;xXMMMMMNOo,.              .....''',,'''....                           .'lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMNOc.             .:kNMMMMW0o,         ..,:loxk0KKXXNNNWWWNNNNXKK0kxol:,..                      .cONMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMNk;.             .;ONMMMMXx;.      .,cdkKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKOdc;.                    ,oKWMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMNk;               ,kNMMMW0l.     ':dOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOd:'                  .cOWMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMWO:               .dXMMMW0c.   .;oONWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;.                .:ONMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMWKc.               :0WMMWKl.  .;dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNWMMMMMMMMMMWKx:.               .:OWMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMNx.               .dNMMMXd.  ,o0WMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0kxOXWMMMMMMMMWKd;.              .cKWMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMW0:                ,OWMMWO, .:kNMMMMMMMMMMMMMMMMMMMMMMWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMWXxc,:d0NMMMMMMMMNOc.              .xNMMMMMMMMMMMMMM
    MMMMMMMMMMMMMNx.                :KMMMXo..c0WMMMMMMMMMMMMMMMMMMMMXxl:;,;;:codkKNMMMMMMMMMMMMMMMMMMMMMMNk;..,o0WMMMMMMMWKo.              :KMMMMMMMMMMMMM
    MMMMMMMMMMMMXl.                cXMMW0:.c0WMMMMMMMMMMMMWWNNXXXNNWXd'..;;'..   .,lkNMMW00NMMMMMMMMMMMMMMMNk;  .;dKWMMMMMMWKo.             'kWMMMMMMMMMMM
    MMMMMMMMMMMK:                 cXMMWk;;OWMMMMMMMMMN0xoc;,'.....';cll'.oKNX0xol,   ,xXNc.,xXMMMMMMMMMMMMMMMNx'   .l0WMMMMMMWKl.            .dNMMMMMMMMMM
    MMMMMMMMMM0;                 cXMMWk:dXMMMMMMMMW0o,.  ..,:clllllcc:;,..;0WMMMMNO:.  ;Ol.  ;0MMMMMMMMMMMMMMMMXl.   .:OWMMMMMMWO;            .lNMMMMMMMMM
    MMMMMMMMM0,                 ;KMMWklkNWMMMMMMMKl.     .';coxOXWMMMMWNKOdxKWMMMMMWk,  .:l:  ,0MMMMMMMMMMMMMMMMWO,    .c0WMMMMMMXo.            lXMMMMMMMM
    MMMMMMMM0,                 '0MMNx,''lXMMMMMWk'   .,cdxkkkxdxxOKXWMMMMMMWNXNMMMMMM0,  .kK;  cNMMMMMMN0XMMMMMMMMKc     .oXMMMMMMWO,            lNMMMMMMM
    MMMMMMM0;                 .xWMKc. . .kWMMMNd.  .l0NMMMMMMMMMMWNXNWMMMMMMMWNNWMMMMMk. 'OWd. .OMMMMXx:oXMMMMMMMMMNo.     ,kWMMMMMMK:           .dWMMMMMM
    MMMMMMX:                  cXM0; .l0o..:ool,  .lKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX; ;XMO. .dWWKo'.:KMMMMMMMMMMMWx.     .oXMMMMMMXc           .kWMMMMM
    MMMMMNl                  .OMX: .oNMWOc'...':dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNc.dWMO.  lOl.  ,0MMMMMMMMMMMMMWx.      :KMMMMMMXl           ;KMMMMM
    MMMMWx.                  lNMx. ;XMMMMMNXKXNWMWNWMMMMMMMMMMMMMMMXO0WMMMMMMMMMMMMMMMK::XMWx.  ...'.'OMMMMMMMMMMMMMMMWd.      ;0MMMMMMXc           oWMMMM
    MMMMK,                  .kMNl  cNMMMMMMMWNX0kxONMMMMMMMMMMMMMMWd..,cok0NWMMMMMMMMM0xKMMX;   .cd;'kWMMMMMMMMMMMMMMMMNo       ,0MMMMMMK:          '0MMMM
    MMMWo                   .cl:. .,ooolllllc::ld0WMMMMMMMMMMMMMMMNl      .':oOXNMMMMMWMMWO:  ;d00:.xWMMMMMMMMMMMMMMMMMMX:       ;KMMMMMM0'          oWMMM
    MMM0'                    .':ok0KKK0OkxxkOKNWMMMMMMMMMMMMMMMMMMWo          ..;OWMMMMWO:.  ,OWK:.dWMMMMMMMMMMMMMMMMMMMMO'       :XMMMMMWd.         ,KMMM
    MMWo                   .l0NWMMMMMMMMMMMMMMMMMMMMMMMMWXKWMMMMW0o'             .kWMWO:. .cOOOO:.oNMMMMMMMMMNXWMMMMMMMMMWo       .oWMMMMMX:         .kMMM
    MMK,                   .OMMMMMMMMMMMMMMMMMMMMMMMMN0d:.cXMMMKc.                .ok:. ..;KMMX:.lNMMMMMMMMMWxlKMMMMMMMMMM0,       'OMMMMMWk.         oWMM
    MMx.                   'OXXNMMMMMMMMMMMMMMMMMWXkl,.   lWMWO'                       ,O0dd0Kc .kMMMMMMMMMWk' cXMMMMMMMMMWl        lNMMMMMX;         cNMM
    MNl                    .dOKNMMMMMMMMMMMMMMWKxc.       lWM0,                        'xXWN0:   ;0MMMWN0xl,.   'cdOXWMMMMMk.       'OMMMMMWd.        ;XMM
    MX;                    ;XMMMMMMMMNOkXMMWKx;.          ,KWo                           .:c,     ;KMMWN0ko;.   'cdOXWMMMMMK,        dWMMMMMO.        ,KMM
    M0'                    ,KMMMMXKN0:.oWW0c.              ;d;                                     lNMMMMMMWO'.dNMMMMMMMMMMNc        :XMMMMMK,        ;KMM
    MO.                    '0MMM0lkO, 'ONd.                                                        .oNMMMMMMWkdNMMMMMMMMMMMWo        ,KMMMMMX:        ;XMM
    Mk.                    .OMM0,,x;  ;Ol                                     ..',.                 ;KMMMMMMMNNMMMMMMMMMMMMWo        '0MMMMMNc        cNMM
    Mx.                    .dW0, ,:.  ,c.                                      .:0Xk:.              lNMMMMMMMMMMMMMMMMMMMMMWo        .OMMMMMNc        oWMM
    Mk.                     c0:  ..    .                                      .,xOd0NO;            '0MMMMMMMMMMMMMWWMMMMMMMWo        .OMMMMMN:       .kMMM
    Mk.                     .:.                     .,.                       .cx: .lKXl           lWMMMMMMMMMMMWNxlONMMMMMNc        '0MMMMMX;       ;XMMM
    M0'                                           .:c.                      .. .,:;,,l0Xl         .xMMMMMMMMMMMWNk,.:ONMMMMX;        ;XMMMMM0'      .dWMMM
    MK;                                          'dl.                        .....''',:k0d;.       oWMMMMMMMMMMMMWOo0MMMMMMO.        oWMMMMMx.      ,KMMMM
    MNc                                         :kl.                           ......   ,c;.       :XMMMMMMMMMMMMMWWWMMMMMWo        .kMMMMMNc      .dWMMMM
    MWd.                                       c0l.                                                .OMMMMMMMMMMMMMMMMMMMMMK;        :XMMMMMO'      :XMMMMM
    MM0'                                      :0d.                                         .        lNMMMMMMMMMMMMMMMMMMMWd.       .kMMMMMNl      '0MMMMMM
    MMNl                                     '0k.                    ..                    'c.      .OMMMMMMMMMMMMMMMMMMM0,        lNMMMMMO.     .kWMMMMMM
    MMMO.                                   .dK;                    ;0O;                    :d'      ;KMMMMMMMMMMMMMMMMMNl        ,KMMMMMX:     .xWMMMWXNM
    MMMNc                                   ,0d.                   .OMMNk:.                 .x0xo,    cXMMMMMMMMMMMMMMMWd.       'OMMMMMNo     .dWMMMWOkNM
    MMMMO'                                  c0;                   .dWMMMMW0l.                ;dooxl.   :0WMMMMMMMMMMMMWk.       .kWMMMMWx.    .xWMMMWxc0MM
    MMMMWd.                                 ok.                   :XMMMMMMMWO,                  .:dc    'OWMMMMMMMMMMWO'       .kWMMMMWk.    'kWMMMNo,dWMM
    MMMMMX:                                 cd.                  .kWMMMMMMMMWk.         ..      .,cc.    :XMMMMMMMMMWk'       'OWMMMMWk.    :0MMMMKc.cXMMM
    MMMMMM0,                                .'.                  :XMMMMMMMMMMNc      'c;ll.       ..     .OMMMMMMMMWx.       :KMMMMMNx.   .oNMMMWO, ;KMMMM
    MMMMMMWO'                                                   .xWMMMMMMMMMMMk:.    ,0KOOc              .OMMMMMMMNo.      .oXMMMMMXo.   ;OWMMMXl. 'OMMMMM
    MMMMMMMWk.                                                  ,0MMMMMMMMMMMMX0:     .:d00l.            lNMMMMMW0:       ;OWMMMMW0:   'xNMMMNk,  'OWMMMMM
    MMMMMMMMWx.                                                 :XMMMMMNNMMMMMMWk.       .',.          'xNMMMMMNx.      ,xNMMMMMNx.  .oXMMMWO:.  'OWMMMMMM
    MMMMMMMMMWk.                                                cNMMMMNdxNMMMMMMWO:.                .;xXMMMMMWO:      'dXMMMMMWO;  .oKWMMW0c.   'OWMMMMMMM
    MMMMMMMMMMWO,                                               cNWNKk:..:kKNWMMMMWKxc'.         .,oONMMMMMW0c.    .;xXMMMMMWKl..,dXWMMNOc.    ;0WMMMMMMMM
    MMMMMMMMMMMMK:                                              cNWN0o'  'oONWMMMMMMMWN0dc;''';lxKNMMMMMMW0l.    .cONMMMMMWKl'.ckNMMMNk;.     cKMMMMMMMMMM
    MMMMMMMMMMMMMXo.                                            cNMMMMKccKMMMMMMMMMMMMMMMMWNNNWMMMMMMMMNOc.   .:xXWMMMMMWOl;:dKWMMW0o'      .dNMMMMMMMMMMM
    MMMMMMMMMMMMMMWk'                                           lNMMMMMXXMMMMMMMMMMMMMMMMMMMMMMMMMMMWKx;. .,lkXWMMMMMWXOdoxKWMMWKd;.       ;OWMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMKl.                                         oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkc,';lxKNMMMMMMMWX0OOXWMMN0d;.        .oXMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMWk;                                        lXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOxdxOXWMMMMMMMMMMMWNWMMWKxl,.         .:0WMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMXd'                                       .:ok0NWMMMMMMMMMMMMMMMMMMMMMMMWNWWMMMMMMMMMMMMMMMMWX0xl,.            ,kNMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMXo.                                         .':ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKOdc;..              'xNMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMWKo'                                             .';ccldxO0KXXNWWWWWWWWWNNXKKOkxol:,..                  ,xXMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMWXd,                                                    ....',,,,,,,,,'....                        .;kNMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMNk:.                                                                                          .l0WMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKo,.                                                                                    .:xXWMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo,                                                                               .;dKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;.                                                                        .:xKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'.                                                                .;oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0xl;.                                                       .':oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOdl;'.                                           ..,cokKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKOxoc;,...                          ..';:ldk0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWXK0Okxdollcccc:::cccclloddkO0KXNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
        ███╗   ███╗ ██████╗  ██████╗ ███╗   ██╗██╗███████╗██╗    ██╗ █████╗ ██████╗ ███████╗██╗  ██╗ ██████╗██╗  ██╗ █████╗ ███╗   ██╗ ██████╗ ███████╗
        ████╗ ████║██╔═══██╗██╔═══██╗████╗  ██║██║██╔════╝██║    ██║██╔══██╗██╔══██╗██╔════╝╚██╗██╔╝██╔════╝██║  ██║██╔══██╗████╗  ██║██╔════╝ ██╔════╝
        ██╔████╔██║██║   ██║██║   ██║██╔██╗ ██║██║███████╗██║ █╗ ██║███████║██████╔╝█████╗   ╚███╔╝ ██║     ███████║███████║██╔██╗ ██║██║  ███╗█████╗
        ██║╚██╔╝██║██║   ██║██║   ██║██║╚██╗██║██║╚════██║██║███╗██║██╔══██║██╔═══╝ ██╔══╝   ██╔██╗ ██║     ██╔══██║██╔══██║██║╚██╗██║██║   ██║██╔══╝
        ██║ ╚═╝ ██║╚██████╔╝╚██████╔╝██║ ╚████║██║███████║╚███╔███╔╝██║  ██║██║██╗  ███████╗██╔╝ ██╗╚██████╗██║  ██║██║  ██║██║ ╚████║╚██████╔╝███████╗
        ╚═╝     ╚═╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚═╝╚══════╝ ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝╚═╝  ╚══════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝
    
                                                        ██████╗ ██╗   ██╗     ██╗██╗███╗   ██╗ ██████╗██╗  ██╗
                                                        ██╔══██╗╚██╗ ██╔╝    ███║██║████╗  ██║██╔════╝██║  ██║
                                                        ██████╔╝ ╚████╔╝     ╚██║██║██╔██╗ ██║██║     ███████║
                                                        ██╔══██╗  ╚██╔╝       ██║██║██║╚██╗██║██║     ██╔══██║
                                                        ██████╔╝   ██║        ██║██║██║ ╚████║╚██████╗██║  ██║
                                                        ╚═════╝    ╚═╝        ╚═╝╚═╝╚═╝  ╚═══╝ ╚═════╝╚═╝  ╚═╝
    */
    // File: @openzeppelin/contracts/GSN/Context.sol
    
    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.6.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.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    // File: @openzeppelin/contracts/access/Ownable.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            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 virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    // File: @openzeppelin/contracts/utils/ReentrancyGuard.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
    
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
    
        uint256 private _status;
    
        constructor () internal {
            _status = _NOT_ENTERED;
        }
    
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and make it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            // On the first call to nonReentrant, _notEntered will be true
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
    
            // Any calls to nonReentrant after this point will fail
            _status = _ENTERED;
    
            _;
    
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = _NOT_ENTERED;
        }
    }
    
    // File: @openzeppelin/contracts/math/Math.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a >= b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
        }
    }
    
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    
    pragma solidity ^0.6.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.
         */
        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.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            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.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    
    pragma solidity ^0.6.2;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
    
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
    
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
    
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/ERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    /**
     * @dev Implementation of the {IERC20} interface.
     *
     * This implementation is agnostic to the way tokens are created. This means
     * that a supply mechanism has to be added in a derived contract using {_mint}.
     * For a generic mechanism see {ERC20PresetMinterPauser}.
     *
     * TIP: For a detailed writeup see our guide
     * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * We have followed general OpenZeppelin guidelines: functions revert instead
     * of returning `false` on failure. This behavior is nonetheless conventional
     * and does not conflict with the expectations of ERC20 applications.
     *
     * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
     * This allows applications to reconstruct the allowance for all accounts just
     * by listening to said events. Other implementations of the EIP may not emit
     * these events, as it isn't required by the specification.
     *
     * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
     * functions have been added to mitigate the well-known issues around setting
     * allowances. See {IERC20-approve}.
     */
    contract ERC20 is Context, IERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        mapping (address => uint256) private _balances;
    
        mapping (address => mapping (address => uint256)) private _allowances;
    
        uint256 private _totalSupply;
    
        string private _name;
        string private _symbol;
        uint8 private _decimals;
    
        /**
         * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
         * a default value of 18.
         *
         * To select a different value for {decimals}, use {_setupDecimals}.
         *
         * All three of these values are immutable: they can only be set once during
         * construction.
         */
        constructor (string memory name, string memory symbol) public {
            _name = name;
            _symbol = symbol;
            _decimals = 18;
        }
    
        /**
         * @dev Returns the name of the token.
         */
        function name() public view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev Returns the number of decimals used to get its user representation.
         * For example, if `decimals` equals `2`, a balance of `505` tokens should
         * be displayed to a user as `5,05` (`505 / 10 ** 2`).
         *
         * Tokens usually opt for a value of 18, imitating the relationship between
         * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
         * called.
         *
         * NOTE: This information is only used for _display_ purposes: it in
         * no way affects any of the arithmetic of the contract, including
         * {IERC20-balanceOf} and {IERC20-transfer}.
         */
        function decimals() public view returns (uint8) {
            return _decimals;
        }
    
        /**
         * @dev See {IERC20-totalSupply}.
         */
        function totalSupply() public view override returns (uint256) {
            return _totalSupply;
        }
    
        /**
         * @dev See {IERC20-balanceOf}.
         */
        function balanceOf(address account) public view override returns (uint256) {
            return _balances[account];
        }
    
        /**
         * @dev See {IERC20-transfer}.
         *
         * Requirements:
         *
         * - `recipient` cannot be the zero address.
         * - the caller must have a balance of at least `amount`.
         */
        function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-allowance}.
         */
        function allowance(address owner, address spender) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        /**
         * @dev See {IERC20-approve}.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-transferFrom}.
         *
         * Emits an {Approval} event indicating the updated allowance. This is not
         * required by the EIP. See the note at the beginning of {ERC20};
         *
         * Requirements:
         * - `sender` and `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         * - the caller must have allowance for ``sender``'s tokens of at least
         * `amount`.
         */
        function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
    
        /**
         * @dev Atomically increases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
            return true;
        }
    
        /**
         * @dev Atomically decreases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         * - `spender` must have allowance for the caller of at least
         * `subtractedValue`.
         */
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
            return true;
        }
    
        /**
         * @dev Moves tokens `amount` from `sender` to `recipient`.
         *
         * This is internal function is equivalent to {transfer}, and can be used to
         * e.g. implement automatic token fees, slashing mechanisms, etc.
         *
         * Emits a {Transfer} event.
         *
         * Requirements:
         *
         * - `sender` cannot be the zero address.
         * - `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         */
        function _transfer(address sender, address recipient, uint256 amount) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
    
            _beforeTokenTransfer(sender, recipient, amount);
    
            _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
    
        /** @dev Creates `amount` tokens and assigns them to `account`, increasing
         * the total supply.
         *
         * Emits a {Transfer} event with `from` set to the zero address.
         *
         * Requirements
         *
         * - `to` cannot be the zero address.
         */
        function _mint(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: mint to the zero address");
    
            _beforeTokenTransfer(address(0), account, amount);
    
            _totalSupply = _totalSupply.add(amount);
            _balances[account] = _balances[account].add(amount);
            emit Transfer(address(0), account, amount);
        }
    
        /**
         * @dev Destroys `amount` tokens from `account`, reducing the
         * total supply.
         *
         * Emits a {Transfer} event with `to` set to the zero address.
         *
         * Requirements
         *
         * - `account` cannot be the zero address.
         * - `account` must have at least `amount` tokens.
         */
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
    
            _beforeTokenTransfer(account, address(0), amount);
    
            _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
            _totalSupply = _totalSupply.sub(amount);
            emit Transfer(account, address(0), amount);
        }
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
         *
         * This is internal function is equivalent to `approve`, and can be used to
         * e.g. set automatic allowances for certain subsystems, etc.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `owner` cannot be the zero address.
         * - `spender` cannot be the zero address.
         */
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        /**
         * @dev Sets {decimals} to a value other than the default one of 18.
         *
         * WARNING: This function should only be called from the constructor. Most
         * applications that interact with token contracts will not expect
         * {decimals} to ever change, and may work incorrectly if it does.
         */
        function _setupDecimals(uint8 decimals_) internal {
            _decimals = decimals_;
        }
    
        /**
         * @dev Hook that is called before any transfer of tokens. This includes
         * minting and burning.
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * will be to transferred to `to`.
         * - when `from` is zero, `amount` tokens will be minted for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
         * - `from` and `to` are never both zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
    
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
    
        /**
         * @dev Deprecated. This function has issues similar to the ones found in
         * {IERC20-approve}, and its usage is discouraged.
         *
         * Whenever possible, use {safeIncreaseAllowance} and
         * {safeDecreaseAllowance} instead.
         */
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
    
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
            // the target address contains contract code and also asserts for success in the low-level call.
    
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    
    // File: contracts/libraries/UniERC20.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    library UniERC20 {
        using SafeMath for uint256;
        using SafeERC20 for IERC20;
    
        function isETH(IERC20 token) internal pure returns(bool) {
            return (address(token) == address(0));
        }
    
        function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) {
            if (isETH(token)) {
                return account.balance;
            } else {
                return token.balanceOf(account);
            }
        }
    
        function uniTransfer(IERC20 token, address payable to, uint256 amount) internal {
            if (amount > 0) {
                if (isETH(token)) {
                    to.transfer(amount);
                } else {
                    token.safeTransfer(to, amount);
                }
            }
        }
    
        function uniTransferFromSenderToThis(IERC20 token, uint256 amount) internal {
            if (amount > 0) {
                if (isETH(token)) {
                    require(msg.value >= amount, "UniERC20: not enough value");
                    if (msg.value > amount) {
                        // Return remainder if exist
                        msg.sender.transfer(msg.value.sub(amount));
                    }
                } else {
                    token.safeTransferFrom(msg.sender, address(this), amount);
                }
            }
        }
    
        function uniSymbol(IERC20 token) internal view returns(string memory) {
            if (isETH(token)) {
                return "ETH";
            }
    
            (bool success, bytes memory data) = address(token).staticcall{ gas: 20000 }(
                abi.encodeWithSignature("symbol()")
            );
            if (!success) {
                (success, data) = address(token).staticcall{ gas: 20000 }(
                    abi.encodeWithSignature("SYMBOL()")
                );
            }
    
            if (success && data.length >= 96) {
                (uint256 offset, uint256 len) = abi.decode(data, (uint256, uint256));
                if (offset == 0x20 && len > 0 && len <= 256) {
                    return string(abi.decode(data, (bytes)));
                }
            }
    
            if (success && data.length == 32) {
                uint len = 0;
                while (len < data.length && data[len] >= 0x20 && data[len] <= 0x7E) {
                    len++;
                }
    
                if (len > 0) {
                    bytes memory result = new bytes(len);
                    for (uint i = 0; i < len; i++) {
                        result[i] = data[i];
                    }
                    return string(result);
                }
            }
    
            return _toHex(address(token));
        }
    
        function _toHex(address account) private pure returns(string memory) {
            return _toHex(abi.encodePacked(account));
        }
    
        function _toHex(bytes memory data) private pure returns(string memory) {
            bytes memory str = new bytes(2 + data.length * 2);
            str[0] = "0";
            str[1] = "x";
            uint j = 2;
            for (uint i = 0; i < data.length; i++) {
                uint a = uint8(data[i]) >> 4;
                uint b = uint8(data[i]) & 0x0f;
                str[j++] = byte(uint8(a + 48 + (a/10)*39));
                str[j++] = byte(uint8(b + 48 + (b/10)*39));
            }
    
            return string(str);
        }
    }
    
    // File: contracts/libraries/Sqrt.sol
    
    
    pragma solidity ^0.6.0;
    
    
    library Sqrt {
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint256 y) internal pure returns (uint256) {
            if (y > 3) {
                uint256 z = y;
                uint256 x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
                return z;
            } else if (y != 0) {
                return 1;
            } else {
                return 0;
            }
        }
    }
    
    // File: contracts/Mooniswap.sol
    
    
    pragma solidity ^0.6.0;
    
    
    
    
    
    
    
    
    
    interface IFactory {
        function fee() external view returns(uint256);
    }
    
    
    library VirtualBalance {
        using SafeMath for uint256;
    
        struct Data {
            uint216 balance;
            uint40 time;
        }
    
        uint256 public constant DECAY_PERIOD = 5 minutes;
    
        function set(VirtualBalance.Data storage self, uint256 balance) internal {
            self.balance = uint216(balance);
            self.time = uint40(block.timestamp);
        }
    
        function update(VirtualBalance.Data storage self, uint256 realBalance) internal {
            set(self, current(self, realBalance));
        }
    
        function scale(VirtualBalance.Data storage self, uint256 realBalance, uint256 num, uint256 denom) internal {
            set(self, current(self, realBalance).mul(num).add(denom.sub(1)).div(denom));
        }
    
        function current(VirtualBalance.Data memory self, uint256 realBalance) internal view returns(uint256) {
            uint256 timePassed = Math.min(DECAY_PERIOD, block.timestamp.sub(self.time));
            uint256 timeRemain = DECAY_PERIOD.sub(timePassed);
            return uint256(self.balance).mul(timeRemain).add(
                realBalance.mul(timePassed)
            ).div(DECAY_PERIOD);
        }
    }
    
    
    contract Mooniswap is ERC20, ReentrancyGuard, Ownable {
        using Sqrt for uint256;
        using SafeMath for uint256;
        using UniERC20 for IERC20;
        using VirtualBalance for VirtualBalance.Data;
    
        struct Balances {
            uint256 src;
            uint256 dst;
        }
    
        struct SwapVolumes {
            uint128 confirmed;
            uint128 result;
        }
    
        event Deposited(
            address indexed account,
            uint256 amount
        );
    
        event Withdrawn(
            address indexed account,
            uint256 amount
        );
    
        event Swapped(
            address indexed account,
            address indexed src,
            address indexed dst,
            uint256 amount,
            uint256 result,
            uint256 srcBalance,
            uint256 dstBalance,
            uint256 totalSupply,
            address referral
        );
    
        uint256 public constant REFERRAL_SHARE = 20; // 1/share = 5% of LPs revenue
        uint256 public constant BASE_SUPPLY = 1000;  // Total supply on first deposit
        uint256 public constant FEE_DENOMINATOR = 1e18;
    
        IFactory public factory;
        IERC20[] public tokens;
        mapping(IERC20 => bool) public isToken;
        mapping(IERC20 => SwapVolumes) public volumes;
        mapping(IERC20 => VirtualBalance.Data) public virtualBalancesForAddition;
        mapping(IERC20 => VirtualBalance.Data) public virtualBalancesForRemoval;
    
        constructor(IERC20[] memory assets, string memory name, string memory symbol) public ERC20(name, symbol) {
            require(bytes(name).length > 0, "Mooniswap: name is empty");
            require(bytes(symbol).length > 0, "Mooniswap: symbol is empty");
            require(assets.length == 2, "Mooniswap: only 2 tokens allowed");
    
            factory = IFactory(msg.sender);
            tokens = assets;
            for (uint i = 0; i < assets.length; i++) {
                require(!isToken[assets[i]], "Mooniswap: duplicate tokens");
                isToken[assets[i]] = true;
            }
        }
    
        function fee() public view returns(uint256) {
            return factory.fee();
        }
    
        function getTokens() external view returns(IERC20[] memory) {
            return tokens;
        }
    
        function decayPeriod() external pure returns(uint256) {
            return VirtualBalance.DECAY_PERIOD;
        }
    
        function getBalanceForAddition(IERC20 token) public view returns(uint256) {
            uint256 balance = token.uniBalanceOf(address(this));
            return Math.max(virtualBalancesForAddition[token].current(balance), balance);
        }
    
        function getBalanceForRemoval(IERC20 token) public view returns(uint256) {
            uint256 balance = token.uniBalanceOf(address(this));
            return Math.min(virtualBalancesForRemoval[token].current(balance), balance);
        }
    
        function getReturn(IERC20 src, IERC20 dst, uint256 amount) external view returns(uint256) {
            return _getReturn(src, dst, amount, getBalanceForAddition(src), getBalanceForRemoval(dst));
        }
    
        function deposit(uint256[] calldata amounts, uint256[] calldata minAmounts) external payable nonReentrant returns(uint256 fairSupply) {
            IERC20[] memory _tokens = tokens;
            require(amounts.length == _tokens.length, "Mooniswap: wrong amounts length");
            require(msg.value == (_tokens[0].isETH() ? amounts[0] : (_tokens[1].isETH() ? amounts[1] : 0)), "Mooniswap: wrong value usage");
    
            uint256[] memory realBalances = new uint256[](amounts.length);
            for (uint i = 0; i < realBalances.length; i++) {
                realBalances[i] = _tokens[i].uniBalanceOf(address(this)).sub(_tokens[i].isETH() ? msg.value : 0);
            }
    
            uint256 totalSupply = totalSupply();
            if (totalSupply == 0) {
                fairSupply = BASE_SUPPLY.mul(99);
                _mint(address(this), BASE_SUPPLY); // Donate up to 1%
    
                // Use the greatest token amount but not less than 99k for the initial supply
                for (uint i = 0; i < amounts.length; i++) {
                    fairSupply = Math.max(fairSupply, amounts[i]);
                }
            }
            else {
                // Pre-compute fair supply
                fairSupply = type(uint256).max;
                for (uint i = 0; i < amounts.length; i++) {
                    fairSupply = Math.min(fairSupply, totalSupply.mul(amounts[i]).div(realBalances[i]));
                }
            }
    
            uint256 fairSupplyCached = fairSupply;
            for (uint i = 0; i < amounts.length; i++) {
                require(amounts[i] > 0, "Mooniswap: amount is zero");
                uint256 amount = (totalSupply == 0) ? amounts[i] :
                    realBalances[i].mul(fairSupplyCached).add(totalSupply - 1).div(totalSupply);
                require(amount >= minAmounts[i], "Mooniswap: minAmount not reached");
    
                _tokens[i].uniTransferFromSenderToThis(amount);
                if (totalSupply > 0) {
                    uint256 confirmed = _tokens[i].uniBalanceOf(address(this)).sub(realBalances[i]);
                    fairSupply = Math.min(fairSupply, totalSupply.mul(confirmed).div(realBalances[i]));
                }
            }
    
            if (totalSupply > 0) {
                for (uint i = 0; i < amounts.length; i++) {
                    virtualBalancesForRemoval[_tokens[i]].scale(realBalances[i], totalSupply.add(fairSupply), totalSupply);
                    virtualBalancesForAddition[_tokens[i]].scale(realBalances[i], totalSupply.add(fairSupply), totalSupply);
                }
            }
    
            require(fairSupply > 0, "Mooniswap: result is not enough");
            _mint(msg.sender, fairSupply);
    
            emit Deposited(msg.sender, fairSupply);
        }
    
        function withdraw(uint256 amount, uint256[] memory minReturns) external nonReentrant {
            uint256 totalSupply = totalSupply();
            _burn(msg.sender, amount);
    
            for (uint i = 0; i < tokens.length; i++) {
                IERC20 token = tokens[i];
    
                uint256 preBalance = token.uniBalanceOf(address(this));
                uint256 value = preBalance.mul(amount).div(totalSupply);
                token.uniTransfer(msg.sender, value);
                require(i >= minReturns.length || value >= minReturns[i], "Mooniswap: result is not enough");
    
                virtualBalancesForAddition[token].scale(preBalance, totalSupply.sub(amount), totalSupply);
                virtualBalancesForRemoval[token].scale(preBalance, totalSupply.sub(amount), totalSupply);
            }
    
            emit Withdrawn(msg.sender, amount);
        }
    
        function swap(IERC20 src, IERC20 dst, uint256 amount, uint256 minReturn, address referral) external payable nonReentrant returns(uint256 result) {
            require(msg.value == (src.isETH() ? amount : 0), "Mooniswap: wrong value usage");
    
            Balances memory balances = Balances({
                src: src.uniBalanceOf(address(this)).sub(src.isETH() ? msg.value : 0),
                dst: dst.uniBalanceOf(address(this))
            });
    
            // catch possible airdrops and external balance changes for deflationary tokens
            uint256 srcAdditionBalance = Math.max(virtualBalancesForAddition[src].current(balances.src), balances.src);
            uint256 dstRemovalBalance = Math.min(virtualBalancesForRemoval[dst].current(balances.dst), balances.dst);
    
            src.uniTransferFromSenderToThis(amount);
            uint256 confirmed = src.uniBalanceOf(address(this)).sub(balances.src);
            result = _getReturn(src, dst, confirmed, srcAdditionBalance, dstRemovalBalance);
            require(result > 0 && result >= minReturn, "Mooniswap: return is not enough");
            dst.uniTransfer(msg.sender, result);
    
            // Update virtual balances to the same direction only at imbalanced state
            if (srcAdditionBalance != balances.src) {
                virtualBalancesForAddition[src].set(srcAdditionBalance.add(confirmed));
            }
            if (dstRemovalBalance != balances.dst) {
                virtualBalancesForRemoval[dst].set(dstRemovalBalance.sub(result));
            }
    
            // Update virtual balances to the opposite direction
            virtualBalancesForRemoval[src].update(balances.src);
            virtualBalancesForAddition[dst].update(balances.dst);
    
            if (referral != address(0)) {
                uint256 invariantRatio = uint256(1e36);
                invariantRatio = invariantRatio.mul(balances.src.add(confirmed)).div(balances.src);
                invariantRatio = invariantRatio.mul(balances.dst.sub(result)).div(balances.dst);
                if (invariantRatio > 1e36) {
                    // calculate share only if invariant increased
                    uint256 referralShare = invariantRatio.sqrt().sub(1e18).mul(totalSupply()).div(1e18).div(REFERRAL_SHARE);
                    if (referralShare > 0) {
                        _mint(referral, referralShare);
                    }
                }
            }
    
            emit Swapped(msg.sender, address(src), address(dst), confirmed, result, balances.src, balances.dst, totalSupply(), referral);
    
            // Overflow of uint128 is desired
            volumes[src].confirmed += uint128(confirmed);
            volumes[src].result += uint128(result);
        }
    
        function rescueFunds(IERC20 token, uint256 amount) external nonReentrant onlyOwner {
            uint256[] memory balances = new uint256[](tokens.length);
            for (uint i = 0; i < balances.length; i++) {
                balances[i] = tokens[i].uniBalanceOf(address(this));
            }
    
            token.uniTransfer(msg.sender, amount);
    
            for (uint i = 0; i < balances.length; i++) {
                require(tokens[i].uniBalanceOf(address(this)) >= balances[i], "Mooniswap: access denied");
            }
            require(balanceOf(address(this)) >= BASE_SUPPLY, "Mooniswap: access denied");
        }
    
        function _getReturn(IERC20 src, IERC20 dst, uint256 amount, uint256 srcBalance, uint256 dstBalance) internal view returns(uint256) {
            if (isToken[src] && isToken[dst] && src != dst && amount > 0) {
                uint256 taxedAmount = amount.sub(amount.mul(fee()).div(FEE_DENOMINATOR));
                return taxedAmount.mul(dstBalance).div(srcBalance.add(taxedAmount));
            }
        }
    }

    File 3 of 3: VotingToken
    {"ICommonUtilities.sol":{"content":"pragma solidity ^0.6.0;\r\n\r\ninterface ICommonUtilities {\r\n    function toString(address _addr) external pure returns(string memory);\r\n    function toString(uint _i) external pure returns(string memory);\r\n    function toUint256(bytes calldata bs) external pure returns(uint256 x);\r\n    function toAddress(bytes calldata b) external pure returns (address addr);\r\n    function compareStrings(string calldata a, string calldata b) external pure returns(bool);\r\n    function getFirstJSONPart(address sourceLocation, uint256 sourceLocationId, address location) external pure returns(bytes memory);\r\n    function formatReturnAbiParametersArray(string calldata m) external pure returns(string memory);\r\n    function toLowerCase(string calldata str) external pure returns(string memory);\r\n}"},"IERC20.sol":{"content":"pragma solidity ^0.6.0;\r\n\r\ninterface IERC20 {\r\n    function totalSupply() external view returns (uint256);\r\n    function balanceOf(address account) external view returns (uint256);\r\n    function transfer(address recipient, uint256 amount) external returns (bool);\r\n    function allowance(address owner, address spender) external view returns (uint256);\r\n    function approve(address spender, uint256 amount) external returns (bool);\r\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\r\n\r\n    event Transfer(address indexed from, address indexed to, uint256 value);\r\n    event Approval(address indexed owner, address indexed spender, uint256 value);\r\n}"},"IERC721.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IERC721 {\n    function ownerOf(uint256 _tokenId) external view returns (address);\n    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n}"},"IERC721Receiver.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IERC721Receiver {\n    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);\n}"},"IMVDFunctionalitiesManager.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IMVDFunctionalitiesManager {\n\n    function getProxy() external view returns (address);\n    function setProxy() external;\n\n    function init(address sourceLocation,\n        uint256 getMinimumBlockNumberSourceLocationId, address getMinimumBlockNumberFunctionalityAddress,\n        uint256 getEmergencyMinimumBlockNumberSourceLocationId, address getEmergencyMinimumBlockNumberFunctionalityAddress,\n        uint256 getEmergencySurveyStakingSourceLocationId, address getEmergencySurveyStakingFunctionalityAddress,\n        uint256 checkVoteResultSourceLocationId, address checkVoteResultFunctionalityAddress) external;\n\n    function addFunctionality(string calldata codeName, address sourceLocation, uint256 sourceLocationId, address location, bool submitable, string calldata methodSignature, string calldata returnAbiParametersArray, bool isInternal, bool needsSender) external;\n    function addFunctionality(string calldata codeName, address sourceLocation, uint256 sourceLocationId, address location, bool submitable, string calldata methodSignature, string calldata returnAbiParametersArray, bool isInternal, bool needsSender, uint256 position) external;\n    function removeFunctionality(string calldata codeName) external returns(bool removed, uint256 position);\n    function isValidFunctionality(address functionality) external view returns(bool);\n    function isAuthorizedFunctionality(address functionality) external view returns(bool);\n    function setCallingContext(address location) external returns(bool);\n    function clearCallingContext() external;\n    function getFunctionalityData(string calldata codeName) external view returns(address, uint256, string memory, address, uint256);\n    function hasFunctionality(string calldata codeName) external view returns(bool);\n    function getFunctionalitiesAmount() external view returns(uint256);\n    function functionalitiesToJSON() external view returns(string memory);\n    function functionalitiesToJSON(uint256 start, uint256 l) external view returns(string memory functionsJSONArray);\n    function functionalityNames() external view returns(string memory);\n    function functionalityNames(uint256 start, uint256 l) external view returns(string memory functionsJSONArray);\n    function functionalityToJSON(string calldata codeName) external view returns(string memory);\n\n    function preConditionCheck(string calldata codeName, bytes calldata data, uint8 submitable, address sender, uint256 value) external view returns(address location, bytes memory payload);\n\n    function setupFunctionality(address proposalAddress) external returns (bool);\n}"},"IMVDFunctionalityModelsManager.sol":{"content":"pragma solidity ^0.6.0;\r\n\r\ninterface IMVDFunctionalityModelsManager {\r\n    function init() external;\r\n    function checkWellKnownFunctionalities(string calldata codeName, bool submitable, string calldata methodSignature, string calldata returnAbiParametersArray, bool isInternal, bool needsSender, string calldata replaces) external view;\r\n}"},"IMVDFunctionalityProposal.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IMVDFunctionalityProposal {\n\n    function init(string calldata codeName, address location, string calldata methodSignature, string calldata returnAbiParametersArray, string calldata replaces, address proxy) external;\n    function setCollateralData(bool emergency, address sourceLocation, uint256 sourceLocationId, bool submitable, bool isInternal, bool needsSender, address proposer, uint256 votesHardCap) external;\n\n    function getProxy() external view returns(address);\n    function getCodeName() external view returns(string memory);\n    function isEmergency() external view returns(bool);\n    function getSourceLocation() external view returns(address);\n    function getSourceLocationId() external view returns(uint256);\n    function getLocation() external view returns(address);\n    function isSubmitable() external view returns(bool);\n    function getMethodSignature() external view returns(string memory);\n    function getReturnAbiParametersArray() external view returns(string memory);\n    function isInternal() external view returns(bool);\n    function needsSender() external view returns(bool);\n    function getReplaces() external view returns(string memory);\n    function getProposer() external view returns(address);\n    function getSurveyEndBlock() external view returns(uint256);\n    function getSurveyDuration() external view returns(uint256);\n    function isVotesHardCapReached() external view returns(bool);\n    function getVotesHardCapToReach() external view returns(uint256);\n    function toJSON() external view returns(string memory);\n    function getVote(address addr) external view returns(uint256 accept, uint256 refuse);\n    function getVotes() external view returns(uint256, uint256);\n    function start() external;\n    function disable() external;\n    function isDisabled() external view returns(bool);\n    function isTerminated() external view returns(bool);\n    function accept(uint256 amount) external;\n    function retireAccept(uint256 amount) external;\n    function moveToAccept(uint256 amount) external;\n    function refuse(uint256 amount) external;\n    function retireRefuse(uint256 amount) external;\n    function moveToRefuse(uint256 amount) external;\n    function retireAll() external;\n    function withdraw() external;\n    function terminate() external;\n    function set() external;\n\n    event Accept(address indexed voter, uint256 amount);\n    event RetireAccept(address indexed voter, uint256 amount);\n    event MoveToAccept(address indexed voter, uint256 amount);\n    event Refuse(address indexed voter, uint256 amount);\n    event RetireRefuse(address indexed voter, uint256 amount);\n    event MoveToRefuse(address indexed voter, uint256 amount);\n    event RetireAll(address indexed voter, uint256 amount);\n}"},"IMVDFunctionalityProposalManager.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IMVDFunctionalityProposalManager {\n    function newProposal(string calldata codeName, address location, string calldata methodSignature, string calldata returnAbiParametersArray, string calldata replaces) external returns(address);\n    function checkProposal(address proposalAddress) external;\n    function getProxy() external view returns (address);\n    function setProxy() external;\n    function isValidProposal(address proposal) external view returns (bool);\n}"},"IMVDProxy.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IMVDProxy {\n\n    function init(address votingTokenAddress, address functionalityProposalManagerAddress, address stateHolderAddress, address functionalityModelsManagerAddress, address functionalitiesManagerAddress, address walletAddress) external;\n\n    function getDelegates() external view returns(address,address,address,address,address,address);\n    function getToken() external view returns(address);\n    function getMVDFunctionalityProposalManagerAddress() external view returns(address);\n    function getStateHolderAddress() external view returns(address);\n    function getMVDFunctionalityModelsManagerAddress() external view returns(address);\n    function getMVDFunctionalitiesManagerAddress() external view returns(address);\n    function getMVDWalletAddress() external view returns(address);\n    function setDelegate(uint256 position, address newAddress) external returns(address oldAddress);\n    function changeProxy(address newAddress, bytes calldata initPayload) external;\n    function isValidProposal(address proposal) external view returns (bool);\n    function isAuthorizedFunctionality(address functionality) external view returns(bool);\n    function newProposal(string calldata codeName, bool emergency, address sourceLocation, uint256 sourceLocationId, address location, bool submitable, string calldata methodSignature, string calldata returnParametersJSONArray, bool isInternal, bool needsSender, string calldata replaces) external returns(address proposalAddress);\n    function startProposal(address proposalAddress) external;\n    function disableProposal(address proposalAddress) external;\n    function transfer(address receiver, uint256 value, address token) external;\n    function transfer721(address receiver, uint256 tokenId, bytes calldata data, bool safe, address token) external;\n    function flushToWallet(address tokenAddress, bool is721, uint256 tokenId) external;\n    function setProposal() external;\n    function read(string calldata codeName, bytes calldata data) external view returns(bytes memory returnData);\n    function submit(string calldata codeName, bytes calldata data) external payable returns(bytes memory returnData);\n    function callFromManager(address location, bytes calldata payload) external returns(bool, bytes memory);\n    function emitFromManager(string calldata codeName, address proposal, string calldata replaced, address replacedSourceLocation, uint256 replacedSourceLocationId, address location, bool submitable, string calldata methodSignature, bool isInternal, bool needsSender, address proposalAddress) external;\n\n    function emitEvent(string calldata eventSignature, bytes calldata firstIndex, bytes calldata secondIndex, bytes calldata data) external;\n\n    event ProxyChanged(address indexed newAddress);\n    event DelegateChanged(uint256 position, address indexed oldAddress, address indexed newAddress);\n\n    event Proposal(address proposal);\n    event ProposalCheck(address indexed proposal);\n    event ProposalSet(address indexed proposal, bool success);\n    event FunctionalitySet(string codeName, address indexed proposal, string replaced, address replacedSourceLocation, uint256 replacedSourceLocationId, address indexed replacedLocation, bool replacedWasSubmitable, string replacedMethodSignature, bool replacedWasInternal, bool replacedNeededSender, address indexed replacedProposal);\n\n    event Event(string indexed key, bytes32 indexed firstIndex, bytes32 indexed secondIndex, bytes data);\n}"},"IMVDWallet.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IMVDWallet {\n\n    function getProxy() external view returns (address);\n\n    function setProxy() external;\n\n    function setNewWallet(address payable newWallet, address tokenAddress) external;\n\n    function transfer(address receiver, uint256 value, address tokenAddress) external;\n    \n    function transfer(address receiver, uint256 tokenId, bytes calldata data, bool safe, address token) external;\n\n    function flushToNewWallet(address token) external;\n\n    function flush721ToNewWallet(uint256 tokenId, bytes calldata data, bool safe, address tokenAddress) external;\n}"},"IStateHolder.sol":{"content":"pragma solidity ^0.6.0;\n\ninterface IStateHolder {\n\n    function init() external;\n\n    function getProxy() external view returns (address);\n    function setProxy() external;\n    function toJSON() external view returns(string memory);\n    function toJSON(uint256 start, uint256 l) external view returns(string memory);\n    function getStateSize() external view returns (uint256);\n    function exists(string calldata varName) external view returns(bool);\n    function getDataType(string calldata varName) external view returns(string memory dataType);\n    function clear(string calldata varName) external returns(string memory oldDataType, bytes memory oldVal);\n    function setBytes(string calldata varName, bytes calldata val) external returns(bytes memory);\n    function getBytes(string calldata varName) external view returns(bytes memory);\n    function setString(string calldata varName, string calldata val) external returns(string memory);\n    function getString(string calldata varName) external view returns (string memory);\n    function setBool(string calldata varName, bool val) external returns(bool);\n    function getBool(string calldata varName) external view returns (bool);\n    function getUint256(string calldata varName) external view returns (uint256);\n    function setUint256(string calldata varName, uint256 val) external returns(uint256);\n    function getAddress(string calldata varName) external view returns (address);\n    function setAddress(string calldata varName, address val) external returns (address);\n}"},"IVotingToken.sol":{"content":"pragma solidity ^0.6.0;\r\n\r\ninterface IVotingToken {\r\n    function init(string calldata name, string calldata symbol, uint256 decimals, uint256 totalSupply) external;\r\n\r\n    function getProxy() external view returns (address);\r\n    function setProxy() external;\r\n\r\n    function name() external view returns(string memory);\r\n    function symbol() external view returns(string memory);\r\n    function decimals() external view returns(uint256);\r\n\r\n    function mint(uint256 amount) external;\r\n    function burn(uint256 amount) external;\r\n\r\n    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\r\n    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\r\n}"},"VotingToken.sol":{"content":"pragma solidity ^0.6.0;\n\nimport \"./IMVDProxy.sol\";\nimport \"./IERC20.sol\";\nimport \"./IVotingToken.sol\";\nimport \"./IMVDFunctionalityProposalManager.sol\";\nimport \"./IMVDFunctionalitiesManager.sol\";\n\ncontract VotingToken is IERC20, IVotingToken {\n\n    mapping (address =\u003e uint256) private _balances;\n\n    mapping (address =\u003e mapping (address =\u003e uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n    uint256 private _decimals;\n    address private _proxy;\n    string private _name;\n    string private _symbol;\n\n    constructor(string memory name, string memory symbol, uint256 decimals, uint256 totalSupply) public {\n        if(totalSupply == 0) {\n            return;\n        }\n        init(name, symbol, decimals, totalSupply);\n    }\n\n    function init(string memory name, string memory symbol, uint256 decimals, uint256 totalSupply) public override {\n        require(_totalSupply == 0, \"Init already called!\");\n\n        _name = name;\n        _symbol = symbol;\n        _decimals = decimals;\n        _totalSupply = totalSupply * (10 ** decimals);\n        _balances[msg.sender] = _totalSupply;\n        emit Transfer(address(this), msg.sender, _totalSupply);\n    }\n\n    receive() external payable {\n        revert(\"ETH not accepted\");\n    }\n\n    function getProxy() public override view returns(address) {\n        return _proxy;\n    }\n\n    function name() public override view returns(string memory) {\n        return _name;\n    }\n\n    function symbol() public override view returns(string memory) {\n        return _symbol;\n    }\n\n    function decimals() public override view returns(uint256) {\n        return _decimals;\n    }\n\n    function totalSupply() public override view returns (uint256) {\n        return _totalSupply;\n    }\n\n    function balanceOf(address account) public override view returns (uint256) {\n        return _balances[account];\n    }\n\n    function transfer(address recipient, uint256 amount) public override returns (bool) {\n        _transfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    function allowance(address owner, address spender) public override view returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    function approve(address spender, uint256 amount) public override returns (bool) {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {\n        _transfer(sender, recipient, amount);\n        address txSender = msg.sender;\n        if(_proxy == address(0) || !(IMVDFunctionalityProposalManager(IMVDProxy(_proxy).getMVDFunctionalityProposalManagerAddress()).isValidProposal(txSender) \u0026\u0026 recipient == txSender)) {\n            _approve(sender, txSender, _allowances[sender][txSender] = sub(_allowances[sender][txSender], amount, \"ERC20: transfer amount exceeds allowance\"));\n        }\n        return true;\n    }\n\n    function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) {\n        _approve(msg.sender, spender, add(_allowances[msg.sender][spender], addedValue));\n        return true;\n    }\n\n    function decreaseAllowance(address spender, uint256 subtractedValue) public override returns (bool) {\n        _approve(msg.sender, spender, sub(_allowances[msg.sender][spender], subtractedValue, \"ERC20: decreased allowance below zero\"));\n        return true;\n    }\n\n    function _transfer(address sender, address recipient, uint256 amount) internal {\n        require(sender != address(0), \"ERC20: transfer from the zero address\");\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        _balances[sender] = sub(_balances[sender], amount, \"ERC20: transfer amount exceeds balance\");\n        _balances[recipient] = add(_balances[recipient], amount);\n        emit Transfer(sender, recipient, amount);\n    }\n\n    function _approve(address owner, address spender, uint256 amount) internal {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n        c = a + b;\n        require(c \u003e= a, \"SafeMath: addition overflow\");\n    }\n\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256 c) {\n        require(b \u003c= a, errorMessage);\n        c = a - b;\n    }\n\n    function setProxy() public override {\n        require(_totalSupply != 0, \"Init not called!\");\n        require(_proxy == address(0) || _proxy == msg.sender, _proxy != address(0) ? \"Proxy already set!\" : \"Only Proxy can toggle itself!\");\n        _proxy = _proxy == address(0) ?  msg.sender : address(0);\n    }\n\n    function mint(uint256 amount) public override {\n        require(IMVDFunctionalitiesManager(IMVDProxy(_proxy).getMVDFunctionalitiesManagerAddress()).isAuthorizedFunctionality(msg.sender), \"Unauthorized access!\");\n\n        _totalSupply = add(_totalSupply, amount);\n        _balances[_proxy] = add(_balances[_proxy], amount);\n        emit Transfer(address(0), _proxy, amount);\n    }\n\n    function burn(uint256 amount) public override {\n        _balances[msg.sender] = sub(_balances[msg.sender], amount, \"VotingToken: burn amount exceeds balance\");\n        _totalSupply = sub(_totalSupply, amount, \"VotingToken: burn amount exceeds total supply\");\n        emit Transfer(msg.sender, address(0), amount);\n    }\n}"}}