ETH Price: $3,472.08 (+2.76%)

Transaction Decoder

Block:
11041725 at Oct-12-2020 04:02:15 PM +UTC
Transaction Fee:
0.240424002 ETH $834.77
Gas Used:
2,165,982 Gas / 111 Gwei

Emitted Events:

94 MetaSwap.OwnershipTransferred( previousOwner=0x00000000...000000000, newOwner=[Sender] 0x7f18bb4dd92cf2404c54cba1a9be4a1153bdb078 )

Account State Difference:

  Address   Before After State Difference Code
(Mining Express)
40.4627327453276478 Eth40.7031567473276478 Eth0.240424002
0x74de5d4F...794016631
(MetaMask: Swaps Spender)
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 22875659071242425958751476695531904985038452622178470149008601038444898468220133385408279034104295947748854535801758379174640044725692981768975468068050093864057181504734373338797565710689352725223592310514559228874792964319347812845560463550835406747910042128275789737266802866464612681105978163610079158046378567081748453972867861784503981566407767063291125617875310009604334196601967792986011885831234373284419732706810836538036393240189868025216288485017737390966809465445759982643396611836975634958896097158099940168043787423151492650646677356960229669987587790020112579738373420265357627366580842697129053716034304075151094885908694520010198321414372351648497827005992333967413249037105896940853473171670426792825327095740651319616014988720722242965685793336873053671405076648230631138854239275938682694461682112071437340072961877478962325189256657590209423380814231284858352002849684800048557628877868420360840112657856223703862322697373666308185451082628371742603775761233661971356264487077949435937725982183426587223493293192453420453694216212564175739719248028510296048891280951464069980489168073691372162991956354058943212531166962063677092209476313199309507657559385799854833579683277889065779514373634137734170733729031518098017921419462546062627025250166343983068071638971810708383617149874585728214419048599647374484903913458253953199670055059424971179862385397394690629017309605254539969748759081133031007340902293438842901628048089003444508562865227431321867475723455133784451714708327588493217875579312463705373158688181341910181417586817914198074846013853283911509812593477686877278955396210432026370215150662950178689410998968575976196528733906244371023291890990350806550548050631431151541213944794755798569142720318801832641952204550284870439649803918159520041833425789617990783023007066832018527952515387293423671758684958519786974625597576713258163111804260251572217749185852673443217668938767744789772121087487074050365944837951217099742099728836692687812985142368801642117697077052428676226723868349521275818475051477557473602766634004935852028072402708721683248924433184459452458725944832192798575551221266629957255564663949422567457803434402285147505721186940221255390767123822786129026347358680459921152563690127433427915311047219752797930534659708974530268486089597339167062836533149632806258166860660911889313568211352883282734571579154696449759561062171018712003083059117018751855860559202171360854706620144328050973589589795406650851480545651821401028869183500402064103545640841004799354227178591340033690900103415651333124115197085843343264338134029446178193059603992194340801848283085997179140047428853947335448945126532949337286954448403519431073198667192300008238373950481486574834322060398643426129175263966806050558808762106107649885266444327173308193740577046579
0x7F18BB4D...153bdb078
(AirSwap: Legacy Deployer 3)
1.182151867883463388 Eth
Nonce: 564
0.941727865883463388 Eth
Nonce: 565
0.240424002
0x881D4023...dC08D300C
(Metamask: Swap Router)
0 Eth
Nonce: 0
0 Eth
Nonce: 2
From: 0 To: 135770479654969335393511163915834216767786433490981118856376590368939197775130384817028026677451570583984767149026186464497972345594387716795024988071455205227441317668097678690789503676357093498661078050755933742981408479047464531748436587744934108417682197160471415642345683615033892618624543704476621997062795387319997127990089467274022456982877469727174208327761713278643952561063557855299985685817171433567222014637041270689038347993262480886991044194736463328571794027602657925521590526743756619216184818930701849123842014442564169909671182799892687434079788958382306132888861378815291857523864779941051218541184324083820272585592437066697228455419000980637131148621742397955752505185699035940133045141540054667697664187982003539592868537559154644756717001624676715734687933913571446971341011920535015495268767307754907536260993049354156646722005224607131424515707494990052528431870784144558029122621872028557194263770744428733004658400461995788495731651995965544506535101211461335502274314608253874242701393295945216799211094799444225975962036620571759350451508440915070785778740322847063751402259543099376794424052773774570009182660115076196642967599283632343459833682217808845927970809766007970232958064939000255223775624200995950605686708163154865864413303587994292968226997723611299005383052783545794665052906377843479120226319483557837258168463930354233557572594454301228109626074569726093576407334787422360354952102651323724476105347827428946836132731274639550657078502166010521547190049429506093889164179232273175140730783603279403922386714868337696266589478851910149887381954513418200768431780377691372183979325344769433214305889530014053322242347304508853593366697908910541764203894392312138736132895609523963970803051835350811370620551595769283136499983597390143202146349394283790360807517981145970267050953501424623489022345112111118672361488738098983056882664306306925356621947004769992601275148913491028149913250152326307630935703950578314444570926093602366365256613430036616809979108274842133062946881592494263413538897746123175602998032640592510175039588922226503950633594726258873615720621318433854776722593541005179581998994643703730559399644422874036870142828973524466970834892584981598839996143671908851250753185794986323051905430989690181204474243522727319686797974272643596228407510030301405744068913336020315873448939398541083977112320478701282049818672168088139233677075692193739874037271115588115316810313780376848732365824357925583413453930399394646415759287271471214082989260392660103943776384595513779186933996941195330928533219467316566197329982434935239847492185466564860275411995874552863250460133708130790808339334992080794346491429756101667917009645488996769344015735048207770443537784760377145870532463529882485979200763341304807719248706704772076758099604656383525395497145503047244349891284494205528233100641019685663862152423579256852557737328973418599770644236224636688946978732479513157349001955020131052894627718138792893302363976065978961028765220418361904769957477796970133595850867296036174734641076108052507643604296789809981163925370370387706208529620523578276444173391900938260686720865950534974638285169078686240921513864023936584972959259096740524463767957199405390644601373252933628435758076135453063382645747088966335121519202275262887654897030867020128809821037318816801914660217786725383239371058010605023594012436115914646717235667415144103888020094670506388511951211401091828669588181383860051894211589980820976376468536119563850153804247845613227055341473778963545498043609723503127160851778629082271778729953598832777402725656396496869905824027454741366650121074911965399379868905642973245770975200736915758188575594501133251097782644966839539173909898415215235941044708927225979800274304943820090256989696568648705081594781857985808483952537054388167828933546314666155902698935399058384271128522090831279299473924100994647449954913159824675364276933412110904094855354280213383014120486859584982634027088451572483658311779234135190911660237957165098329268316128801903202149305345487783422210330507122485668613740961857541548075132754068236213248581362010114697303633223461571570221511268195144289601468015992459886049934897459219949713739265968950242016858404974607280734491473714872202742958823288528137298658122191898119247727984684590276420254158105339617934172125773495521768976791691610320923236246877811183337804050426627857952626712026694968934902488408357170978033740070450590150352245128646351767283315881346562731940580757965114437806042981826439613307209218381860261060613645958573441302804257206799414249376656792082893709734776344044843425882339508346617049046139045757250981626443470170986630985360341268692337039456604164660015212015070400270194130318788815963606632676247633991470278116488636387613843467625504747986248813110693743415247602980902754344995043707192126905287601870003839342052351250330889928496995737313282467376062140088771132543287408826789297620767537120772117109217786767724764784204202979917865079509284275755181673947021169359080951694936700404360908517875483745291968395379742911084854710451851646988533437828314700586224929924727016331438570083108734843907429602582087010136225234359476518623439455781806195357371929531668726919311797305240840796091173052434913749168270597440208157895361210814945212455786718573729869084877242803605747337966184356253236906744574953356227081097032107180110352477151241602729225199032831097686172393875850360472071391603855092200833290370494742574753777383804362455605695807873466014548790591833825182355459986201418095655027505356563206015666080036303394167990935917207592079885369777947086798546195892086627361239309167570295070008401611747695848468169988354159013234594471905108352009963868258708417198989115358848821911534912095520409310909231678755110808546699459449903877036832033547292302992334752655439919165895671024971079494650025691015794992310741179155680976811222293219301148700366577149108280345820064270160363213824515160744459525420740730263824369987359017333314180123073532135849187992829095740367238993198224440873597860097192468944747608979543797832706276685014228620875639011865944569239894288380584609050541465328638641278532522096258949881022239295036499054007882096012192536999147810473462388161837561752670797687558732597317965675106759568921820928961114575549183137975620485732619826460210529138356938860587353659641912422232732216817592433925203967733699299590417864721013001873197781987915477659396273456993377431916846831540563584852391347933624990499145122176721840298729251063609052781450737293736033212703608925724189031206058660781272862084987983074595971135067133025822018574243597011741537823607400540913199261701004919129966024744087914490232232557958790753522482017129980345467724741926396271381740354731420768481344005454704773093917091231151948479199025908219320200281706471192628660096357446328490276260456341474454926144893789186141212551222545666449536176697253931355840677954978768309203956906018248651457292422478167555620389670737123961915919991090802007733238520317826731043892965942916099173827703534579326364508427094018275548693091495296964202773847459397872410862115411959627728753904314808755618580738664582741384309837171313840004377277840623290289796118950501798246397095947668208138787619371445654340017828200239517490183676851869660143148106966804122404993260247819895262882030372958050185728383204540533596063869151640433760877137032230119053741563799318266558922756946485238203482985847609711016946084031565550701208072796082510827589640803597535836583825512772943335987782909521286678400595210599073584646592231842826259767028471967691791104006665980669044188889074562982703325790232530321989274404479597308520744125580613567865949023032261766032151461013816245516293597078066679446288570129603616386462112186236739758583565584673301977165897150042229609774125139825256932017026950891397338165095098070250873714367143479853633141397592457664867987997899283239163499247076625584204761004730144903619378440397986257900542934728440297696901899048283764282487416521402341067217840076236474603455266720704503298330514710840012764865929298424488959504526424023930335758218577347315679841803006704442640863467306087336009057651190163617262607309642798295019104279240983420602530770260621681328536341365185631786293845358801175056773796663778291996519843131185219341747188260044424615794025837974757439876301689431174861767201863212087973351387933308102881698606836109550710849006872583529127877211902527576211582318186899203979770194061643735559955515936171794516832965235591613533756593236806330336457367728432054924064374711225548948198756287386922830597893361847428963675840956095395126964662667415910647635540744124608655480817321551135234307494581083504390360767785931739475967901243726942838289957160454864316149999231633066847844722201971691396443720845120627698410684970775350212126027010990545069090151047036424866718750929179066017140008986390040819016388385176807960735011685420042344374990610539328641613374425628049014159259894545472266133030972850042554786005352453472036059610441881488551736769205286682775645904601767875078854195981062352610010900772446387303743559113000698187810225869759825803788066927981831254116141732912854138185383138896107372294589061732104794111859410106405864811153004600940654674599426492668796842827593024024070979023696746636364796114036728673583027807067443738627144985053557625657574655354212247644354852092332427315242879839990319285988859366340813277854085730896336613335907104238434318227308922704215976974022983225196530124516080277666607773025759559299713692240226641011383437676628945763466487911170494817081419187915113331411253517687798554746847423261407298317246698491152308181241279498785766437241746407979290968990038827437468135295686722442453281535534648036613056570214664159525173850125273953674283552315584407947392100252085575509843698495255595411687228671241713671968228636687648397308072942929939547923613192346449469190984842949591744058545976201860824203004887561881662865694482715203953770054949090760574315204862948318260864662772353562958776958390799507693263350001620355280549698361589871994004755859537813076566860674676675253686525965122957468762152936716349721095971666107913607051722540642200918862005117806083909587683058633480781536259942446428312602426631935418232433212553387424540511065579342329070578837822589558250002684606147957190008577145108465504244631091508223871462775442297128370602485738553849524233813633622472236374575233107218833841049521327873246159011460399693227327903975322433108485968549267980844762566653510335136043050397201673115916198177262151792187247863115736332895335111190984549886973722457038507582604318783062757738872771583340880781219677156895253431180732625566170867375196703261750563595414853386476011448411323402095146195083832321653866435038288984592561264122609900445283242546687471212495772374739516246400847588541261538014921099786354480981323941352342956967519229365708427144944158167030641814228162018262559974306743969426631986328473326552950914120785997439250417606784364252988144332034545313093688059361562059288052521134894326154592297800761402653576813233238712177345631801969087629975124115561051586961571367538498874455961369510791916487276201056701610338632918982007211666317353887680867379020893319973149790797046757090603649669082104310239858114588123150192908647053832017162512322729760541189558019686491325906992554496272419233328395771748054356943186991073562058874911317743255138444360845311478086058195775312157015714097879313910243290833104869980171091798881750455357454331259443560382690398704362700213173291695640213925882110910157863436536439801068612310353127040268848116997020547289175100471863146978240820441707769832918572853266108036640942524478154402695340246739254704000411876235655263369826495584686341645563156370884437130290181853235565977800300603831399547050238126669442728749982789272124465603675348435144745635388687435006192638481030382340929056109762108183891944198036411324908984480371364444140544930522892141320510755969915832099771282067441005201138001729464576032033548036857959002530433282991621920300573956660792027505558896896750607273217014434183370055183628349448527995694575091524369370738408020702064740727713823926058420279369567666340945730483846187154196412360191385878200417040193218783328955154570290972611266617228917342437972229011399854546332163746602024785592935877253867102814520251609081449445689514363259492562958159381469898952085338293271848963111426670903432731024032973592372229727976066949721341315484139299920585103150584303453391064753345433096918434248082843766481253128036334775997016582718307095563644395772660841842365066433975239195981979702063837479168950079853912247772084192408551668654378539661913870935307631947055549286214490878100815150589445525656939051938748516603698927622608659483593846910344418788161999114984906498606339662995899004923132055176363269389766320299752168731627462126711313852608514772244617234659318909544837898598773489586835031901008392535705655727253878139282455372480326200200416465361254447348699530210740478313342409481892371561290330783063936070857419579417434947243613471494066249513527291269447022599816340005803785176005268882483951468288051479735757407181069853050123627156745846901404505606403596780719225586169206292195738387713944454872851783098422707322817499669986343002168796540678658204951583040780246146278173527368456629069404593113313549935109702734434192853851594505005249338153859292247064371240884181623876690682354453172508604317085504970383100494644118800590831253412163556826941252108665208934176033276916840204780258011229201882568265379832070616306690636164214156228066479950667209438130734032059077277477464870895571382782708256285803886685460532881468431147869342129762174470492281276486951916874562321661573493391436798711349795535862677737189922299942035924382097917320286759104463382379391182614411689196800166162313872671352157506526722260343947990645495864883916509420544755319428702629102670352924670599328834271321057949611225168768808280201781935785958753746366245763541108780777861290101282845964196031063230421538273482875641388023633896044071261489754152183396640427993034977272382110961464138521225616600567537144114533865033193331793908755337195566467626776133304397893626909454222199276876741300887616911894982709518002489905831886147544178479410270019463476337047609150369605949742839931220143785577891326912561456693482047553350117151904654352683708676489000512540572438492536782032178681514445729389320085806603189178441603275827117104760411536194056695872329072743871348035596876926424273163264711284825289301480939822800753875819792237388973302227450201249621479484022614930390233909101579238764849443128866087773002940487137007179703256300036509602618140465817140008551664483090931675606693510121310269302996642209849786508088059277962199026429745267243357950200013088956618305067991924945288603483803650604712564734238239799077635143685369767623291315958982110968638716077267327597929709381320967605851723213423097697315273336573365367663405132900698156857827709475977737707778369217131740744300600243295427286247772753996189686903325572343170708250226449682077360450024969818522215108187622134380972322925050259218415202183925881832663855175614869693877302164321814616257036817819517875922945255122100197395756575670671163255087317728553301029428203010412087790305260378321638215746423500920302851353883422263721272848679528708604810035294970895899356204579731008834580519971159271542107827658047448652697839440109562800787332508880599341798923688291957788434472509974434840940514291129493802079087570277052644572423534425486144963329603152502823568024664362085062888096997958303096454366886163549086843503996304745765252556222885151478180783628653389149315509982543359919642585515224454017028193751572885191649721797717162951058033158008891901553683680936442345655154256596995960638023478788726886936843518881420467609490168619373129985628233302650364753572315947694146049143505169338596983847167120761532162975214622612856144912483616816394556336546481627264956030388737750232897505620779059844231802230314838673719389260879940334633632209428013708918655679781839427980518484638148432944714586744885818777182505242204982128653641431089682642896471206086801237813137881100405696324799706859073413978413254151706908593221528439530481029792615664652219692223761680638774669643543167422970713271372111019022439505039986476398544273557890889134749255904061385340230175418262391773887951265614364147382166301246510125567118283244478595078773942261581170684780911774925342876768926849795955601358368269557298089347429559037336403837311677387583844265599631578191041759819742780495675816090767930917805743791536171827469556272559442726548329337974853676023717511823226402860499230841996391047759736258672175167904601161710432102181949226863132804628163399196416226536533852376900313102545822139518989940059953990291881032013946112700982652836236217763864639158621912512546866491471934452460943415999912423365503581688384791052234733008306407963619698959393246077083866051518449501168579989293652597353306950738399124109660144302431850211682991899661416804997879769612646548013406287004812950712478893808170241669932024532061940689433431711448825967085322295366187487292431493993711335045812052535495813436999291036039672996428065513920793381646030001557445728926127888742945315555189839781167218743319544203299046329210876937387117027153947944562029244084758441671920062972547719257141688915320772750365063502200222932625349070611892872249093039862648032958949502335360501603548158478411101874788121263632608610129653384720546284061589519514964689002071009295777935278665822044520431707982212933142946693054493092442463638052556616809713601102058426109010671889907071674285529340990287030410596500289684345252164508798179520857930310464376012803017102309514629897633385315463664632026897681995336242256968707675133709731664236937108183250716843835595672394608877151237367609749988593330300505386317889656434424482310551102193122231694714858394975958975291705348533342193459968025757839068777118863067353562149434186050500231209695240869558538871397732228800664849097185480473459100616472044945421539865861116073589713844444361850503180390850562061288622707786406558331200980491641970361070033112080218691451894687308076607277149081243721918309656561990974470375402180454313444717353245713493637620029285506975658006609087934354803017608774609325263217467845409217230255222957082528713049265066428055337699748620509830880629091028782709912749855280461374821095191823297119343220587424795544783915404457373496019287704738592440235265646755346595842967844575200407339875353019311927850171656776418748430195170158620677734530447045064866077457476563196105522399698200452472168654225039427708157654887683140644047919289045330550402368534148373331544850836074934595998477074283645939421958961311353595951765148682579558642475564336234027260423381771097735554777075939554211023213350454830594240227755142803116477048206767988110195526305660481691948716070951129850512251004744998852865235974170751595853041541138030055057797845896290285038314619589871821356242750620555240027762839628321651776458581238457463082299253075387954353900342065876024625961174892573403306195660799556747651630180766480375810344925371342561386557438471982852321462981674276889563699906107206676460982043240972339818460489369290872519523292822541894034547175012222587652732374230434599471193779319822970193706465252692037304096095772185044537765805106092155201662833882521465672358683487277769241997093377980420100041532479454584652236527679759096287910415037863579870334041995956556531533311691438649708954996880594141990486182190242929613674774081397267388078906973463271907633913846637193032374705628278454221063548452859137574164086024381219483921497236151365146658508525351779177626422526948869217059825585677637456774727745686102875546541170430384194869344579983898885559197638969235806913051131165113236650552197171

Execution Trace

MetaSwap.60c06040( )
  • Spender.60a06040( )
    File 1 of 2: MetaSwap
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "../Constants.sol";
    contract CommonAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        /**
         * @dev Performs a swap
         * @param recipient The original msg.sender performing the swap
         * @param aggregator Address of the aggregator's contract
         * @param spender Address to which tokens will be approved
         * @param method Selector of the function to be called in the aggregator's contract
         * @param tokenFrom Token to be swapped
         * @param tokenTo Token to be received
         * @param amountFrom Amount of tokenFrom to swap
         * @param amountTo Minimum amount of tokenTo to receive
         * @param data Data used for the call made to the aggregator's contract
         */
        function swap(
            address payable recipient,
            address aggregator,
            address spender,
            bytes4 method,
            IERC20 tokenFrom,
            IERC20 tokenTo,
            uint256 amountFrom,
            uint256 amountTo,
            bytes calldata data
        ) external payable {
            require(tokenFrom != tokenTo, "TOKEN_PAIR_INVALID");
            if (address(tokenFrom) != Constants.ETH) {
                _approveSpender(tokenFrom, spender, amountFrom);
            }
            // We always forward msg.value as it may be necessary to pay fees
            bytes memory encodedData = abi.encodePacked(method, data);
            aggregator.functionCallWithValue(encodedData, msg.value);
            // Transfer remaining balance of tokenFrom to sender
            if (address(tokenFrom) != Constants.ETH) {
                uint256 balance = tokenFrom.balanceOf(address(this));
                _transfer(tokenFrom, balance, recipient);
            }
            uint256 weiBalance = address(this).balance;
            // Transfer remaining balance of tokenTo to sender
            if (address(tokenTo) != Constants.ETH) {
                uint256 balance = tokenTo.balanceOf(address(this));
                require(balance >= amountTo, "INSUFFICIENT_AMOUNT");
                _transfer(tokenTo, balance, recipient);
            } else {
                // If tokenTo == ETH, then check that the remaining ETH balance >= amountTo
                require(weiBalance >= amountTo, "INSUFFICIENT_AMOUNT");
            }
            // If there are unused fees or if tokenTo is ETH, transfer to sender
            if (weiBalance > 0) {
                recipient.sendValue(weiBalance);
            }
        }
        /**
         * @dev Transfers token to sender if amount > 0
         * @param token IERC20 token to transfer to sender
         * @param amount Amount of token to transfer
         * @param recipient Address that will receive the tokens
         */
        function _transfer(
            IERC20 token,
            uint256 amount,
            address recipient
        ) internal {
            if (amount > 0) {
                token.safeTransfer(recipient, amount);
            }
        }
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol
        /**
         * @dev Approves max amount of token to the spender if the allowance is lower than amount
         * @param token The ERC20 token to approve
         * @param spender Address to which funds will be approved
         * @param amount Amount used to compare current allowance
         */
        function _approveSpender(
            IERC20 token,
            address spender,
            uint256 amount
        ) internal {
            // If allowance is not enough, approve max possible amount
            uint256 allowance = token.allowance(address(this), spender);
            if (allowance < amount) {
                bytes memory returndata = address(token).functionCall(
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        type(uint256).max
                    )
                );
                if (returndata.length > 0) {
                    // Return data is optional
                    require(abi.decode(returndata, (bool)), "APPROVAL_FAILED");
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    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);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "./IERC20.sol";
    import "../../math/SafeMath.sol";
    import "../../utils/Address.sol";
    /**
     * @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");
            }
        }
    }
    // SPDX-License-Identifier: MIT
    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;
        }
    }
    // SPDX-License-Identifier: MIT
    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) {
            // This method relies in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly { size := extcodesize(account) }
            return size > 0;
        }
        /**
         * @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);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    library Constants {
        address internal constant ETH = 0x0000000000000000000000000000000000000000;
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/math/SafeMath.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "../Constants.sol";
    contract FeeCommonAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        using SafeMath for uint256;
        // solhint-disable-next-line var-name-mixedcase
        address payable public immutable FEE_WALLET;
        constructor(address payable feeWallet) public {
            FEE_WALLET = feeWallet;
        }
        /**
         * @dev Performs a swap
         * @param recipient The original msg.sender performing the swap
         * @param aggregator Address of the aggregator's contract
         * @param spender Address to which tokens will be approved
         * @param method Selector of the function to be called in the aggregator's contract
         * @param tokenFrom Token to be swapped
         * @param tokenTo Token to be received
         * @param amountFrom Amount of tokenFrom to swap
         * @param amountTo Minimum amount of tokenTo to receive
         * @param data Data used for the call made to the aggregator's contract
         * @param fee Amount of tokenFrom sent to the fee wallet
         */
        function swap(
            address payable recipient,
            address aggregator,
            address spender,
            bytes4 method,
            IERC20 tokenFrom,
            IERC20 tokenTo,
            uint256 amountFrom,
            uint256 amountTo,
            bytes calldata data,
            uint256 fee
        ) external payable {
            require(tokenFrom != tokenTo, "TOKEN_PAIR_INVALID");
            if (address(tokenFrom) == Constants.ETH) {
                FEE_WALLET.sendValue(fee);
            } else {
                _transfer(tokenFrom, fee, FEE_WALLET);
                _approveSpender(tokenFrom, spender, amountFrom);
            }
            // We always forward msg.value as it may be necessary to pay fees
            aggregator.functionCallWithValue(
                abi.encodePacked(method, data),
                address(this).balance
            );
            // Transfer remaining balance of tokenFrom to sender
            if (address(tokenFrom) != Constants.ETH) {
                _transfer(tokenFrom, tokenFrom.balanceOf(address(this)), recipient);
            }
            uint256 weiBalance = address(this).balance;
            // Transfer remaining balance of tokenTo to sender
            if (address(tokenTo) != Constants.ETH) {
                uint256 balance = tokenTo.balanceOf(address(this));
                require(balance >= amountTo, "INSUFFICIENT_AMOUNT");
                _transfer(tokenTo, balance, recipient);
            } else {
                // If tokenTo == ETH, then check that the remaining ETH balance >= amountTo
                require(weiBalance >= amountTo, "INSUFFICIENT_AMOUNT");
            }
            // If there are unused fees or if tokenTo is ETH, transfer to sender
            if (weiBalance > 0) {
                recipient.sendValue(weiBalance);
            }
        }
        /**
         * @dev Transfers token to sender if amount > 0
         * @param token IERC20 token to transfer to sender
         * @param amount Amount of token to transfer
         * @param recipient Address that will receive the tokens
         */
        function _transfer(
            IERC20 token,
            uint256 amount,
            address recipient
        ) internal {
            if (amount > 0) {
                token.safeTransfer(recipient, amount);
            }
        }
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol
        /**
         * @dev Approves max amount of token to the spender if the allowance is lower than amount
         * @param token The ERC20 token to approve
         * @param spender Address to which funds will be approved
         * @param amount Amount used to compare current allowance
         */
        function _approveSpender(
            IERC20 token,
            address spender,
            uint256 amount
        ) internal {
            // If allowance is not enough, approve max possible amount
            uint256 allowance = token.allowance(address(this), spender);
            if (allowance < amount) {
                bytes memory returndata = address(token).functionCall(
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        type(uint256).max
                    )
                );
                if (returndata.length > 0) {
                    // Return data is optional
                    require(abi.decode(returndata, (bool)), "APPROVAL_FAILED");
                }
            }
        }
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/math/SafeMath.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "../Constants.sol";
    import "../IWETH.sol";
    contract FeeWethAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        using SafeMath for uint256;
        IWETH public immutable weth;
        // solhint-disable-next-line var-name-mixedcase
        address payable public immutable FEE_WALLET;
        constructor(IWETH _weth, address payable feeWallet) public {
            weth = _weth;
            FEE_WALLET = feeWallet;
        }
        /**
         * @dev Performs a swap
         * @param recipient The original msg.sender performing the swap
         * @param aggregator Address of the aggregator's contract
         * @param spender Address to which tokens will be approved
         * @param method Selector of the function to be called in the aggregator's contract
         * @param tokenFrom Token to be swapped
         * @param tokenTo Token to be received
         * @param amountFrom Amount of tokenFrom to swap
         * @param amountTo Minimum amount of tokenTo to receive
         * @param data Data used for the call made to the aggregator's contract
         * @param fee Amount of tokenFrom sent to the fee wallet
         */
        function swap(
            address payable recipient,
            address aggregator,
            address spender,
            bytes4 method,
            IERC20 tokenFrom,
            IERC20 tokenTo,
            uint256 amountFrom,
            uint256 amountTo,
            bytes calldata data,
            uint256 fee
        ) external payable {
            require(tokenFrom != tokenTo, "TOKEN_PAIR_INVALID");
            if (address(tokenFrom) == Constants.ETH) {
                FEE_WALLET.sendValue(fee);
                // If tokenFrom is ETH, msg.value = fee + amountFrom (total fee could be 0)
                // Can't deal with ETH, convert to WETH, the remaining balance will be the fee
                weth.deposit{value: amountFrom}();
                _approveSpender(weth, spender, amountFrom);
            } else {
                _transfer(tokenFrom, fee, FEE_WALLET);
                // Otherwise capture tokens from sender
                _approveSpender(tokenFrom, spender, amountFrom);
            }
            // Perform the swap
            aggregator.functionCallWithValue(
                abi.encodePacked(method, data),
                address(this).balance
            );
            // Transfer remaining balance of tokenFrom to sender
            if (address(tokenFrom) != Constants.ETH) {
                _transfer(tokenFrom, tokenFrom.balanceOf(address(this)), recipient);
            } else {
                // If using ETH, just unwrap any remaining WETH
                // At the end of this function all ETH will be transferred to the sender
                _unwrapWETH();
            }
            uint256 weiBalance = address(this).balance;
            // Transfer remaining balance of tokenTo to sender
            if (address(tokenTo) != Constants.ETH) {
                uint256 balance = tokenTo.balanceOf(address(this));
                require(balance >= amountTo, "INSUFFICIENT_AMOUNT");
                _transfer(tokenTo, balance, recipient);
            } else {
                // If tokenTo == ETH, unwrap received WETH and add it to the wei balance,
                // then check that the remaining ETH balance >= amountTo
                // It is safe to not use safeMath as no one can have enough Ether to overflow
                weiBalance += _unwrapWETH();
                require(weiBalance >= amountTo, "INSUFFICIENT_AMOUNT");
            }
            // If there are unused fees or if tokenTo is ETH, transfer to sender
            if (weiBalance > 0) {
                recipient.sendValue(weiBalance);
            }
        }
        /**
         * @dev Unwraps all available WETH into ETH
         */
        function _unwrapWETH() internal returns (uint256) {
            uint256 balance = weth.balanceOf(address(this));
            weth.withdraw(balance);
            return balance;
        }
        /**
         * @dev Transfers token to sender if amount > 0
         * @param token IERC20 token to transfer to sender
         * @param amount Amount of token to transfer
         * @param recipient Address that will receive the tokens
         */
        function _transfer(
            IERC20 token,
            uint256 amount,
            address recipient
        ) internal {
            if (amount > 0) {
                token.safeTransfer(recipient, amount);
            }
        }
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol
        /**
         * @dev Approves max amount of token to the spender if the allowance is lower than amount
         * @param token The ERC20 token to approve
         * @param spender Address to which funds will be approved
         * @param amount Amount used to compare current allowance
         */
        function _approveSpender(
            IERC20 token,
            address spender,
            uint256 amount
        ) internal {
            // If allowance is not enough, approve max possible amount
            uint256 allowance = token.allowance(address(this), spender);
            if (allowance < amount) {
                bytes memory returndata = address(token).functionCall(
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        type(uint256).max
                    )
                );
                if (returndata.length > 0) {
                    // Return data is optional
                    require(abi.decode(returndata, (bool)), "APPROVAL_FAILED");
                }
            }
        }
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    interface IWETH is IERC20 {
        function deposit() external payable;
        function withdraw(uint256) external;
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/math/SafeMath.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
    import "../Constants.sol";
    contract UniswapAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        using SafeMath for uint256;
        // solhint-disable-next-line var-name-mixedcase
        IUniswapV2Router02 public immutable UNISWAP;
        // solhint-disable-next-line var-name-mixedcase
        address payable public immutable FEE_WALLET;
        constructor(address payable feeWallet, IUniswapV2Router02 uniswap) public {
            FEE_WALLET = feeWallet;
            UNISWAP = uniswap;
        }
        /**
         * @dev Performs a swap
         * @param recipient The original msg.sender performing the swap
         * @param tokenFrom Token to be swapped
         * @param tokenTo Token to be received
         * @param amountFrom Amount of tokenFrom to swap
         * @param amountTo Minimum amount of tokenTo to receive
         * @param path Used by Uniswap
         * @param deadline Timestamp at which the swap becomes invalid. Used by Uniswap
         * @param feeOnTransfer Use `supportingFeeOnTransfer` Uniswap methods
         * @param fee Amount of tokenFrom sent to the fee wallet
         */
        function swap(
            address payable recipient,
            IERC20 tokenFrom,
            IERC20 tokenTo,
            uint256 amountFrom,
            uint256 amountTo,
            address[] calldata path,
            uint256 deadline,
            bool feeOnTransfer,
            uint256 fee
        ) external payable {
            require(tokenFrom != tokenTo, "TOKEN_PAIR_INVALID");
            if (address(tokenFrom) == Constants.ETH) {
                FEE_WALLET.sendValue(fee);
            } else {
                _transfer(tokenFrom, fee, FEE_WALLET);
            }
            if (address(tokenFrom) == Constants.ETH) {
                if (feeOnTransfer) {
                    UNISWAP.swapExactETHForTokensSupportingFeeOnTransferTokens{
                        value: address(this).balance
                    }(amountTo, path, address(this), deadline);
                } else {
                    UNISWAP.swapExactETHForTokens{value: address(this).balance}(
                        amountTo,
                        path,
                        address(this),
                        deadline
                    );
                }
            } else {
                _approveSpender(tokenFrom, address(UNISWAP), amountFrom);
                if (address(tokenTo) == Constants.ETH) {
                    if (feeOnTransfer) {
                        UNISWAP.swapExactTokensForETHSupportingFeeOnTransferTokens(
                            amountFrom,
                            amountTo,
                            path,
                            address(this),
                            deadline
                        );
                    } else {
                        UNISWAP.swapExactTokensForETH(
                            amountFrom,
                            amountTo,
                            path,
                            address(this),
                            deadline
                        );
                    }
                } else {
                    if (feeOnTransfer) {
                        UNISWAP
                            .swapExactTokensForTokensSupportingFeeOnTransferTokens(
                            amountFrom,
                            amountTo,
                            path,
                            address(this),
                            deadline
                        );
                    } else {
                        UNISWAP.swapExactTokensForTokens(
                            amountFrom,
                            amountTo,
                            path,
                            address(this),
                            deadline
                        );
                    }
                }
            }
            // Transfer remaining balance of tokenFrom to sender
            if (address(tokenFrom) != Constants.ETH) {
                _transfer(tokenFrom, tokenFrom.balanceOf(address(this)), recipient);
            }
            uint256 weiBalance = address(this).balance;
            // Transfer remaining balance of tokenTo to sender
            if (address(tokenTo) != Constants.ETH) {
                uint256 balance = tokenTo.balanceOf(address(this));
                require(balance >= amountTo, "INSUFFICIENT_AMOUNT");
                _transfer(tokenTo, balance, recipient);
            } else {
                // If tokenTo == ETH, then check that the remaining ETH balance >= amountTo
                require(weiBalance >= amountTo, "INSUFFICIENT_AMOUNT");
            }
            // If there are unused fees or if tokenTo is ETH, transfer to sender
            if (weiBalance > 0) {
                recipient.sendValue(weiBalance);
            }
        }
        /**
         * @dev Transfers token to sender if amount > 0
         * @param token IERC20 token to transfer to sender
         * @param amount Amount of token to transfer
         * @param recipient Address that will receive the tokens
         */
        function _transfer(
            IERC20 token,
            uint256 amount,
            address recipient
        ) internal {
            if (amount > 0) {
                token.safeTransfer(recipient, amount);
            }
        }
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol
        /**
         * @dev Approves max amount of token to the spender if the allowance is lower than amount
         * @param token The ERC20 token to approve
         * @param spender Address to which funds will be approved
         * @param amount Amount used to compare current allowance
         */
        function _approveSpender(
            IERC20 token,
            address spender,
            uint256 amount
        ) internal {
            // If allowance is not enough, approve max possible amount
            uint256 allowance = token.allowance(address(this), spender);
            if (allowance < amount) {
                bytes memory returndata = address(token).functionCall(
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        type(uint256).max
                    )
                );
                if (returndata.length > 0) {
                    // Return data is optional
                    require(abi.decode(returndata, (bool)), "APPROVAL_FAILED");
                }
            }
        }
    }
    pragma solidity >=0.6.2;
    import './IUniswapV2Router01.sol';
    interface IUniswapV2Router02 is IUniswapV2Router01 {
        function removeLiquidityETHSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountETH);
        function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountETH);
        function swapExactTokensForTokensSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
        function swapExactETHForTokensSupportingFeeOnTransferTokens(
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable;
        function swapExactTokensForETHSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
    }
    pragma solidity >=0.6.2;
    interface IUniswapV2Router01 {
        function factory() external pure returns (address);
        function WETH() external pure returns (address);
        function addLiquidity(
            address tokenA,
            address tokenB,
            uint amountADesired,
            uint amountBDesired,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB, uint liquidity);
        function addLiquidityETH(
            address token,
            uint amountTokenDesired,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
        function removeLiquidity(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETH(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountToken, uint amountETH);
        function removeLiquidityWithPermit(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETHWithPermit(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountToken, uint amountETH);
        function swapExactTokensForTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapTokensForExactTokens(
            uint amountOut,
            uint amountInMax,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
        function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
        function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
        function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
        function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
        function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
        function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
        function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
        function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "../Constants.sol";
    import "../IWETH.sol";
    contract WethAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        IWETH public immutable weth;
        constructor(IWETH _weth) public {
            weth = _weth;
        }
        /**
         * @dev Performs a swap
         * @param recipient The original msg.sender performing the swap
         * @param aggregator Address of the aggregator's contract
         * @param spender Address to which tokens will be approved
         * @param method Selector of the function to be called in the aggregator's contract
         * @param tokenFrom Token to be swapped
         * @param tokenTo Token to be received
         * @param amountFrom Amount of tokenFrom to swap
         * @param amountTo Minimum amount of tokenTo to receive
         * @param data Data used for the call made to the aggregator's contract
         */
        function swap(
            address payable recipient,
            address aggregator,
            address spender,
            bytes4 method,
            IERC20 tokenFrom,
            IERC20 tokenTo,
            uint256 amountFrom,
            uint256 amountTo,
            bytes calldata data
        ) external payable {
            require(tokenFrom != tokenTo, "TOKEN_PAIR_INVALID");
            if (address(tokenFrom) == Constants.ETH) {
                // If tokenFrom is ETH, msg.value = fee + amountFrom (total fee could be 0)
                // Can't deal with ETH, convert to WETH, the remaining balance will be the fee
                weth.deposit{value: amountFrom}();
                _approveSpender(weth, spender, amountFrom);
            } else {
                // Otherwise capture tokens from sender
                _approveSpender(tokenFrom, spender, amountFrom);
            }
            // Perform the swap
            aggregator.functionCallWithValue(
                abi.encodePacked(method, data),
                address(this).balance
            );
            // Transfer remaining balance of tokenFrom to sender
            if (address(tokenFrom) != Constants.ETH) {
                _transfer(tokenFrom, tokenFrom.balanceOf(address(this)), recipient);
            } else {
                // If using ETH, just unwrap any remaining WETH
                // At the end of this function all ETH will be transferred to the sender
                _unwrapWETH();
            }
            uint256 weiBalance = address(this).balance;
            // Transfer remaining balance of tokenTo to sender
            if (address(tokenTo) != Constants.ETH) {
                uint256 balance = tokenTo.balanceOf(address(this));
                require(balance >= amountTo, "INSUFFICIENT_AMOUNT");
                _transfer(tokenTo, balance, recipient);
            } else {
                // If tokenTo == ETH, unwrap received WETH and add it to the wei balance,
                // then check that the remaining ETH balance >= amountTo
                // It is safe to not use safeMath as no one can have enough Ether to overflow
                weiBalance += _unwrapWETH();
                require(weiBalance >= amountTo, "INSUFFICIENT_AMOUNT");
            }
            // If there are unused fees or if tokenTo is ETH, transfer to sender
            if (weiBalance > 0) {
                recipient.sendValue(weiBalance);
            }
        }
        /**
         * @dev Unwraps all available WETH into ETH
         */
        function _unwrapWETH() internal returns (uint256) {
            uint256 balance = weth.balanceOf(address(this));
            weth.withdraw(balance);
            return balance;
        }
        /**
         * @dev Transfers token to sender if amount > 0
         * @param token IERC20 token to transfer to sender
         * @param amount Amount of token to transfer
         * @param recipient Address that will receive the tokens
         */
        function _transfer(
            IERC20 token,
            uint256 amount,
            address recipient
        ) internal {
            if (amount > 0) {
                token.safeTransfer(recipient, amount);
            }
        }
        // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/SafeERC20.sol
        /**
         * @dev Approves max amount of token to the spender if the allowance is lower than amount
         * @param token The ERC20 token to approve
         * @param spender Address to which funds will be approved
         * @param amount Amount used to compare current allowance
         */
        function _approveSpender(
            IERC20 token,
            address spender,
            uint256 amount
        ) internal {
            // If allowance is not enough, approve max possible amount
            uint256 allowance = token.allowance(address(this), spender);
            if (allowance < amount) {
                bytes memory returndata = address(token).functionCall(
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        type(uint256).max
                    )
                );
                if (returndata.length > 0) {
                    // Return data is optional
                    require(abi.decode(returndata, (bool)), "APPROVAL_FAILED");
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    interface ICHI is IERC20 {
        function freeUpTo(uint256 value) external returns (uint256);
        function freeFromUpTo(
            address from,
            uint256 value
        ) external returns (uint256);
        function mint(uint256 value) external;
    }
      
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.6.0;
    // We import the contract so truffle compiles it, and we have the ABI
    // available when working from truffle console.
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; //helpers// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "../../GSN/Context.sol";
    import "./IERC20.sol";
    import "../../math/SafeMath.sol";
    import "../../utils/Address.sol";
    /**
     * @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 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 { }
    }
    // 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;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "@openzeppelin/contracts/utils/Pausable.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "./ICHI.sol";
    import "./Spender.sol";
    /**
     * @title MetaSwap
     */
    contract MetaSwap is Ownable, Pausable, ReentrancyGuard {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        struct Adapter {
            address addr; // adapter's address
            bytes4 selector;
            bytes data; // adapter's fixed data
        }
        ICHI public immutable chi;
        Spender public immutable spender;
        // Mapping of aggregatorId to aggregator
        mapping(string => Adapter) public adapters;
        mapping(string => bool) public adapterRemoved;
        event AdapterSet(
            string indexed aggregatorId,
            address indexed addr,
            bytes4 selector,
            bytes data
        );
        event AdapterRemoved(string indexed aggregatorId);
        event Swap(string indexed aggregatorId, address indexed sender);
        constructor(ICHI _chi) public {
            chi = _chi;
            spender = new Spender();
        }
        /**
         * @dev Sets the adapter for an aggregator. It can't be changed later.
         * @param aggregatorId Aggregator's identifier
         * @param addr Address of the contract that contains the logic for this aggregator
         * @param selector The function selector of the swap function in the adapter
         * @param data Fixed abi encoded data the will be passed in each delegatecall made to the adapter
         */
        function setAdapter(
            string calldata aggregatorId,
            address addr,
            bytes4 selector,
            bytes calldata data
        ) external onlyOwner {
            require(addr.isContract(), "ADAPTER_IS_NOT_A_CONTRACT");
            require(!adapterRemoved[aggregatorId], "ADAPTER_REMOVED");
            Adapter storage adapter = adapters[aggregatorId];
            require(adapter.addr == address(0), "ADAPTER_EXISTS");
            adapter.addr = addr;
            adapter.selector = selector;
            adapter.data = data;
            emit AdapterSet(aggregatorId, addr, selector, data);
        }
        /**
         * @dev Removes the adapter for an existing aggregator. This can't be undone.
         * @param aggregatorId Aggregator's identifier
         */
        function removeAdapter(string calldata aggregatorId) external onlyOwner {
            require(
                adapters[aggregatorId].addr != address(0),
                "ADAPTER_DOES_NOT_EXIST"
            );
            delete adapters[aggregatorId];
            adapterRemoved[aggregatorId] = true;
            emit AdapterRemoved(aggregatorId);
        }
        /**
         * @dev Performs a swap
         * @param aggregatorId Identifier of the aggregator to be used for the swap
         * @param data Dynamic data which is concatenated with the fixed aggregator's
         * data in the delecatecall made to the adapter
         */
        function swap(
            string calldata aggregatorId,
            IERC20 tokenFrom,
            uint256 amount,
            bytes calldata data
        ) external payable whenNotPaused nonReentrant {
            _swap(aggregatorId, tokenFrom, amount, data);
        }
        /**
         * @dev Performs a swap
         * @param aggregatorId Identifier of the aggregator to be used for the swap
         * @param data Dynamic data which is concatenated with the fixed aggregator's
         * data in the delecatecall made to the adapter
         */
        function swapUsingGasToken(
            string calldata aggregatorId,
            IERC20 tokenFrom,
            uint256 amount,
            bytes calldata data
        ) external payable whenNotPaused nonReentrant {
            uint256 gas = gasleft();
            _swap(aggregatorId, tokenFrom, amount, data);
            uint256 gasSpent = 21000 + gas - gasleft() + 16 * msg.data.length;
            chi.freeFromUpTo(msg.sender, (gasSpent + 14154) / 41947);
        }
        function pauseSwaps() external onlyOwner {
            _pause();
        }
        function unpauseSwaps() external onlyOwner {
            _unpause();
        }
        function _swap(
            string calldata aggregatorId,
            IERC20 tokenFrom,
            uint256 amount,
            bytes calldata data
        ) internal {
            Adapter storage adapter = adapters[aggregatorId];
            if (address(tokenFrom) != Constants.ETH) {
                tokenFrom.safeTransferFrom(msg.sender, address(spender), amount);
            }
            spender.swap{value: msg.value}(
                adapter.addr,
                abi.encodePacked(
                    adapter.selector,
                    abi.encode(msg.sender),
                    adapter.data,
                    data
                )
            );
            emit Swap(aggregatorId, msg.sender);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "../GSN/Context.sol";
    /**
     * @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;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "../GSN/Context.sol";
    /**
     * @dev Contract module which allows children to implement an emergency stop
     * mechanism that can be triggered by an authorized account.
     *
     * This module is used through inheritance. It will make available the
     * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
     * the functions of your contract. Note that they will not be pausable by
     * simply including this module, only once the modifiers are put in place.
     */
    contract Pausable is Context {
        /**
         * @dev Emitted when the pause is triggered by `account`.
         */
        event Paused(address account);
        /**
         * @dev Emitted when the pause is lifted by `account`.
         */
        event Unpaused(address account);
        bool private _paused;
        /**
         * @dev Initializes the contract in unpaused state.
         */
        constructor () internal {
            _paused = false;
        }
        /**
         * @dev Returns true if the contract is paused, and false otherwise.
         */
        function paused() public view returns (bool) {
            return _paused;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        modifier whenNotPaused() {
            require(!_paused, "Pausable: paused");
            _;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        modifier whenPaused() {
            require(_paused, "Pausable: not paused");
            _;
        }
        /**
         * @dev Triggers stopped state.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        function _pause() internal virtual whenNotPaused {
            _paused = true;
            emit Paused(_msgSender());
        }
        /**
         * @dev Returns to normal state.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        function _unpause() internal virtual whenPaused {
            _paused = false;
            emit Unpaused(_msgSender());
        }
    }
    // SPDX-License-Identifier: MIT
    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;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "./Constants.sol";
    contract Spender {
        address public immutable metaswap;
        constructor() public {
            metaswap = msg.sender;
        }
        /// @dev Receives ether from swaps
        fallback() external payable {}
        function swap(address adapter, bytes calldata data) external payable {
            require(msg.sender == metaswap, "FORBIDDEN");
            require(adapter != address(0), "ADAPTER_NOT_PROVIDED");
            _delegate(adapter, data, "ADAPTER_DELEGATECALL_FAILED");
        }
        /**
         * @dev Performs a delegatecall and bubbles up the errors, adapted from
         * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
         * @param target Address of the contract to delegatecall
         * @param data Data passed in the delegatecall
         * @param errorMessage Fallback revert reason
         */
        function _delegate(
            address target,
            bytes memory data,
            string memory errorMessage
        ) private returns (bytes memory) {
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(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);
                }
            }
        }
    }
    pragma solidity ^0.6.0;
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    import "@openzeppelin/contracts/utils/Address.sol";
    contract MockAdapter {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
        event MockAdapterEvent(
            address sender,
            uint256 valueFixed,
            uint256 valueDynamic
        );
        function test(
            address sender,
            uint256 valueFixed,
            uint256 valueDynamic
        ) external payable {
            emit MockAdapterEvent(sender, valueFixed, valueDynamic);
        }
        function testRevert(
            address,
            uint256,
            uint256
        ) external payable {
            revert("SWAP_FAILED");
        }
        function testRevertNoReturnData(
            address,
            uint256,
            uint256
        ) external payable {
            revert();
        }
    }
    pragma solidity ^0.6.0;
    // TAKEN FROM https://github.com/gnosis/mock-contract
    // TODO: use their npm package once it is published for solidity 0.6
    interface MockInterface {
        /**
         * @dev After calling this method, the mock will return `response` when it is called
         * with any calldata that is not mocked more specifically below
         * (e.g. using givenMethodReturn).
         * @param response ABI encoded response that will be returned if method is invoked
         */
        function givenAnyReturn(bytes calldata response) external;
        function givenAnyReturnBool(bool response) external;
        function givenAnyReturnUint(uint256 response) external;
        function givenAnyReturnAddress(address response) external;
        function givenAnyRevert() external;
        function givenAnyRevertWithMessage(string calldata message) external;
        function givenAnyRunOutOfGas() external;
        /**
         * @dev After calling this method, the mock will return `response` when the given
         * methodId is called regardless of arguments. If the methodId and arguments
         * are mocked more specifically (using `givenMethodAndArguments`) the latter
         * will take precedence.
         * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it
         * @param response ABI encoded response that will be returned if method is invoked
         */
        function givenMethodReturn(bytes calldata method, bytes calldata response)
            external;
        function givenMethodReturnBool(bytes calldata method, bool response)
            external;
        function givenMethodReturnUint(bytes calldata method, uint256 response)
            external;
        function givenMethodReturnAddress(bytes calldata method, address response)
            external;
        function givenMethodRevert(bytes calldata method) external;
        function givenMethodRevertWithMessage(
            bytes calldata method,
            string calldata message
        ) external;
        function givenMethodRunOutOfGas(bytes calldata method) external;
        /**
         * @dev After calling this method, the mock will return `response` when the given
         * methodId is called with matching arguments. These exact calldataMocks will take
         * precedence over all other calldataMocks.
         * @param call ABI encoded calldata (methodId and arguments)
         * @param response ABI encoded response that will be returned if contract is invoked with calldata
         */
        function givenCalldataReturn(bytes calldata call, bytes calldata response)
            external;
        function givenCalldataReturnBool(bytes calldata call, bool response)
            external;
        function givenCalldataReturnUint(bytes calldata call, uint256 response)
            external;
        function givenCalldataReturnAddress(bytes calldata call, address response)
            external;
        function givenCalldataRevert(bytes calldata call) external;
        function givenCalldataRevertWithMessage(
            bytes calldata call,
            string calldata message
        ) external;
        function givenCalldataRunOutOfGas(bytes calldata call) external;
        /**
         * @dev Returns the number of times anything has been called on this mock since last reset
         */
        function invocationCount() external returns (uint256);
        /**
         * @dev Returns the number of times the given method has been called on this mock since last reset
         * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it
         */
        function invocationCountForMethod(bytes calldata method)
            external
            returns (uint256);
        /**
         * @dev Returns the number of times this mock has been called with the exact calldata since last reset.
         * @param call ABI encoded calldata (methodId and arguments)
         */
        function invocationCountForCalldata(bytes calldata call)
            external
            returns (uint256);
        /**
         * @dev Resets all mocked methods and invocation counts.
         */
        function reset() external;
    }
    /**
     * Implementation of the MockInterface.
     */
    contract MockContract is MockInterface {
        enum MockType {Return, Revert, OutOfGas}
        bytes32 public constant MOCKS_LIST_START = hex"01";
        bytes public constant MOCKS_LIST_END = "0xff";
        bytes32 public constant MOCKS_LIST_END_HASH = keccak256(MOCKS_LIST_END);
        bytes4 public constant SENTINEL_ANY_MOCKS = hex"01";
        bytes public constant DEFAULT_FALLBACK_VALUE = abi.encode(false);
        // A linked list allows easy iteration and inclusion checks
        mapping(bytes32 => bytes) calldataMocks;
        mapping(bytes => MockType) calldataMockTypes;
        mapping(bytes => bytes) calldataExpectations;
        mapping(bytes => string) calldataRevertMessage;
        mapping(bytes32 => uint256) calldataInvocations;
        mapping(bytes4 => bytes4) methodIdMocks;
        mapping(bytes4 => MockType) methodIdMockTypes;
        mapping(bytes4 => bytes) methodIdExpectations;
        mapping(bytes4 => string) methodIdRevertMessages;
        mapping(bytes32 => uint256) methodIdInvocations;
        MockType fallbackMockType;
        bytes fallbackExpectation = DEFAULT_FALLBACK_VALUE;
        string fallbackRevertMessage;
        uint256 invocations;
        uint256 resetCount;
        constructor() public {
            calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END;
            methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS;
        }
        function trackCalldataMock(bytes memory call) private {
            bytes32 callHash = keccak256(call);
            if (calldataMocks[callHash].length == 0) {
                calldataMocks[callHash] = calldataMocks[MOCKS_LIST_START];
                calldataMocks[MOCKS_LIST_START] = call;
            }
        }
        function trackMethodIdMock(bytes4 methodId) private {
            if (methodIdMocks[methodId] == 0x0) {
                methodIdMocks[methodId] = methodIdMocks[SENTINEL_ANY_MOCKS];
                methodIdMocks[SENTINEL_ANY_MOCKS] = methodId;
            }
        }
        function _givenAnyReturn(bytes memory response) internal {
            fallbackMockType = MockType.Return;
            fallbackExpectation = response;
        }
        function givenAnyReturn(bytes calldata response) external override {
            _givenAnyReturn(response);
        }
        function givenAnyReturnBool(bool response) external override {
            uint256 flag = response ? 1 : 0;
            _givenAnyReturn(uintToBytes(flag));
        }
        function givenAnyReturnUint(uint256 response) external override {
            _givenAnyReturn(uintToBytes(response));
        }
        function givenAnyReturnAddress(address response) external override {
            _givenAnyReturn(uintToBytes(uint256(response)));
        }
        function givenAnyRevert() external override {
            fallbackMockType = MockType.Revert;
            fallbackRevertMessage = "";
        }
        function givenAnyRevertWithMessage(string calldata message)
            external
            override
        {
            fallbackMockType = MockType.Revert;
            fallbackRevertMessage = message;
        }
        function givenAnyRunOutOfGas() external override {
            fallbackMockType = MockType.OutOfGas;
        }
        function _givenCalldataReturn(bytes memory call, bytes memory response)
            private
        {
            calldataMockTypes[call] = MockType.Return;
            calldataExpectations[call] = response;
            trackCalldataMock(call);
        }
        function givenCalldataReturn(bytes calldata call, bytes calldata response)
            external
            override
        {
            _givenCalldataReturn(call, response);
        }
        function givenCalldataReturnBool(bytes calldata call, bool response)
            external
            override
        {
            uint256 flag = response ? 1 : 0;
            _givenCalldataReturn(call, uintToBytes(flag));
        }
        function givenCalldataReturnUint(bytes calldata call, uint256 response)
            external
            override
        {
            _givenCalldataReturn(call, uintToBytes(response));
        }
        function givenCalldataReturnAddress(bytes calldata call, address response)
            external
            override
        {
            _givenCalldataReturn(call, uintToBytes(uint256(response)));
        }
        function _givenMethodReturn(bytes memory call, bytes memory response)
            private
        {
            bytes4 method = bytesToBytes4(call);
            methodIdMockTypes[method] = MockType.Return;
            methodIdExpectations[method] = response;
            trackMethodIdMock(method);
        }
        function givenMethodReturn(bytes calldata call, bytes calldata response)
            external
            override
        {
            _givenMethodReturn(call, response);
        }
        function givenMethodReturnBool(bytes calldata call, bool response)
            external
            override
        {
            uint256 flag = response ? 1 : 0;
            _givenMethodReturn(call, uintToBytes(flag));
        }
        function givenMethodReturnUint(bytes calldata call, uint256 response)
            external
            override
        {
            _givenMethodReturn(call, uintToBytes(response));
        }
        function givenMethodReturnAddress(bytes calldata call, address response)
            external
            override
        {
            _givenMethodReturn(call, uintToBytes(uint256(response)));
        }
        function givenCalldataRevert(bytes calldata call) external override {
            calldataMockTypes[call] = MockType.Revert;
            calldataRevertMessage[call] = "";
            trackCalldataMock(call);
        }
        function givenMethodRevert(bytes calldata call) external override {
            bytes4 method = bytesToBytes4(call);
            methodIdMockTypes[method] = MockType.Revert;
            trackMethodIdMock(method);
        }
        function givenCalldataRevertWithMessage(
            bytes calldata call,
            string calldata message
        ) external override {
            calldataMockTypes[call] = MockType.Revert;
            calldataRevertMessage[call] = message;
            trackCalldataMock(call);
        }
        function givenMethodRevertWithMessage(
            bytes calldata call,
            string calldata message
        ) external override {
            bytes4 method = bytesToBytes4(call);
            methodIdMockTypes[method] = MockType.Revert;
            methodIdRevertMessages[method] = message;
            trackMethodIdMock(method);
        }
        function givenCalldataRunOutOfGas(bytes calldata call) external override {
            calldataMockTypes[call] = MockType.OutOfGas;
            trackCalldataMock(call);
        }
        function givenMethodRunOutOfGas(bytes calldata call) external override {
            bytes4 method = bytesToBytes4(call);
            methodIdMockTypes[method] = MockType.OutOfGas;
            trackMethodIdMock(method);
        }
        function invocationCount() external override returns (uint256) {
            return invocations;
        }
        function invocationCountForMethod(bytes calldata call)
            external
            override
            returns (uint256)
        {
            bytes4 method = bytesToBytes4(call);
            return
                methodIdInvocations[keccak256(
                    abi.encodePacked(resetCount, method)
                )];
        }
        function invocationCountForCalldata(bytes calldata call)
            external
            override
            returns (uint256)
        {
            return
                calldataInvocations[keccak256(abi.encodePacked(resetCount, call))];
        }
        function reset() external override {
            // Reset all exact calldataMocks
            bytes memory nextMock = calldataMocks[MOCKS_LIST_START];
            bytes32 mockHash = keccak256(nextMock);
            // We cannot compary bytes
            while (mockHash != MOCKS_LIST_END_HASH) {
                // Reset all mock maps
                calldataMockTypes[nextMock] = MockType.Return;
                calldataExpectations[nextMock] = hex"";
                calldataRevertMessage[nextMock] = "";
                // Set next mock to remove
                nextMock = calldataMocks[mockHash];
                // Remove from linked list
                calldataMocks[mockHash] = "";
                // Update mock hash
                mockHash = keccak256(nextMock);
            }
            // Clear list
            calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END;
            // Reset all any calldataMocks
            bytes4 nextAnyMock = methodIdMocks[SENTINEL_ANY_MOCKS];
            while (nextAnyMock != SENTINEL_ANY_MOCKS) {
                bytes4 currentAnyMock = nextAnyMock;
                methodIdMockTypes[currentAnyMock] = MockType.Return;
                methodIdExpectations[currentAnyMock] = hex"";
                methodIdRevertMessages[currentAnyMock] = "";
                nextAnyMock = methodIdMocks[currentAnyMock];
                // Remove from linked list
                methodIdMocks[currentAnyMock] = 0x0;
            }
            // Clear list
            methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS;
            fallbackExpectation = DEFAULT_FALLBACK_VALUE;
            fallbackMockType = MockType.Return;
            invocations = 0;
            resetCount += 1;
        }
        function useAllGas() private {
            while (true) {
                bool s;
                assembly {
                    //expensive call to EC multiply contract
                    s := call(sub(gas(), 2000), 6, 0, 0x0, 0xc0, 0x0, 0x60)
                }
            }
        }
        function bytesToBytes4(bytes memory b) private pure returns (bytes4) {
            bytes4 out;
            for (uint256 i = 0; i < 4; i++) {
                out |= bytes4(b[i] & 0xFF) >> (i * 8);
            }
            return out;
        }
        function uintToBytes(uint256 x) private pure returns (bytes memory b) {
            b = new bytes(32);
            assembly {
                mstore(add(b, 32), x)
            }
        }
        function updateInvocationCount(
            bytes4 methodId,
            bytes memory originalMsgData
        ) public {
            require(
                msg.sender == address(this),
                "Can only be called from the contract itself"
            );
            invocations += 1;
            methodIdInvocations[keccak256(
                abi.encodePacked(resetCount, methodId)
            )] += 1;
            calldataInvocations[keccak256(
                abi.encodePacked(resetCount, originalMsgData)
            )] += 1;
        }
        fallback() external payable {
            bytes4 methodId;
            assembly {
                methodId := calldataload(0)
            }
            // First, check exact matching overrides
            if (calldataMockTypes[msg.data] == MockType.Revert) {
                revert(calldataRevertMessage[msg.data]);
            }
            if (calldataMockTypes[msg.data] == MockType.OutOfGas) {
                useAllGas();
            }
            bytes memory result = calldataExpectations[msg.data];
            // Then check method Id overrides
            if (result.length == 0) {
                if (methodIdMockTypes[methodId] == MockType.Revert) {
                    revert(methodIdRevertMessages[methodId]);
                }
                if (methodIdMockTypes[methodId] == MockType.OutOfGas) {
                    useAllGas();
                }
                result = methodIdExpectations[methodId];
            }
            // Last, use the fallback override
            if (result.length == 0) {
                if (fallbackMockType == MockType.Revert) {
                    revert(fallbackRevertMessage);
                }
                if (fallbackMockType == MockType.OutOfGas) {
                    useAllGas();
                }
                result = fallbackExpectation;
            }
            // Record invocation as separate call so we don't rollback in case we are called with STATICCALL
            (, bytes memory r) = address(this).call{gas: 100000}(
                abi.encodeWithSignature(
                    "updateInvocationCount(bytes4,bytes)",
                    methodId,
                    msg.data
                )
            );
            assert(r.length == 0);
            assembly {
                return(add(0x20, result), mload(result))
            }
        }
    }
    pragma solidity ^0.6.0;
    contract MockSelfDestruct {
        constructor() public payable {}
        fallback() external payable {
            selfdestruct(msg.sender);
        }
        function kill(address payable target) external payable {
            selfdestruct(target);
        }
    }
    

    File 2 of 2: Spender
    {"Constants.84ef19f8.sol":{"content":"// SPDX-License-Identifier: MIT\r\n\r\npragma solidity ^0.6.0;\r\n\r\nlibrary Constants {\r\n    address internal constant ETH = 0x0000000000000000000000000000000000000000;\r\n}\r\n"},"Spender.3372a096.sol":{"content":"// SPDX-License-Identifier: MIT\r\n\r\npragma solidity ^0.6.0;\r\n\r\nimport \"./Constants.84ef19f8.sol\";\r\n\r\ncontract Spender {\r\n    address public immutable metaswap;\r\n\r\n    constructor() public {\r\n        metaswap = msg.sender;\r\n    }\r\n\r\n    /// @dev Receives ether from swaps\r\n    fallback() external payable {}\r\n\r\n    function swap(address adapter, bytes calldata data) external payable {\r\n        require(msg.sender == metaswap, \"FORBIDDEN\");\r\n        require(adapter != address(0), \"ADAPTER_NOT_PROVIDED\");\r\n        _delegate(adapter, data, \"ADAPTER_DELEGATECALL_FAILED\");\r\n    }\r\n\r\n    /**\r\n     * @dev Performs a delegatecall and bubbles up the errors, adapted from\r\n     * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol\r\n     * @param target Address of the contract to delegatecall\r\n     * @param data Data passed in the delegatecall\r\n     * @param errorMessage Fallback revert reason\r\n     */\r\n    function _delegate(\r\n        address target,\r\n        bytes memory data,\r\n        string memory errorMessage\r\n    ) private returns (bytes memory) {\r\n        // solhint-disable-next-line avoid-low-level-calls\r\n        (bool success, bytes memory returndata) = target.delegatecall(data);\r\n        if (success) {\r\n            return returndata;\r\n        } else {\r\n            // Look for revert reason and bubble it up if present\r\n            if (returndata.length \u003e 0) {\r\n                // The easiest way to bubble the revert reason is using memory via assembly\r\n\r\n                // solhint-disable-next-line no-inline-assembly\r\n                assembly {\r\n                    let returndata_size := mload(returndata)\r\n                    revert(add(32, returndata), returndata_size)\r\n                }\r\n            } else {\r\n                revert(errorMessage);\r\n            }\r\n        }\r\n    }\r\n}\r\n"}}