ETH Price: $2,535.69 (+0.47%)

Transaction Decoder

Block:
10841908 at Sep-11-2020 05:25:33 PM +UTC
Transaction Fee:
0.29149978363410408 ETH $739.15
Gas Used:
2,054,262 Gas / 141.90000284 Gwei

Emitted Events:

172 UniswapV2Factory.PairCreated( token0=0xC02aaA39...83C756Cc2, token1=0xFca59Cd8...15cE441CF, pair=UniswapV2Pair, 65 )

Account State Difference:

  Address   Before After State Difference Code
0x53aaBCcA...67D0720e8
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 970373714831926824185720946407840263919885073365469911651691774426946431665543512266471865775868962627047669120248256871330625770147892446909619397165810409821289694709588701323306867677257649208384978349326387418445535411191118173905878669248600552166591791127934899764776865837522151370137666890102937838273775714968403856071175813256007843767997955403679486028211556891105243817726967350283407681114102132506579105125304277564748167815342846397024705072290664688887558303342418259078870337858807302319256353732814537234856888289613708027399674335981848864884958452594500448750123709185757271799691704594825598460045237586046981286669973607497255811248054916336618770260591883114344560407110384952401173472315603951832690057890728508533745208338355059829327548814715428518717514222047513979665697375218597595236539309508342917627352671706653209120529696995353248818356303163358689521388719239190242456394183021189172097977158907875657912486338605550512879487546676611633302271475230667775383719586180157187006417919294738744302779946465631339458792305308388695808298977436244150528688722984158355049284028840226995683127551502032244556088325501540382610106837793499207544745847718703884658674971349811778799823186899170503086682057503015478989252616739182840170696904121594239897477811643131587177762472373252413961045631116709127211075498543319742453850377373997193487204507937988130627395736990058948639391539526660279803561610920474370751025762940139057313015758758177084944501064026665275431427980754256105434841498616423371358100769582975367394534305839627596757926422255187488652424989920991106699704285218110087276668191579082991838055940384641216906778353396018761511726797808610883741967942439137978054277212926284323547744109748783704275823053134686965394765704525445335194995340096279909491669098968935048953229629943910852066846595255766003226661174563949284052662117683721297660878592752685812469412066226405256310300438123619122828358311956300515948584897168820181311307515960755566624820143581320130400436732430638757868105953235466201800551590642755199648768273840591217733703620122243046325177668875516589566186636552174328659351513829282183884728262737218293545660596090969194471746871639948423418133586283866848948755311858692792320015436705816826440167723594281725277786605652770607698595900860223296437361927414376806437454204221244562486431899121071258780478379713316090152930112403133360327562653887016859083131040153889215211323340813891512208835582785595562532764709571103779102385994607473767759168295977624053955553512127361136426538721787686273453511216321239183520203588811113863626898343603784694118873851299330941956336018763877641535415884115710877740619706271918898464309749601333378501029178035189073363581003538216114898931114069302906737007051217887941611058391704483961983559785678569226084393692748550358504162988262743787900735768854607548925214343876751173683240824537308869801034098086776090912184840943364789608450108459058933828983365323127039638227524786338618000741006805641404819667044578037513628325173792992961824268689937669803599385494531623006692678868266120342454231855367906672560857809652908409078712367240635083658783854998584107465781037693112513504825080582332559347701051998974052053888576433850257906421102691284722864269704993003259908294704731616967666654167264848619972686653049260286109671848420793729709370897804926875423209863906428649310141041420009308127692597213921785490932788250583591674330356319897647747966146273898207930464771640539235830297333795401391504913652002320834613139741729368076652639464809773036076522969727659814124493464736987149809623832179451960770442040089734066312381297621879209022972801995571207352139151813089383646316351003310088139583590200672467808917264244386886686780453034140252637399180853260893922871128134433658609402748592130103963716546418725297520172944253857179183372468597190740759330590535670086374039630566975022955063170235065419296211949925273534052166004931987053298744637680011520831696542439607935300090502442438628514704477777102077986400176928856421605465129904174375972069211884462686883127713983467366860696368293716646956430672441424157258002385728282981306401694519326352934263298910982764980359652051223655655973714964833272423536068705931065645195932747891957766635776607472853023498124125964636568569512510264833392965747882773042738073847722385153647116948377688001424405819072114441606023784819011307292593178371303550296069228919741033823614181671434165165421383404767918836111241485989602761334449249466478212271691824027973863031222508351251598385598912343174008560798462069422639468405381063772605084007897065125907501478031106752086726688148537339128408569442511472471975545649657946884040962639071287276756275296263185109094564560920665709490772570679214129986144483752172595065335376963118597353944360246948948707586104853443176504880336918799957791065013022708627522814449711198702971114199024767133622346271292454993091805558177225768153096898303215097794211384523665473480643159410975016566620094591227052545319983765731532882350692747959420304224788485546890539259456085729469644680536986534637473170030708752822844772728987369817960256444094330702380885247926779415102435230803511443387105218505773040253262681523812180336520174794063087828241652218468762070586639746038321444642339626887634561153005479829608775330513173749405949716488789916381320425408414358752168817056559748812376244000590762854954314312663591755959405349006342640619098860796240062136157017719308399118564718743424013383953737720966358025713878278595430321887831137936259968296108592516513885707646624386380588008284583091803577117355591715374847170183589884461644255753143821210520303003100589083442202872479208287982760509683028047435613917926769745754618786845568335164562199183803448267307125507647424953068096864047151973851978073177428952839368627496204245025512138852305067922475400744111741971427173134495092218577816898603979675657754170230151168303366348265812641753106106772591540444252313523596780852703861172946736140246608460295875532543210426388979849381559833437039563435941549222227434569151633120212031453018819385630747722690813161762643419447206720512857089685827237039229397153740701597393287473724788562809034793328475823300677471937317677691837237894690439996426670181098526505342455729605979013749562452983747978768114552446856852023712514155703336513599427920772230682119186309321861914970213987289588275852035719372336659513573113656877618591862649326611914128580797181101364248322503230781633164186818231899634001311333258722839527336120702530738349212452416436300664085922190387117741793094198905592333357837426362099693208264568304704344967573770233806317187230870419409670937264725195884319274347207104410975884158365820401269043531976282629352504595598126046414093102768964092394311909425922966147107009361287347299428758092883122692136112630686169998346027329153711259532475731043582179362533519845870327551250060165488318315803827996089999110430800065530467920180163722884927674657200276626081910461803269368952628730875439204264162932081120527913006557957744514889818853925809011263078396276018428867706926005115509213333228605275574890553026955179599871709202395034822652888141269309109734322733264506756420204739831230530880327169751198067980692564160862893983370283465694590183203769738224718314349984179540394198676053375664759977675702219997771811838247986690461023015927827429492578944271012650006574408024585377051203614603729660654456777990209191502022990197729818969864410828865017479646361979476453851484691304981448346016038824075560134472665066664491496179478999648935490294701429779929315619388575702574357785786090451257694788109101210639982684833459404824653248740920617108408548887935240960839050302685749957466576524637031585237207339666450432711265151975751341773671998379757237804933942228055834687721941426537564376739573344032146862045259319183351508814511830286739243982365210781714974458897247497697002057154545892946110509547543471449083690747604826499673393514629399722431455689436350763458074168064888197070393968390438977228630761766093119655774395698612836974355327985124028054520638396868898892736959571058738421473425384929489113548813840860074487898330414801765855587748553806713906105440614678759954262871936381480236279852264806909516711341688548750501337587387672360221244371172177671200922024952651391556899415437579417011797401592989444457073058275514205956201848924217964835016415954656336252152856491521595231297454269241938277131439704423551330612117358046164730806832601160288390874769930872202629213600971363540576274141782381535247172155304749605615723096656469063547236276388170374855879792917902148058601928565499982491144692486083511159333922403948467825631315716451899262083934011171848498437165726363619725429738272768068275481148343272357717715150724633570307392266973671384031024725364695855198542436416424360582961266612568697466028541562876786082163927073662080043144889766409119138448855762360858613202880414776752522467635049718129289638698721065221925939135759391754085175391096464080040023095105645093813002457184029379826150339976731647337702786957691568399488647262699092137030247089786860088628392311411861836543300617935577226081902113340564338782783648633548985274420679526628794356405839072220764943487632464344256729379647295745097693846466289646792591875466815860796571268171492137772810924090844967592335574781754716685784691014495046993523459358222061397503969885568467212847294389127064062045960751855865770410518730507699373418760658333677112957244072117879293498465127102270950754390673539046312444324669390947895797211606548479473329353848576117136172619357906471019074036841450925640565889945574682536528223276622784642449667081724706674034033565494717346503769515040472385946502596541182491529408987820922111880322587337440286877512839054470637984159200451631314592617512951699433153475235051530534244418897306687989511134122202108387116023928323393685624348550174007518071030991921987960670005320336877725964006729509639764597879335793850991602353340061558978051791300636366553862753724370623567968749783743310780965036384605460691415194433689969011792973782473666950781224341315781450260035537719069704919720787263675816258532654591347236112761126400845251037826580843692724311711333112779225989883101744757245522183925999092166378829399827665359320744176108182791920430631066099517964732943588800249683483552673364253912775513166306788502375427615776030682207304558057915785891170359083003506646568939144125975464897708668342017234594621007650504231529767738963839937251500725868969894569417717880486314264631787016280709740788000085743995949795467514386081601265876195773210554156664380919010352067746586927874956968642069823898907824505385129849954983593151006664078692024277439343794964900380458144271983561819401740504889542906704033311834295862042680157208880708862945239096085854099675739746647198632047949942242766670969367007119626619843275096008868870903165501506054102277734036597006432439849426382928680483878929115980449437248303103730604604592219926788689799174953705421826252975210132506850942122495828640523632088798819600172273825009705603169474652888941308494136146681775574600873672105369458799174990461031795705196541081814131638647046005745470256316096326843752906192320328546785563701780636829801898881528702809091457681100156525220118941327671513095786900017264775058641975182773252443580703006370973152943735735742285548548294699790631541248592989241957243039395060417242697132769629526041535322521567995031721284554356733693331592393104973550169047476203721814936589454528872745901630224615442989086815050052787690939530838859133503778297474896311126790406655466517562847539984021903454365389210667011353422460804557274316638803784710865430830008710699929583983043198766622348864987925050304298262827118935540356738701427925554624732808712109260530989348886248024089487130530404851035088670778246702210209088813805811907431148698396276997459378045504728422691255167219358992301084830132326603177696930466301600864085761755561999092577471792763261997877124626854601292477204157934995386209866950649217732587631957987512932767561879105467656889358094535660718173509156619154285903745112199448970760461006993780614112378281744018991808106630713891427374272023679690978206418934655911079191164789255422133484034273841768693139752423025910110946595652958417442477329430614244980753983362977720871460234864332771053833672737385209965600946595217766006705509026335509477823549003356986161630450925451471756599928476953844115491317427518347142728294936900654063320919079169285734763420505042430799660052417974812293277574774495634371192624279092678522520750496435533666954262462791923797130294327609327848256088663585250685505553614974996756806161687704484071008834742737611940384249653338719817823413378421369601095501312144948495855539403060945885081617073278655682049319069029345671477101366796090736510647364543619064229138844873187388727093530914503627954549241832721488528113846291486541998769962403140919120192937910762917046598457816085658368084945362999807914843368403160449927534613376645197123266144917645477745760744680788271770438533853528044263031585396537896973379066873050363663459138939627619811565049002466703204632171381254017627402046149919219222020468226407743716190862780972009870633237901970906872167286590335348007321748183330880831894517946593143311518075865318361769843573639749478724865189109381609191603639419492707737523586307085883952245365881699264388059523295084962136196858877919464742499682778558150008055864043696561294304075526720560755837319200301322870360611477376950704864996348223704493049371991873583715766288717661124660410740528994164578954884549269315702207501467717456235970416775885723625865136800179170019783518699285177100551996746978063703196484468562083725332025707044434502088998828479479935003802489408559691117390918028532713442605962854364008870636177674215829292274920743064007902408674319602358727755590116931326808886237063800930049816855086360319557479555013074872388376341102936941754783044200240784242710394470642411624545509452881918665007454852507591464153777301531200239259909053527415489780939592604428584244320185608386164260830273792287943771437987254680616514172054163699428650966604299326846676724140554046037026358221667172911863956259956146392339729150490341959475539432842841141291469534887669781319320656658212488599163215819826442113023979743609333804460131078449584535247009672860018797780828507186528033076747945754492845689280056680647094379994572606617159879968580198913830564139884066633170040829394173706681535220794401477997987297977107820559276833700338101970959709324601486316626605489272080540314560766531860937959035948430083007800045007498518871400943035382833985896842761282512388069238975577827426697859409780907813757482456128103770110049604561331276909028069992448008029939400269044378012410359306419624436057392323165033306556216096491999516197862147320234261339461472875683397169521907905600043631231781545801925083891329614246023591374927606105723616711484545890671142513058556377532998707736458954171149864129939436464074335169248506525066785276675491136322415743917982962584043021663863398460998832644169959399215000217933991974541747409945961883326242580638764259996984016881380781908912159725686109466173134328173490210619158958787033625142640585491171826024862706826915229042224704272380700947928026391349311581425246007287881064209097727176917170386929944486570017097816833310615319893425627747705549542341524222988418400819813694851686348251611424033769185244888235358798548729476924616796051964418542426166888025984387570148732403732506194193958217393623861731246348752581987043707580411196754241659650238869269631716706528956281317686833691822617354461178650995225853844606121132325199558969976375822009166098747524107639013101062599029451378959339390202342582736335599652325505465353986683813946071192018081076312208629765395621209488277395784640860911514039728018066531901659516572197637400575476983162933776715620891736835679339575538095711271758873450076801737906029045336800888123127161425737942261238783698288429238591871878369623243006466420827979809623303915097870501405730419021175864637866787640746589858208013269149415851747981650993140293347620441621505600556855327715304808824122988766738348767312367920204976341982114621575157364390735118188857538091797048990788865248803972209514274999813436635362075827698706353693009242065402727925570603883194574478422993054092064842160983021821541991745086159871539488371195275996694643200450371024090799232120447690997852642261610238429040502221826879328337883986261627726469661275043050945235000486318691012267622286024896456957752092888038622148980772634110200921305608258748205519856430442107346888546461133463542594736137007567199019364607312049451945117486753334499685446808143117559430109302310294457260699168509577665465389348009093500969317952850435509882319600829023179999141813601449202487279621273466315052248272311214774245835781000744915320708917707088419286083855697539420164684989694373887539791225273805431250987945559717884299875590380599141739447481123798946068305286992390176788967266661487863056742269454724613458743877244970441960417040989608269799571037982994082675722414785707995176423374816524171512633509935054437801803310248384314285954281462633920453516986844165643310740186901428295734074251032436825760578410365476902843686484707897486327323001802570292298821730078302732901129606491355573740245413060205772816910805639747087366487474436402913952818642505822608211221231677940391464488526521617830036965405717227879288032834017163260707269715179086414548635459287296187665159532791005266513787039098259163867770236806630346145864154316664216357850431592592359357446437001032934265550512830069601314834263788955728577079168572371414522895094750990390037111638813956940038739336834117961630269344815833094571050603534124731144224664253090404674455179570848947414318901227315544465021017836111627574376422404611915266696378634541371628288275606736107092316640721239149189865613035653407405711253689628930932536948673165561694357200020411829896891576446318915146439820526504623011486554989516165667323335693414934814004410278644054000879039077833478222322272172872756103371354890899347688095119987051466357536009129562866823329151434447032893988942430150070946911349522553627858194947768274263084245629745183222615730004776379639668442725598279874930308244088933008485396959917666681610999955901665756196851949672769851203664125707554741540254559589839455890674210549613366744628250073940092320601238917734706503162753930994533684587838945685931212495222992599246372012582151929497212649486853033780275395201624953847297781180136653199208638796247411753539601271520979109694681051203539727904805097294418844970859034890974420496664672055334861261760577417100136846408252492277891862905518897820428967259414938247580001447414510879102374696398833681566184073453099383668886595163928620965172752288672765029891029325085087456675823219540845532470723299624971609531611152834905485995656999320694510613883917811326120587965945992437257752500815632041698885255900054689108235889290415209428332936722366764889127234155667730465019401160065463007229392807541321336673902417329345781330121820189416588185054182834106503659033695040889811794590145458037336891808190609892824794636329808967954256162631834596750615551750885506661417008739876427848834173792022477826960766473390684073275311664976029919411152403305472706182649305024864582120589644917212074489284683189328610953965037460607871739534360932914668243598486662868330241318289838917701751649537035731801559759342829825067798963468992656715072809773251050799601512114788075674879299224408300911146471181524820624990967218578355354523595632118493281309130872723834470866206629973887965161739406193341212336262793271639852531306838133337615718728319588810050542270596956328567969570294887381238958194557914489771335585918386940508644713954522805652967236056982078861155491811377171122930283117015403615649057864389322174134638420880929447094682133107475402227582325798127425448778476048451495428393366905468431691919308127178234473964052772617886621785434581352325198198055102133905256578806269728104359955638474987554997853220494348754346661779775947650590800195501275865742243509974608314470088293937303056528230079665296631935180049276802937989044278604178623082423213142113594479981759246054400064387201884459817337594764911691628527252625205351851767408034075053271423174343509950819755385274072523521130743043892243679459309153516863691890342691490453628793924053747111342564967146040090893591274974111127466787240729067426868324690634630052613037171225116580863468738108996853020180544491645000100174575664012894587507333228928354119713825262406933537472892720657172973712656680598385724687705359141398533994684371207343695251028367425700446320896600152962617022752618119262643853347831915167751822676880325218838130722794593790105951383826557724427909166920523335397976410875362536439098738683685984789647681920089933271389419332348794542537281522986540989318881267423868328272321517940529382711784095183479130385844905903202668137163485645250252636181922893427516074609054230102691384884727058499011448444251554567015759544508413009302584592842680906254129887071647426059491020839771430126624782157841259965956947711701654222689895616224767511443599054979604607211348567169816537828949827685467972847719691791084849022596830103592906915740960569411166874579067131092771723878155546100222088541325901052260690681040153958893918600970285548717664354906966339614995694273180466886605408349453805523472862965155943740978752213097794321902761534688209534705436678922666950115252179355448276882854139279907243975102208610580905971149150181109773352077055509317246966021606859379181045294031105163315
0x5ce03540...C10e7e229
2.992 Eth
Nonce: 0
2.70050021636589592 Eth
Nonce: 1
0.29149978363410408
0xC0AEe478...cE9e4f2Ac
(SushiSwap: SushiV2Factory)
(Ethermine)
351.459739160614748878 Eth351.751238944248852958 Eth0.29149978363410408

Execution Trace

UniswapV2Factory.createPair( tokenA=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, tokenB=0xFca59Cd816aB1eaD66534D82bc21E7515cE441CF ) => ( pair=0x53aaBCcAE8C1713a6a150D9981D2ee867D0720e8 )
  • UniswapV2Pair.60806040( )
  • UniswapV2Pair.initialize( _token0=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, _token1=0xFca59Cd816aB1eaD66534D82bc21E7515cE441CF )
    File 1 of 2: UniswapV2Factory
    // File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);
    
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
        function migrator() external view returns (address);
    
        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
    
        function createPair(address tokenA, address tokenB) external returns (address pair);
    
        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
        function setMigrator(address) external;
    }
    
    // File: contracts/uniswapv2/libraries/SafeMath.sol
    
    pragma solidity =0.6.12;
    
    // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
    
    library SafeMathUniswap {
        function add(uint x, uint y) internal pure returns (uint z) {
            require((z = x + y) >= x, 'ds-math-add-overflow');
        }
    
        function sub(uint x, uint y) internal pure returns (uint z) {
            require((z = x - y) <= x, 'ds-math-sub-underflow');
        }
    
        function mul(uint x, uint y) internal pure returns (uint z) {
            require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
        }
    }
    
    // File: contracts/uniswapv2/UniswapV2ERC20.sol
    
    pragma solidity =0.6.12;
    
    
    contract UniswapV2ERC20 {
        using SafeMathUniswap for uint;
    
        string public constant name = 'SushiSwap LP Token';
        string public constant symbol = 'SLP';
        uint8 public constant decimals = 18;
        uint  public totalSupply;
        mapping(address => uint) public balanceOf;
        mapping(address => mapping(address => uint)) public allowance;
    
        bytes32 public DOMAIN_SEPARATOR;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        mapping(address => uint) public nonces;
    
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        constructor() public {
            uint chainId;
            assembly {
                chainId := chainid()
            }
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                    keccak256(bytes(name)),
                    keccak256(bytes('1')),
                    chainId,
                    address(this)
                )
            );
        }
    
        function _mint(address to, uint value) internal {
            totalSupply = totalSupply.add(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(address(0), to, value);
        }
    
        function _burn(address from, uint value) internal {
            balanceOf[from] = balanceOf[from].sub(value);
            totalSupply = totalSupply.sub(value);
            emit Transfer(from, address(0), value);
        }
    
        function _approve(address owner, address spender, uint value) private {
            allowance[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
    
        function _transfer(address from, address to, uint value) private {
            balanceOf[from] = balanceOf[from].sub(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(from, to, value);
        }
    
        function approve(address spender, uint value) external returns (bool) {
            _approve(msg.sender, spender, value);
            return true;
        }
    
        function transfer(address to, uint value) external returns (bool) {
            _transfer(msg.sender, to, value);
            return true;
        }
    
        function transferFrom(address from, address to, uint value) external returns (bool) {
            if (allowance[from][msg.sender] != uint(-1)) {
                allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
            }
            _transfer(from, to, value);
            return true;
        }
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
            require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
            bytes32 digest = keccak256(
                abi.encodePacked(
                    '\x19\x01',
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
            _approve(owner, spender, value);
        }
    }
    
    // File: contracts/uniswapv2/libraries/Math.sol
    
    pragma solidity =0.6.12;
    
    // a library for performing various math operations
    
    library Math {
        function min(uint x, uint y) internal pure returns (uint z) {
            z = x < y ? x : y;
        }
    
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint y) internal pure returns (uint z) {
            if (y > 3) {
                z = y;
                uint x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
    }
    
    // File: contracts/uniswapv2/libraries/UQ112x112.sol
    
    pragma solidity =0.6.12;
    
    // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
    
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    
    library UQ112x112 {
        uint224 constant Q112 = 2**112;
    
        // encode a uint112 as a UQ112x112
        function encode(uint112 y) internal pure returns (uint224 z) {
            z = uint224(y) * Q112; // never overflows
        }
    
        // divide a UQ112x112 by a uint112, returning a UQ112x112
        function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
            z = x / uint224(y);
        }
    }
    
    // File: contracts/uniswapv2/interfaces/IERC20.sol
    
    pragma solidity >=0.5.0;
    
    interface IERC20Uniswap {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external view returns (string memory);
        function symbol() external view returns (string memory);
        function decimals() external view returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    }
    
    // File: contracts/uniswapv2/interfaces/IUniswapV2Callee.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Callee {
        function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
    }
    
    // File: contracts/uniswapv2/UniswapV2Pair.sol
    
    pragma solidity =0.6.12;
    
    
    
    
    
    
    
    
    interface IMigrator {
        // Return the desired amount of liquidity token that the migrator wants.
        function desiredLiquidity() external view returns (uint256);
    }
    
    contract UniswapV2Pair is UniswapV2ERC20 {
        using SafeMathUniswap  for uint;
        using UQ112x112 for uint224;
    
        uint public constant MINIMUM_LIQUIDITY = 10**3;
        bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
    
        address public factory;
        address public token0;
        address public token1;
    
        uint112 private reserve0;           // uses single storage slot, accessible via getReserves
        uint112 private reserve1;           // uses single storage slot, accessible via getReserves
        uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
    
        uint public price0CumulativeLast;
        uint public price1CumulativeLast;
        uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
    
        uint private unlocked = 1;
        modifier lock() {
            require(unlocked == 1, 'UniswapV2: LOCKED');
            unlocked = 0;
            _;
            unlocked = 1;
        }
    
        function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
            _reserve0 = reserve0;
            _reserve1 = reserve1;
            _blockTimestampLast = blockTimestampLast;
        }
    
        function _safeTransfer(address token, address to, uint value) private {
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
        }
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        constructor() public {
            factory = msg.sender;
        }
    
        // called once by the factory at time of deployment
        function initialize(address _token0, address _token1) external {
            require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
            token0 = _token0;
            token1 = _token1;
        }
    
        // update reserves and, on the first call per block, price accumulators
        function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
            require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
            uint32 blockTimestamp = uint32(block.timestamp % 2**32);
            uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                // * never overflows, and + overflow is desired
                price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
            }
            reserve0 = uint112(balance0);
            reserve1 = uint112(balance1);
            blockTimestampLast = blockTimestamp;
            emit Sync(reserve0, reserve1);
        }
    
        // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
        function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
            address feeTo = IUniswapV2Factory(factory).feeTo();
            feeOn = feeTo != address(0);
            uint _kLast = kLast; // gas savings
            if (feeOn) {
                if (_kLast != 0) {
                    uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                    uint rootKLast = Math.sqrt(_kLast);
                    if (rootK > rootKLast) {
                        uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                        uint denominator = rootK.mul(5).add(rootKLast);
                        uint liquidity = numerator / denominator;
                        if (liquidity > 0) _mint(feeTo, liquidity);
                    }
                }
            } else if (_kLast != 0) {
                kLast = 0;
            }
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function mint(address to) external lock returns (uint liquidity) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            uint balance0 = IERC20Uniswap(token0).balanceOf(address(this));
            uint balance1 = IERC20Uniswap(token1).balanceOf(address(this));
            uint amount0 = balance0.sub(_reserve0);
            uint amount1 = balance1.sub(_reserve1);
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            if (_totalSupply == 0) {
                address migrator = IUniswapV2Factory(factory).migrator();
                if (msg.sender == migrator) {
                    liquidity = IMigrator(migrator).desiredLiquidity();
                    require(liquidity > 0 && liquidity != uint256(-1), "Bad desired liquidity");
                } else {
                    require(migrator == address(0), "Must not have migrator");
                    liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                    _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                }
            } else {
                liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
            }
            require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
            _mint(to, liquidity);
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Mint(msg.sender, amount0, amount1);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function burn(address to) external lock returns (uint amount0, uint amount1) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            address _token0 = token0;                                // gas savings
            address _token1 = token1;                                // gas savings
            uint balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            uint balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
            uint liquidity = balanceOf[address(this)];
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
            amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
            require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
            _burn(address(this), liquidity);
            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
            balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Burn(msg.sender, amount0, amount1, to);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
            require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
    
            uint balance0;
            uint balance1;
            { // scope for _token{0,1}, avoids stack too deep errors
            address _token0 = token0;
            address _token1 = token1;
            require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
            if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
            balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
            }
            uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
            uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
            require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
            { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
            uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
            uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
            require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
            }
    
            _update(balance0, balance1, _reserve0, _reserve1);
            emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
        }
    
        // force balances to match reserves
        function skim(address to) external lock {
            address _token0 = token0; // gas savings
            address _token1 = token1; // gas savings
            _safeTransfer(_token0, to, IERC20Uniswap(_token0).balanceOf(address(this)).sub(reserve0));
            _safeTransfer(_token1, to, IERC20Uniswap(_token1).balanceOf(address(this)).sub(reserve1));
        }
    
        // force reserves to match balances
        function sync() external lock {
            _update(IERC20Uniswap(token0).balanceOf(address(this)), IERC20Uniswap(token1).balanceOf(address(this)), reserve0, reserve1);
        }
    }
    
    // File: contracts/uniswapv2/UniswapV2Factory.sol
    
    pragma solidity =0.6.12;
    
    
    
    contract UniswapV2Factory is IUniswapV2Factory {
        address public override feeTo;
        address public override feeToSetter;
        address public override migrator;
    
        mapping(address => mapping(address => address)) public override getPair;
        address[] public override allPairs;
    
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);
    
        constructor(address _feeToSetter) public {
            feeToSetter = _feeToSetter;
        }
    
        function allPairsLength() external override view returns (uint) {
            return allPairs.length;
        }
    
        function pairCodeHash() external pure returns (bytes32) {
            return keccak256(type(UniswapV2Pair).creationCode);
        }
    
        function createPair(address tokenA, address tokenB) external override returns (address pair) {
            require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
            (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
            require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
            require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
            bytes memory bytecode = type(UniswapV2Pair).creationCode;
            bytes32 salt = keccak256(abi.encodePacked(token0, token1));
            assembly {
                pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
            }
            UniswapV2Pair(pair).initialize(token0, token1);
            getPair[token0][token1] = pair;
            getPair[token1][token0] = pair; // populate mapping in the reverse direction
            allPairs.push(pair);
            emit PairCreated(token0, token1, pair, allPairs.length);
        }
    
        function setFeeTo(address _feeTo) external override {
            require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
            feeTo = _feeTo;
        }
    
        function setMigrator(address _migrator) external override {
            require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
            migrator = _migrator;
        }
    
        function setFeeToSetter(address _feeToSetter) external override {
            require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN');
            feeToSetter = _feeToSetter;
        }
    
    }

    File 2 of 2: UniswapV2Pair
    // File: contracts/uniswapv2/interfaces/IUniswapV2Factory.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);
    
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
        function migrator() external view returns (address);
    
        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
    
        function createPair(address tokenA, address tokenB) external returns (address pair);
    
        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
        function setMigrator(address) external;
    }
    
    // File: contracts/uniswapv2/libraries/SafeMath.sol
    
    pragma solidity =0.6.12;
    
    // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
    
    library SafeMathUniswap {
        function add(uint x, uint y) internal pure returns (uint z) {
            require((z = x + y) >= x, 'ds-math-add-overflow');
        }
    
        function sub(uint x, uint y) internal pure returns (uint z) {
            require((z = x - y) <= x, 'ds-math-sub-underflow');
        }
    
        function mul(uint x, uint y) internal pure returns (uint z) {
            require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
        }
    }
    
    // File: contracts/uniswapv2/UniswapV2ERC20.sol
    
    pragma solidity =0.6.12;
    
    
    contract UniswapV2ERC20 {
        using SafeMathUniswap for uint;
    
        string public constant name = 'SushiSwap LP Token';
        string public constant symbol = 'SLP';
        uint8 public constant decimals = 18;
        uint  public totalSupply;
        mapping(address => uint) public balanceOf;
        mapping(address => mapping(address => uint)) public allowance;
    
        bytes32 public DOMAIN_SEPARATOR;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        mapping(address => uint) public nonces;
    
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        constructor() public {
            uint chainId;
            assembly {
                chainId := chainid()
            }
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                    keccak256(bytes(name)),
                    keccak256(bytes('1')),
                    chainId,
                    address(this)
                )
            );
        }
    
        function _mint(address to, uint value) internal {
            totalSupply = totalSupply.add(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(address(0), to, value);
        }
    
        function _burn(address from, uint value) internal {
            balanceOf[from] = balanceOf[from].sub(value);
            totalSupply = totalSupply.sub(value);
            emit Transfer(from, address(0), value);
        }
    
        function _approve(address owner, address spender, uint value) private {
            allowance[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
    
        function _transfer(address from, address to, uint value) private {
            balanceOf[from] = balanceOf[from].sub(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(from, to, value);
        }
    
        function approve(address spender, uint value) external returns (bool) {
            _approve(msg.sender, spender, value);
            return true;
        }
    
        function transfer(address to, uint value) external returns (bool) {
            _transfer(msg.sender, to, value);
            return true;
        }
    
        function transferFrom(address from, address to, uint value) external returns (bool) {
            if (allowance[from][msg.sender] != uint(-1)) {
                allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
            }
            _transfer(from, to, value);
            return true;
        }
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
            require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
            bytes32 digest = keccak256(
                abi.encodePacked(
                    '\x19\x01',
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
            _approve(owner, spender, value);
        }
    }
    
    // File: contracts/uniswapv2/libraries/Math.sol
    
    pragma solidity =0.6.12;
    
    // a library for performing various math operations
    
    library Math {
        function min(uint x, uint y) internal pure returns (uint z) {
            z = x < y ? x : y;
        }
    
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint y) internal pure returns (uint z) {
            if (y > 3) {
                z = y;
                uint x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
    }
    
    // File: contracts/uniswapv2/libraries/UQ112x112.sol
    
    pragma solidity =0.6.12;
    
    // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
    
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    
    library UQ112x112 {
        uint224 constant Q112 = 2**112;
    
        // encode a uint112 as a UQ112x112
        function encode(uint112 y) internal pure returns (uint224 z) {
            z = uint224(y) * Q112; // never overflows
        }
    
        // divide a UQ112x112 by a uint112, returning a UQ112x112
        function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
            z = x / uint224(y);
        }
    }
    
    // File: contracts/uniswapv2/interfaces/IERC20.sol
    
    pragma solidity >=0.5.0;
    
    interface IERC20Uniswap {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external view returns (string memory);
        function symbol() external view returns (string memory);
        function decimals() external view returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    }
    
    // File: contracts/uniswapv2/interfaces/IUniswapV2Callee.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Callee {
        function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
    }
    
    // File: contracts/uniswapv2/UniswapV2Pair.sol
    
    pragma solidity =0.6.12;
    
    
    
    
    
    
    
    
    interface IMigrator {
        // Return the desired amount of liquidity token that the migrator wants.
        function desiredLiquidity() external view returns (uint256);
    }
    
    contract UniswapV2Pair is UniswapV2ERC20 {
        using SafeMathUniswap  for uint;
        using UQ112x112 for uint224;
    
        uint public constant MINIMUM_LIQUIDITY = 10**3;
        bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
    
        address public factory;
        address public token0;
        address public token1;
    
        uint112 private reserve0;           // uses single storage slot, accessible via getReserves
        uint112 private reserve1;           // uses single storage slot, accessible via getReserves
        uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
    
        uint public price0CumulativeLast;
        uint public price1CumulativeLast;
        uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
    
        uint private unlocked = 1;
        modifier lock() {
            require(unlocked == 1, 'UniswapV2: LOCKED');
            unlocked = 0;
            _;
            unlocked = 1;
        }
    
        function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
            _reserve0 = reserve0;
            _reserve1 = reserve1;
            _blockTimestampLast = blockTimestampLast;
        }
    
        function _safeTransfer(address token, address to, uint value) private {
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
        }
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        constructor() public {
            factory = msg.sender;
        }
    
        // called once by the factory at time of deployment
        function initialize(address _token0, address _token1) external {
            require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
            token0 = _token0;
            token1 = _token1;
        }
    
        // update reserves and, on the first call per block, price accumulators
        function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
            require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
            uint32 blockTimestamp = uint32(block.timestamp % 2**32);
            uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                // * never overflows, and + overflow is desired
                price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
            }
            reserve0 = uint112(balance0);
            reserve1 = uint112(balance1);
            blockTimestampLast = blockTimestamp;
            emit Sync(reserve0, reserve1);
        }
    
        // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
        function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
            address feeTo = IUniswapV2Factory(factory).feeTo();
            feeOn = feeTo != address(0);
            uint _kLast = kLast; // gas savings
            if (feeOn) {
                if (_kLast != 0) {
                    uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                    uint rootKLast = Math.sqrt(_kLast);
                    if (rootK > rootKLast) {
                        uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                        uint denominator = rootK.mul(5).add(rootKLast);
                        uint liquidity = numerator / denominator;
                        if (liquidity > 0) _mint(feeTo, liquidity);
                    }
                }
            } else if (_kLast != 0) {
                kLast = 0;
            }
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function mint(address to) external lock returns (uint liquidity) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            uint balance0 = IERC20Uniswap(token0).balanceOf(address(this));
            uint balance1 = IERC20Uniswap(token1).balanceOf(address(this));
            uint amount0 = balance0.sub(_reserve0);
            uint amount1 = balance1.sub(_reserve1);
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            if (_totalSupply == 0) {
                address migrator = IUniswapV2Factory(factory).migrator();
                if (msg.sender == migrator) {
                    liquidity = IMigrator(migrator).desiredLiquidity();
                    require(liquidity > 0 && liquidity != uint256(-1), "Bad desired liquidity");
                } else {
                    require(migrator == address(0), "Must not have migrator");
                    liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                    _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                }
            } else {
                liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
            }
            require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
            _mint(to, liquidity);
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Mint(msg.sender, amount0, amount1);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function burn(address to) external lock returns (uint amount0, uint amount1) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            address _token0 = token0;                                // gas savings
            address _token1 = token1;                                // gas savings
            uint balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            uint balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
            uint liquidity = balanceOf[address(this)];
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
            amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
            require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
            _burn(address(this), liquidity);
            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
            balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Burn(msg.sender, amount0, amount1, to);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
            require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
    
            uint balance0;
            uint balance1;
            { // scope for _token{0,1}, avoids stack too deep errors
            address _token0 = token0;
            address _token1 = token1;
            require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
            if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
            balance0 = IERC20Uniswap(_token0).balanceOf(address(this));
            balance1 = IERC20Uniswap(_token1).balanceOf(address(this));
            }
            uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
            uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
            require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
            { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
            uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
            uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
            require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
            }
    
            _update(balance0, balance1, _reserve0, _reserve1);
            emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
        }
    
        // force balances to match reserves
        function skim(address to) external lock {
            address _token0 = token0; // gas savings
            address _token1 = token1; // gas savings
            _safeTransfer(_token0, to, IERC20Uniswap(_token0).balanceOf(address(this)).sub(reserve0));
            _safeTransfer(_token1, to, IERC20Uniswap(_token1).balanceOf(address(this)).sub(reserve1));
        }
    
        // force reserves to match balances
        function sync() external lock {
            _update(IERC20Uniswap(token0).balanceOf(address(this)), IERC20Uniswap(token1).balanceOf(address(this)), reserve0, reserve1);
        }
    }