ETH Price: $2,406.58 (-0.57%)

Transaction Decoder

Block:
13595007 at Nov-11-2021 12:53:40 PM +UTC
Transaction Fee:
0.56056247 ETH $1,349.04
Gas Used:
4,312,019 Gas / 130 Gwei

Emitted Events:

129 Bridge.RoleGranted( role=0000000000000000000000000000000000000000000000000000000000000000, account=[Sender] 0x83f53c078bf81f6d8b79e01e2ed36c473a960c5e, sender=[Sender] 0x83f53c078bf81f6d8b79e01e2ed36c473a960c5e )

Account State Difference:

  Address   Before After State Difference Code
0x83f53C07...73A960c5E
(Units Network: Deployer)
0.966727189093067559 Eth
Nonce: 2
0.406164719093067559 Eth
Nonce: 3
0.56056247
0xBBbD1BbB...4071dE884
(Allbridge: Bridge)
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 3847205748455038751114063348107261719447138279742305820110108786742373896637809823495715799493217821113594163492676027461755685139416248666386391848982879289418708798351454896275542089794587334857011279177164646778346717367193011090025051385946360896560951027746674359301903827659732057136652722468900888954997839118015201446865125647519580066953163813820017830194713483924868993225223421508756518370881149324923502872975213165782985052140006706677023561840404276654443098580487967455898864130595360148649511561990159845383409496967953440296034645204716632163810716467199519707070733380256749270502150943078037320451957671600734874841802092927957753042203669171369569845861981087733374079088430582647999635786425185123008037268344241436568502037612398970738541522052857871329680855888373820489480802473976271681424776868679199102334726200786200543658187832931474680389519845344604269078421529056127113770529693130174921294879134255512826105867274176526793487733632779084284339940919207306763242402185623210273158573983759841135802043496448290577312579402215960639909196619863674288998599275360074186867300585133543221120785526265924680724732252111223627084242996180655020110099721981143238033765050922642757386193695202770865765216590901845947706955334530036182809319500778666719147747208364676811299187248300132773003841215203091508582294761224381252232479428061356592346056156895484189972256055239217855515662589728632358322750342498531546367432779144120560267433767947536672441844166888914711604720444701713234428367984588404637962274037302599980266334575371562500632536519805390622212129847977451492405670986244684155269935258692471260618163392549201231625370253765634698737579455765337990918762086253243267159839014274785909665451796186431957474484451281954402493280327201992115188957810873163866559348056662457213377336981368715538610398120064970264686731416645115735495068086177945422173469430501564266117064086406746828302088148122274648629654322448236822834886932493729388103953362490722166859018200029147661568851269833712340018510395154860283883961360246662239887187665922233798115604701224360704915114143234555348667604453425872477505398073094961200185273662117900418605754035474432670497307752919822134874756670584839578588415215093954897331929350369357718725164505856236195160478653322396137141740276926978347728312780744697875723026922523409098590419033755955616052884915518530834211776735528303216823213736474301317152612160638229963603439455689504082892203292993727921836527885086187724935773713599169620772081958384060079985156296254013609836102030968585940888297831662592605240231360282734995720513422148051992536712333180499606993529430474737019814257543123088497625024378652606885642420003075424617894528738961683284941627831100643865215250257831919079594606183457666255193470582577046106452235011577883977567938481698748661380028578966525620264955186477494048436925587495297203835099123298744378436488339581760879667391956807045743518275020464154956663823229058294211637503001321399187446906437072547837561033616114715615833209770580940778594417768520057929141959277935199701928202768910397531734578128798887480004066273157553426497642102115534669924455276743031840833896344578421277529595164958963999197919685584738832367959614749843054737915741035321530992646883160485510425701585255573113204018373860769278709800498151649237404155221957583341988348370113985317418570724638313218554800373188458196832995088144206450078354288489814135986409484080573308928890830562239911161610376670242090264455427843028112304799199584599400479862967144434651820949598481244804688209964998078225535061115851650616181226818097164322064158616892945404692066827664009898870345193615166824555359629266346847691088168334338838943452702236870371310910608918200550559800372846501459017287611392343549435010766477727256338951881627114045477949104524319399771117629486609895021706833786160204057904794167921794449090105643607787493785795950065053452051333276839693961497555234495938219859531328737936632131935199352474043235580251550184309234226216205662891679797372858615303330269857798380655519033311923317478897587056013038593723377180324931063433700904252842867963609886780031227398551884332525906417644995531837887610316478974300348755077317530489302978213898836806891953689253173375967640873234984282612982756088573629757488562150421963526403693215934711010160732902449734010528548400726242188092472056920495324414596212541639625598330224865993105605088410868053687769237943219247565372245460106421833536871114679978483293382707291540202139492713211423106100037396938822227367109167535214804590068517036708385237615929891151954756126956489569517047145104411264890366466111121601852919592351356864987796352453251742901534839138352468717460471476304292676021491036296567430926137140213036381254470835518366544322664415949379770061168106837734307021848024248172646445072613723567278552838164557501732716849103280692041534190842656590186190913111715064810782814083839080764382815219823012670609211871802419264575689951658000929349591738814506311454036657605759659953040604324732176536890277991473287514841307370887874580744033528863212238242505354399829981835169535480001304237578754357984306890766313370666110479737197308001577078905666916332206149837292424062279727012503093668329885529583700631509540428658389182308512510176828062802532593957562387757436744033287983534280326939116711493306917788263237228463026752437479179953317199174611588049021103633684403440895660124754907851648885121035415437053458483788263283837150927460158604253044810641976193872688617737797816848224970001895973895581520439608199784906335925799601755680205745006141767194155650796557502814656477791868366671950807495000291830830869155521927296136390132361106418396596303091340308048778769255161967471821796063368325156570673193216730737019024462751355200445960196517453416989312279971487437793816245030356820017708043783450702864097697434953897848328547634375808568865021550981428545757553141627035652190447487794141730579138081265539825646915569360727502355235193112564902520646823447071360912273755258312843313963086096669366551338913874268776442369929172161922240110422025293743142793505308829274608223328718813956662493218772679490571677501871181398732804868699531530255100596036347211684614756869180875121672392437749106330785053691341749539540588758132250908163611803897820241094256096380105976170591286904727829583338881378226199170405626116937125037663518775147417583461364518193262684250703604398462123582271403656029046649706445480865608069337507726970027817334266602464076411141495122080971923704171749430302888012061078939707783406954144134174102558095831762105680459912341283207253024905393018712487712610279981624577532814395630582561488872557502354701942473848507370934290381346027403712727291264799786797274334099314070151977313103478360809531517151526492240880970709826012849764365593993660098478816890152853025268409494386592073418052949210598885164951354704512292240916569641299626286264794723583104171560754130371293908305537318532000872648063665863816033323577850179514558112164705879897489224158482234683589486266509393018236813918683404627263028605421257196762044281331708160752927236974129533716631587636761898088414097311049599226524142682945033128504395070688213245001765907598059601980151008960140186927584562310348421867404112760480654845192261010635613584934106120222758533938920780984183755684469314848133591128925100228218032637774834801865784243877797305492549270044097763027929355872775434564922847220446910608244150121541332172502641681467347483973038431308277690014208405936133054683924090492411969584392322734171034178617795484665754781112552955552203633335381970459954035218848935998261858058548513195200371241648049545533842376450201595794681372888823886870166102506564842638918294003150989022983857863291397186691210749062254350637177256510056164590464743187399206930234599939779704017652120067524141638960229955580803831018502490246306790006600054670540159363511267365253050669565050100294681542321347527888640779251153484228130313584556362428574953632688456370168570586645356011007066558804798719393538595683350262125302699425008444214560077016115145369432891768546966966798602651437243170186841035766178079203584798038561491787507326662204023696629588890129029517404561878309955993361606883279591248051245463784325414456820556842320210180218079564569806992702591809725440935878586547265161766228304052922395327110634927347700093417395588722922362776331738525975239409475630746445251529744043280079528563286001729587635606311470179509301544287590132247412749545503292256497485957481912760015834663427937319163153061717053785656464935688353902533796776010875280286919545580780510440251103283290118512876882688419198360380207798899835214406980557524248165018070057603851496642674765572935340028797554352600524240500194607491664251761666780594715301759210596221897865579639109379069092773127153478735852408697236416870500828994526562974571223138738247103369435802572523228943344456853233117361361606709127090371719316065818847326193479662705993414746665641745943383257930675881071428351612521112225754401379934772271256089495987658927668977644370030584654755106674714902794400247746848611318558960700075042970941482768279878111191513950665501320448749895943445937270192928729585924960041347564278640715665110482037206155819554101821831684896864606013378618633788102152244534449102448729236602164216616533152383710445839956740307086495376161307257330491887747191007389946806204537814977405173357408456051573924888152901683711939991663050028546437032354232286547965137329661241119130260464914155864797150606930613467755058025709103051921668812130587451753258633840155100295840146009398714431540082842548118469235372484591063732909350204602715994395475860768805911975722453005194356582011431782653347112840897421488635515855364156251453404652585152550635068431964995606164536891528583021976732535644014118646745694569186585705322791258450840687717871677067693960829842175119466220196605464808873059638218389731732605942626968961615754870492543739493336182557230515050382354930506637935087699203026810034789811876841637605089580648992755834562639716273636050950683689984235160227590443683320744063104284720333917382939068233380018012245323656422920579851927553115841234789572838419736005923978961993522855583084508953511969789776184805201876984173131696666584943537715617812410367195043133226428544780628964808638491344207100528361660917842027500479913571984594673197860555284941650488277248569070041210779179413731520245399534400500409431917542179846925022972137357784660632416616296180803987147604596736185397711074003904325748479488507466323007123117407674361255217820050987345621616956176675793800082295879627831694621553466986297079529685059560436304298042022615178524939300549283731083152187718135545357324208521759407265343817179617125182584518889042103009395711140152255676070197882402896346678303451453074767574031193093349028810484448547511006740506732758707558886388444426125876237285774078932325037755623928583193006320123711167853702626152541893717209821243232664021430391615745327048407430506375386673517764671327585971418201662945136868353443653576876308913396589025241125387771304809463832667740496133364684040435515723308284168618471933970458310340311288602794452446201624148620003139148919032085457518564654267656970831344581748453098521994658918307788033548383981064902455608346449420781626328975396619373897849867090289648430896393575313672625454230880954846082941303903514505203288154864315085553257948321700695742499929963852136773339267576598435587547920409777362335721957244279397460402243133048014891418479638126275953057950054001018109492526311465612039714127761774254261740097159762025797796690999000432331950613999430756275763232405641942515391276671107543082719603521959824302995412345589131147146742843552309903850947602669322614798106903076382803441623374459543372368064992869390206160538720188916604576135762236001871553082734004131343676776046199800703318131615746348334572095382713275589120302515632525957592067807903256710237094596233124728447506367784988582812137743703426086116722135289246546375952520817846260950560866270882946643268410528321232073582717662120348630232304026004099878411583238892226161443058647845042222405712507013957970494706472224537782825226066553763005630096848042581850892535252036891094492115537161741576743480601676421486429021436229903032946054472293383571481143834733169074408741574879234861259155114434917203827669022206458215609337961147962567667166355302155982741045272133679793618243031657006992541719757517011026017864995749831304448400825872088200662870549767338022413102623189926314179653069614400889915675355028456078085442296671920110315867189266899294561129530197690631751653046912594882694444405885417551021801483673726840177045250921947592148996347085975804365697115565855058489934567742872689047804353860820205282512015891822778247678400505616268697596184138890159664402986021012544433537655428240662124934012122791222825690732927464111690927026791041317278577293986521957524056888647789821846679699023085049818539380806163580396756266334616674832658537872623385810659433713511336919966774077892261319908177012180325142231671743264840427288205932764068887977909050913145562503055578144508726559974531059786500913663251021637063530589718174742721186212086703030488742643003302036111661017915230255009862286147141485322641739561730311926704518385988135805983623465692191528348316304483253964701694439463509317795084898019302728048097983313021344165704426790775033785352457559907090638447153820499037897071823063950032393195866609971861265593788663789561520464263234236846740436621646315674255172700877632247984107354230680674597200799012661458015774507897794910180282110182989890971171006749784321617368094999714018347526505550736713218306554857237729389985304556711618958041074350591387576339013047505006346893986234219738911349515291859961690134426285194006917198848629000235501755449960569423660299269296336562712831491329891212372556779851168091049263561227363198681549042707424318309960618283270925651755436170936076024840808625546691335388662074755057176983342432559255574901370594404136001269933669608890495096176979018597439554899892497369874770582119277821437885944678226897774199176215095625638742513485179213548110850432114087166075795942341059904340692308927481662725567138744836382142137334521888228674662776075907049840157530130473826569069213875432043404710296532311962058474595280039130368329262310093944112101316128756830754498848628923211652377406235678185640933463208827551958476654544048462743106168931272345674583039355704733908776970660074382964329656751519794087647327565188362131513693037986553507162521928566826541987027088189516145111826983144452523256452875084529619861144538126317707024571840401172705140276259825113330389206948788172078244090175845921989919590109705304594538883068203383552515673868952534392026982590609751354748111241984872060194496008526401619033139328586862546990716041204326018398267360118762882949482047721147417387002458401629593326052244412413286388606577162952463312435028444029125583737422414864285644555086987375746383696743368690776563360933746456145049775680221893545325866243258565412480925212038411656615106378002120166661506869639288552846216445901404988559810029579779869534762202411724597191818393119081518591682184619656916529192594623089277072687869164520185352650704520433065686494443114321660067467732132905513454869132518532729976627676368760661048950299674933260670675905222524309559255186164910119369224020221674549533801535418750059497799362634505117942050956119486876090752004055630262359619548738829098253963081082184934303317100974914789147916282873838932057161098382695826061994843392942357689836619159423833912174913061791761989503250977138744245028149017308907880727111407926084447136897862892004933109985609896263411834882171634162904083065815068195901792571746842283596461298162463878656454985800837888256704925703031056813044524427823915382731836882409531799674559551332177696463875229655433058746362453934582026276410306864362250466370314924695876287549232183017548392751345316635111448462975062277339418461258141022282919445191142547703447384200295482957590231518501866774916493384648830784558801958363164731338044657456585248382486914484155111232058926140072330253038948847737243506973647519314930815173020936141993810462056833362332282521748348320690346142157449394346407186177753145487184197101668539773076793498311638675849076647265025616971520067704352298140205158121293800023443451716664267767858784701999449089552000913870409167673298724371604745310684143195980244894488681551295724404883039047729725978185784156815442905316315246194190357795403439311399575611765974829887750485985030323370904211781975008645307981515528816915045797840366200029990011566587258531428551769947760113479030473494062850273577127774816488234746071089181115829798699380589755290915824576052670879509168894154837110908804505701117391825586362678737964611877199369518603066709998614890308655499802158889872679030292961806128467712629056360264360042053011167151341392041466158735807826459423083407960407768802949547897274040885800991683184006735892753572925352685470222597376449132038678470495271074302886129731477856939319748814111774296245404976278682632791137796299329711831970826836714192247594177246724879760510703462583591011182456527828626962355087176802819992148039556429783843900148601462321101724278290031202041717295353779955976780445098131890669916314240774367270635537847245081969905866051644822719459197386682129319423987644400880701358880121628800856657147205798033403482478302115128004519590611754760456717437659137367690051986079450173932999666272973925357609409928759259456355834783006775785293142948216567688066256640964293777544187447028551828527358369592576245081604292759260357794991081800216694473172885779615464915688635716133336650690281244186048869466432624032465954955911807839246168579180499408908539013714083353206857275454339435305497735724365712413130500689047060337687602087055740966054879829911431153620636531648580130478658633631874379109840213693462655204610444862982045859893785785897409936401994896454473955857205279124121504069813174969504602088348818425373512138704542219183511926593749694729059591097007535824998750785208229069954104360068321494104627459341294845176101734984577737818541372930471732816687602954441169098219166505051704995229094999491365779947965033212237442375495387548260436159403860046033871444597550354493920381944275920673755983294443140674050917981109031095772822520456396098105607181893759610354713767119235075926935422646708721492909096248646532410707014332618298193972090459024492609864488579059428041770148053123799058447795392478851931966851753889789793633753234772049089722148287967931716925568961064043318172906201732722497339291293261268341418055447668668276782254954217172994280920837002630038005061188158543778170416289718111705066927216746716282589432278001428314673227198518065288051857386657526973752767707902592409428550729729504735369090472940757859028358109732673286370400955071892982088358199237582399501221850509999388362269774677470541561885608051406145968339443714257866376183556310095686187918423971738199200450225034267426426326217152950905501872238216513247160790638298069505903822307689067518831872408395360193766688148912288114039872559684146083426865917820863692761364581064263895515287117095022345860035661630412016853645145382224084460515999586223405976324356842673624397402595438175078031593887068550131074826569918111479567801693997470964673577236767468723789871185430336432441946127431772664664646085863286819899983501351578504365299677786284294193262014817634846933328273157449932375521571926033972639394758469901443249155431895717709073979137929630237753328409356889423119632057947916261560902924296147418083647512873353016021238964657647186267576894464558833940688338694285708205632670520156685197786428103378558263267981339906797349181476770610192828642741135973702074513354324428649752260123449997737990873601428221009730305201921923170692645465820662221699355221350278016672061952082517694819756039255296875332768862674486191870457075331308878106377323655362597452884337823477660459173210933012244553683352705212506187377247866214644491701359700492567991361073392913551341909411944621968256294300903665947013435596298759030265977942162136770025441181515950063137095477205526009269177074080033598936165633199216374843703793489735207072079307231673130841112918812261473536136867220219485508468874464539421378062680792049606103478763567248550228308808817223372643810204653713960498405602884292788233160654598927398701989864054277768730638748775221924453454092525128361059473325831432732838029334061392395412722796166232593059634220324053370925071243124452850674302519321503928211075125175779137336282978134195688611759616691585799290159607204056976231187797258359597609047867767023069306173292334886563169110492070438399137778076276066923519005258713382550362669133057915842190621895160366299962525511003691575223670958862992881038201298994322617163296434060170120578140664677187070198604069992693252062900766560502419487286621923727486369096769880744312190761492733027428346776305386781975437883228538193515727258986754181992567685434545109149082931421501327564339127460807109544516011514846973508353945776780200362290039732629288108024168648029533471182318431628405999607161057141912512597292693022032072039069599266683239464374849165755076922616026840567663215797894116346542465877072504552364340836965162820562960076502789070512663050711917052131782373403126975173110058778519921745143540912794594667617269151460413118974494226410965496254986833149188450981906481229939447198653228838715731235923598991481875335142822028601656593262605898472950530127715132190579247167601836249019967590994418284161887890272823183270858645735960503484995902658908563411100512434259017967484446594589594360356076730878324990874006423278237134581056697203351049694856531333620537372599142447604840110051235370733203252278417507329362850071796561851856914378192977679978209409937535069396107969830329459414856668867226620525450273208975357025483371743483978840727313059035888497928670685239430415420241764046654572437985211365966485053046136362792713938073351167595626364011190412458256616694484795355748235501766001510731050692222074523397119891553818902709261646833789865413260466299128267979583996852356731742742163407904914428527150039157397226630739439747968071027727421206769734151518028022513803342131858388311296061473809155174584286503728081784068814195807588596880045441228005138731032267461406740489944477628138876119163960408486679007478858063581171040531709960356602374304353156483201052871891372697551374494176727895090780164831906596631652755550095229570119620617570594683811757540434125210312560719843459966791733697189095554088769906112537227356181680441875092360990256158019938058011145618717678802493159601063002484766921282901233958811362416169285200371466708512903033061106728337404612886633089367794592062223424071047198624845730346258342051166058672757058590220920694848849851610899295250556333144226839339985733044027580366319585798234219755581194225060118479410856816257008301394853151118200628358328199143347635686658773385169289384187394318775105018432626113078529908911214223946507005578581759888070581769578753460892358869600829946147612497909811232120859058717278072441047196616282405842822361591763971355899977727877379496413046954730893210618661917603336011617004480462938623978253339328146926611872929145794045409434510481439308404580015326710950061848945156133526467932390234565163150767245556302886711218095623744335164849616942707426011293756822536025185890013460441322406103928270151479922769989368390792651729409806757370397622957848912558220596615653009294300397874794933973996125766343926819978734938889080506654355482339598442512836849208960384522393963552646484089847688739819821984873039939545701029368853182170449984274082295496030502513670756708157476149883358202490880933055104794250820122786613262207531688869908535012487020259843095961809614419732138944365349989281325309892667002191725229451850127806474394609352648711737103684529574023975954751574973604073972177312385291776533134996775045330209766017897790698090265884565882647104889748618166704421584745214059573762268206492192002218566826229629878228022259587806653395596115062047260111949062634380618545894772199098702219455151523261114474791858963401087589123403261122951274582944612242663181949527278116983402859315729909990698051918472216625390865215304752922473531879020211782412737961470300727181478106646914000050542088755719756066224755423526354577067991813401007671654258649089841018480575483183184490582729113824062800245744743850188955406372950864729591676389345528377983200755803344285863004997990332818077275942763784567510023311261373434601605233442584304227885231485878337012537247067605859505187605172027173747155859454376252219311664615038049294299134300555860661891366177066542756245454755825761587034370359513888098745559465523790247147695987761153692728284733961864468582795271571016198170150986190012135393687029053089748324009288214796799418801707334360368545542506543155746709811508149432403640708354282217621156658006892511643380484578064715680148948663548449109471719726250332164960474305431427425024547125356113520438744497827423489616333267041911239799070066999939027063401857272999086601538633633169499677147827026523288217583615890621621243297848464472687554167262442595352236979669780673381781353886437523879221917693149359628471461053809924437989227133407512905265767052635555388715876779341652938686598004703432593190633779502867941217229664750791547993965271421620949693788990586432166724926568167544970159677542759072204618236642439945906424963872294164433626136953832858955174026182006137417293434650321081910207795695330589684319971940971001811771125463843672346213575258651128225687004102049668042131452677694117508110437849012149009016553153204488546305948442411970813014876234214545989840049687440321679794491102918086992962752366073578045976282739139311267302785239353314795371816508860361107935304702406337267088689032430099588945622474894380536475743971123851632030738641933233353070665406679857349332757327093083223832527264263841212226696228983403803968470300961465289120344548295718760999077567771448930502418964722358243720247685368926253757058494766960124730110007532574031324307106667008703354048106483799921842122967024428736740709719256713301166046268512487774039516083098744544771081505469528894841359068505566594481852292773805611692880866812818115483767769899093936185757119567543384660050933271357799311817544534280588783921325556428867017355887524232974527846402880335534030230646726685822511608505007930999966522002242765348283856840044971745234641172950195928370248976806431539718816050072134477940708160781415373384245688774912811350229493818710867325083257645263827519473029484307766975826551080884562144441436410940162486956666627837250570323235000210229636065403376404657465068557853879382386451764732124905401839553002440542623702395865904586159618009449945205242120638161413046884056574009674982098820293848978147948761050590689115315202602110247069959997149234599570964191527532669002668521029012235993899176964446298789302213882966163363456732278906445823822397632174170904700134590284157603423270969611091006630899518759315772286254317602024260339601953852904524250359739106229533943200320468050067439008454563779322307192679120819866219148749046489435207841407170213760223154596259278035619235506587273499910331068371747123503116356321758429193398355468649423286835705928707377744428125769166509057637117476862551609739735064379016714932462473823469457661484886145104688991130903697735373444029402307988775790871831399457947567730329574640413318517641079869590278682199319404879362900860524555730022525445659815856204960187851429737777634512849410232350662635497251355581619197742411978881319782577179039484030730224523365799765082392448606684815759643313447583351753475696821918888124823029065051209758958013952161133803227200511374994709792922663724515881259705614065035535035856567100313944231751665134169529499740347052586512743021914748022686559047852990752290562985816600210662852241928107295469497568842230138468419897236656344480543782058709419879301770377047992825437233209044317721353965480513740494935527630973486934872354604349332877423390502148782625016325605087182435447585719558693891796408410507567470904450231059141289155978517351386124446553756019656187866167069407597312838517209246733578183555646654697828043693024544991182222118453849804103294572368327739422694105621200244200866499704209483364797802465069366930692015577780043312196390974654871210199242572903644093046309585969612690189950748164798991417519459127906888889988957235070082751257005690737024092769181057823935804279925516445209553041477100980052656278282598193584681869972053799312315706342925162177314596773148168387563868567568130489267605963039799704163037941710779408934878314911969322662800289209305901742087888720070276600032423327791646038610671867759424805859060815484361130226743162095967135176396164150634911652542249791336847065584771097482918616147210831997185450691093231483435495490992064296211048616318578748705510668057906027566347616742398766903682464598268876565908564991036472044098774975360798647979052895062410662131376852763489658617319518500554650799215584522075218763290448558879161506554499012466098031638274011587431795940550276739518186334151221979720062536854456580811148733245011493302673522456348539955803351554049451980830549208941064865727824840695484900780310565255307049542498006870083999747829167035683655148064221695421797125406828060994289181504837236048081857714227214504864069654783969897208238389224093993885277130530584224830790333654220425143537038746992282518504869278939527714861203451249939182946129940852228464660670823342191175223490019194303736068691007642602887413879777537767764873866055295886104330347928973097154477672586588942500750630371933916908918248285871356434444185364734603666348596771162944684698327284524812147656373013944547701916359812779783167232888285602406603402275241666141175960947198752935129553309226335976202902919514384980145904789625611657255351062235548022728709257076280716529086312949867955288751255725436762227946619255617317578567469864708230721505162300154543493104881239648377663335039016074386515881257682328675799312826383868129625411908109170848399650013803308174279558154977196261965460465641254846425324111639416611674138990560679803429764955741948652998011764155218119459277289681424862093988852867454988232436884521276040037664143741527524768266258642865339914043815673281350331267005402732596809346923816091282192115844213271128905211389903972050014293415730629369170292547024934771553584285813516424057096616664454557887031068550015356859057688282582507822937482370352607089218264364621091347346530779205212429431044680821569129895802380046662264771638399925810083873611937361121945300300265027750440550136406101203029425235110019088797519272401233599824881272351178443445110087597985653813524029057330753836626262206636926393835667683248680970067601688617149930062922510741178749971594682822742378928628337248448880718355906663253920870985885957710472747986590976418061731653542473299702454692014536093930939129783418513467629413461265951130700279437184490265870368192232699056482437563741552687952185897754717715736375324711000042727996925792387181222048661748793838190972770165575710560562061523771978121121688769854443768692570769395044356582531539625096873431448383734521340956804266321623140072424990666709561108992079132306475600972818249977380751353486304674464661867944712597186166388601437279392462124217946291700345646494972313029236471058174992980298571537580709280124647187836483121515780307639515183689366628339887135589207051657108459812811048965755512012287963375400279561562404823157515481001155100974006937766635996822922731998638937361574431735633610039575482608521559415482974196415927363106827323839110889180753954280080151397270765448379884500692879777719803524658045596864454724772629758240197967404993197623488245072521064852753478943916577271506907073282866078448815556498995296810340531856489364075694005253875565402232153714939184654261924200850610124037878794317680917099701723624918650342583413656913419529157231194249628177045422086915115973932084613215976870497348275343462361602083863643210384827677466647393088933757005030950128463349345382531641124899313750603164125034831380411606059875228867283644206954941095027916488705864035120967911025911229376486046333161524907002114707737345124953186287118978304304977315795078618144872138263100272298202985865189233508554747860646153708738884567857537153678641971487603298355964798361484325264188990038264273021401306612406180511784358605714538554729466379004717542278739886416266903899475948006061868059860479921454882843708247941079879375581401129610515906724715029748710612609891590173567383573866578237214111908377531817900800847501073883029452149834159918742309816456587246700546657816592048714149340944391563248700016798109190618970483089735023223306081131502444957418468032289784426756493086810225849449245946122552711226838178878305350191558348989211313921530880099880097934359687966721238957371833677742208495086825971955250659181964562583941918225417470868165911661455317490196201718414301696579085594066227758009687599299575517136278461365990188387245687824235928251088361072232712231148753362997804117805802542483399591721505362802854503813193655661982296137245774613386845043451353832618487317756458145647013935761357126503135542823750153038570060358584849392544263421641323031419271933593461733094351175977058824157379523951871806006644270930726390417647332092707690888385255307013536179700259754727756285105560201963684594709007779903953954439470129051996903043290795389845388683203988234842608875909953058166268657626429058664824483761067490798654254970013612812026523917359816772990249668008019871198257512631661428089349451568779379536250017195513543177494923754942911824570471242698952131434442056580487017976933452297403753457832036682594070175741632543053635225065967196262671533350298717234711372860330461457606857155995755999123340587785346636354606958166461216615284907087816566112600416856566664344842582369349800983030940612978732410667354824163438782539780047347357437418513252189242052710533745898456539456986878946451035434290698972963835347575745620086396730377378848624901800091632849425076692901800170192148243163077488899700295478869806389681329388125774134119302545652256711457481705903572361549632822188618063550698520047398239216065548635621602732141240045182439243040376191238106047327649128643405968178864839321436009785218554724944042442012170504697295952129245173673789689686842391142214626409238694140345486222677098599613988522843585219940428233406638239220333564513291140285861773244763887799774705694056748025309471833912830306968885294807721513538001268239355172004004608284152952360955666965912866202607368630479029066829753069781518359120212431267819133932834122567161433484372705077607664639896088179656998305092099057214603496430128225475554864971353507226091276657311675356790163329642668321944554904999228873462739476558583401777939450728572225949738668558004424408820578830046558615656130627753664609595744781660422783290865337448310565674485212183748849854049401857528198010168908147738142895694219155404205589523240370215191825172105532648666015466831910950049798447065988225966694736261091544513164889504926977656966943332066769017297154281380202389505582287740147053145638725663424438478652398835854604915637329261531214242305056197730339882113467618928186074111318675250947491933303540845605059908484441089201158148640047486532681880016370079201146506080182420369942131642033140145219510415120080711540720405328628640421538024717065899954019810977133847663854708053357387470768369815844536982512415101143571284201092850159731774283308393166003526785040161274988586116382910827093939676184610069388561323362393575171296267274920574020970960119549692173135536896241471536362232554283274091834748049882203454128717193290932020296851336240079034818783772745495670230370441171717626094288976965703430377913771477101613142982190051134630672249119664710326973930136452929571417984790196756425174955579496102088434930954760460401906193578904260646110098069317074522971469027465526746000846834489321852355653662871539303568582693625710936707624956776266924334498928320228763089018062761253385754501026368069252048290951947634556857129970326375048648258470239880578713708306317263732867223121119821183153234244513706951127841026109040745071584297995517976741873174833960093073201064092767179752261731999624625528902880330806040674415519130599747525054009462042536961373601492578666678287479025254700865934611919824893142797742545043932655076512026350760943535934205336166632658361790852742314566657976566459852629780865862943181697802538920462050852963121693122680054332857905901543808012263314082799291117715733352646090557553517671401333709992177734750774300748971460749903555668798229740037714220645716704016636214075811464896818985734964707431789617341581251339302064038099786806038595523661958249451649845334714037474699921426653389030212713691838271910779809392394249290259410510208114641545836465235580904795397719139516986190074018830522249833365268760972820650732557950398774211443063100123607238186484681847901188295312204532189633347710664893307120941289982880191038806225037085684555894003805919952349291220084860130188022343784350896399344438659242042461531314453391238190194578845851965233884838053499946261809701058116817422334884038844379901698252229137196829857956547643733301698728443664574307567889235793448328888031633044486687830101633656523392525424313352096482246021112853852273718114008794022342996316056264139358774788188678569351364024234537608561680709885476503197584658723293954195734290263415601459467376437308818346474343541592801747016007278855744517534427941819315149147235934507506131612889321214163191613315069148744752768708789923537840952571233444030027114655129010318031247812768091135522858324311774286315949892441329843782842758501304857648859584203908276451008172936676461192188637017085585969334830103805805947529470356922354743742117150848230847990294660702699895810663063869766133520187195648814692328547252680120527309614289170667245717907484717662702224095031573627003932192667443846902652793747183663386387518681432871430017521393802403938983356704015076473774744395618548398697186998155148705180237153963911813002425708016619160186405191724263134144339990622662182780528555460249408112896560535392232425736231806943732584681121003850726862173412298448717897343038180290077942524246894930496710066694396364815157166174175138421987872745788380139598703863000557625940624740736214469233394062916094040864371288179911756750444884990302183915366955266933928224988250573850791210859275761737357165702132174020129385909912180171221235142651094784767960743686156397643096518297745394932438416412718611583986115688890598265761517498789852852545760127739084265575554585281708313158107552886127433141910931964870350887913686360668468035857002282239217387077206292072237453073106164915986946202843679846967112160323755054506883290136893274064505597656053939336242479662103579444561925014191428541250396786815895438864106417487525117108441825095185347951890197743707736772948991496292927103665351120386568271574102116121095338952027517715915751878824583530582268507806075752979656304342340704900263359666385460921998565863639508133022864749187003585497951064004218750407752727496521374790913649980730501925628993502219992407629989700240056725400643437857498999670831471528558733481703543193831983711633750229320675713626459082389621729220967632099024878463903599734115650974453109660219247538497874819135258420622835605479958894544758410365210404058321778121132495813664047552445488214615372709687724992916472142449925816838998850537078506069183310823331556999250051077174264254996449577522117713744990883312100028551392491066203499291923249855429650839256745526100808256225197381967404838273373751262982977053690056587511258395675105906554214142394323622258217245153745987338657896905511517519270996351140357079761014214486165813341734316443020168519045013124145231709845705812998543534489377269359274051898376672421937877136209597725748509253624872826282832817222311492263089443688045231504039004841967449680148334170321270866123337689833820932247810371857169897348994880675441050825249666751454381035671406991840419440124606762027787387948196050816734294799515487083147531588336157807126079046917069566453879115095650064820126569697342275926403951641497045117470362491283245976456900902415453206347680709730589604606824026981534001457775158970047298747327793982237478312186063287377732114182415092046547559369992305426982522637255607925030409444032537223880404741538131259655320780521154540669290796324899947999011429951490999486279662381755886122828107016824752472894348340663919384090806828530294996844244771815984997795175716225356180978245874359967409427565323794424522415953518283652026917692502088987764051351199259028428533699738106673480406268056658408797259351197966245714223022705820770688059531554150827761848676470592363369316393255396004455356795545821180120331658180638453948606859879931828091030490481312931202570962035796152657955245651950708928361209720818428473738575252216951212039830868243655007717769308332021196770864452998900440021863694344556993685107339166268970512243597605977513256358339122495284113316050778607640698955231688274144460983100965766264364750489746830555192375946316766623658825140085839604680456662706535761002238306570079369485727294472787733268859885131809527622705335406474556716860737315736920974817825532046601583455446949077342766864757107648286005107978801769473169367078193515521683598319521833828942567608926716472434349191759125009754044751527170589155485468120393497418108390129268971302099945433200472047098735243692063218292785858600055783242386881801185712685606270657719508596932206332049457525899428214514395323072950543384870263841419669946861849215880385624593770742882732173526107818854635620990025403704243161353558746511401625862879239370291399894178726482278385369231470147681812317746741241583838667733448532392413783359509962882728126894971164034370812785752980912841816163396985535245036256565647000962324686575387295816129164491488810046909552786993268102687121552085611148799543154246286756053206386989142083674962220693869768505451737865239801324291469747765941859459157291739704419988177786979182294535691470920384955330801392349712355156606446286573147399091926996914586950325182079714044560155817023241679703123707680795505780813080385922680691591339583722177492452404748579495507142779745544792775052315988302489425864796658782353140183145800015214289060725606913738649802182525108791405550808089829240882085164868204207730183552442007007224130443161636211249908705697543770015315714124818695341966232396889493952311216806961386791724610792849817156045837030285871568327163782135068138808058709908529102079844455228986912825894818994292745281395269730354973888097089243870925567780688727282602728419374866986481987041175583415908506940344291663681252393605225365224342345851355601845839483912904154451564773834397200235572508352592583516628653683398889934791781045887626895347713334804229776444885823887979339589578105918875888223154551355554063260456577773491661956913960548259082196129412330192821617115715819900814233967305009442846665735685225140268322735417919960928675464133968796422577594810802005841175206125757696897175097349837298878362400574501127044341999888184650509571107543093458374557109272802811349214663960897603105628483809728425124547687246111205094988663348688880363974907790806980502035483205636847778391434275943351871051397231902971478629902231322012569659610093837730304092993839980589871029865549413871993601987232174615561826751358808499594912953780748747332261717964152757744142252987215667761806552640364912022324860479593222100598460322206877157858650467468248479591511462464603815262779703074521602703529429840320718352127154756403480364029895171414017329526023362263914636940609403405038316169715667226850296235024842964761517195100239518201550073383353232854106725141519005708300279795456902501647023371154756877492310871967098153560050529323065614755419672508738357814295995284259248302730035720754801697541022615676049709822427281447619500091035552873306212924243316565349656699981905693742660466289742251394335462708383409267341159884887315878813085605445566398043279928372560679255352456700573921712453720141468230453721392428430572561430997585017191423351575594665218718864630428430388094898260410088558855240549043953427940505865009830570526829318086222966760638607215085264970082578904389828972290354387700835393764948004402172043604237354751297414096769161204300575651032288672509654539464109194518540136600833242560459122583969843973883284756508711716775835102510723705552069088885694668772158296355798373368085534184030742455799581469332870124779028072334986015606647949107133872640377917426660667525769574827859372060314473087012309206081069536942455913069778269455604545588740958420195661153037348934849203823184475980025882186494857005573959526568026177976425419519308117712273266865155256849369594784743917488300080717784091122516624369136877786039427786985740328273545647079817249439002577296435989305461472326068078440821564401149385220499323371666437659376962354859428951079194586459520803600668976947049653520916227182880040522987186106570078532047087633004978595183159657013034103848814383587545791649502992444414451080314510604204631570051471145511030345617778160142212223563696727358478294379418887732329046519292022754708716551376527809080550408885544503380068485563260135668401429552072362918376472193557703288112881123831510708277547215014020580484825251485058951906306065613903110872697243340574226859727455034920819118100176440775146772262342593616435668497179719535637360943316491798196773498946007773606648143669239014906949279376500283579965952147845671121165675599461244578058870102025329374548009191820941059533222420616739052080473759057452291129658916639948033943796157739836560028800099406998314853386375727982882860841626374586826803
(Ethermine)
2,354.937697327513307673 Eth2,354.971560799180959561 Eth0.033863471667651888

Execution Trace

Bridge.60806040( )
/**
 *Submitted for verification at BscScan.com on 2022-10-20
*/

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

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

/**
 * @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 on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        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");

        (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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

/**
 * @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 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'
        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) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _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
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

/**
 * @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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

/**
 * @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 Contracts guidelines: functions revert
 * instead 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, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override 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 this function is
     * overridden;
     *
     * 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 virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual 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);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - amount);
        }

        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] + 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) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This 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);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(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:
     *
     * - `account` 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 += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(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);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(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 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 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 {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

/**
 * @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.
 */
abstract 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() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual 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 {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    function _grantRole(bytes32 role, address account) private {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

contract WrappedToken is Context, Ownable, ERC20 {
    uint8 private _decimals;
    bytes4 public source;
    bytes32 public sourceAddress;

    constructor(
        bytes4 source_,
        bytes32 sourceAddress_,
        uint8 decimals_,
        string memory name,
        string memory symbol
    ) ERC20(name, symbol) {
        source = source_;
        sourceAddress = sourceAddress_;
        _decimals = decimals_;
    }

    function decimals() public view virtual override returns (uint8) {
        return _decimals;
    }

    function mint(address to, uint256 amount) public virtual onlyOwner {
        _mint(to, amount);
    }

    function burn(address from, uint256 amount) public virtual onlyOwner {
        _burn(from, amount);
    }
}

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}
// This contract handles swapping to and from xABR, Allbridge's staking token.
contract Staking is ERC20("xABR", "xABR"){
    IERC20 public ABR;

    // Define the ABR token contract
    constructor(IERC20 _ABR) {
        ABR = _ABR;
    }

    // Locks ABR and mints xABR
    function deposit(uint256 _amount) public {
        // Gets the amount of ABR locked in the contract
        uint256 totalABR = ABR.balanceOf(address(this));
        // Gets the amount of xABR in existence
        uint256 totalShares = totalSupply();
        // If no xABR exists, mint it 1:1 to the amount put in
        if (totalShares == 0 || totalABR == 0) {
            _mint(msg.sender, _amount);
        }
        // Calculate and mint the amount of xABR the ABR is worth. The ratio will change overtime, 
        // as xABR is burned/minted and ABR deposited + gained from fees / withdrawn.
        else {
            uint256 what = _amount * totalShares / totalABR;
            _mint(msg.sender, what);
        }
        // Lock the ABR in the contract
        ABR.transferFrom(msg.sender, address(this), _amount);
    }

    // Unlocks the staked + gained ABR and burns xABR
    function withdraw(uint256 _share) public {
        // Gets the amount of xABR in existence
        uint256 totalShares = totalSupply();
        // Calculates the amount of ABR the xABR is worth
        uint256 what = _share * ABR.balanceOf(address(this)) / totalShares;
        _burn(msg.sender, _share);
        ABR.transfer(msg.sender, what);
    }
}

contract FeeOracle is Ownable {
    using Math for uint256;

    // tokenAddress => mintFee
    mapping(address => uint256) public minFee;

    // poolId => multiplier
    uint256 public feeMultiplier;
    uint256 public baseFeeRateBP;

    uint256 public constant BP = 10000;

    IERC20 public xABR;

    constructor(IERC20 xABR_, uint256 baseFeeRateBP_, uint256 feeMultiplier_) {
        xABR = xABR_;
        baseFeeRateBP = baseFeeRateBP_;
        feeMultiplier = feeMultiplier_;
    }

    function setFeeMultiplier(uint256 multiplier) public onlyOwner {
        feeMultiplier = multiplier;
    }

    function setMinFee(address token, uint256 _minFee) public onlyOwner {
        minFee[token] = _minFee;
    }

    function setBaseFeeRate(uint256 baseFeeRateBP_) public onlyOwner {
        baseFeeRateBP = baseFeeRateBP_;
    }

    // Fourth argument is destination
    function fee(address token, address sender, uint256 amount, bytes4) public view returns (uint256) {
        uint256 _minFee = minFee[token];
        if (xABR.totalSupply() == 0 || baseFeeRateBP == 0 || amount == 0) {
            return _minFee;
        }
        uint256 userShareBP = xABR.balanceOf(sender) * feeMultiplier * BP / xABR.totalSupply();

        uint256 result = (amount * BP) / (userShareBP + (BP * BP / baseFeeRateBP));
        if (_minFee > 0 && result < _minFee) {
            return _minFee;
        } else {
            return result;
        }
    }

}

interface IValidator {
    function createLock(
        uint128 lockId,
        address sender,
        bytes32 recipient,
        uint256 amount,
        bytes4 destination,
        bytes4 tokenSource,
        bytes32 tokenSourceAddress
    ) external;

    function createUnlock(
        uint128 lockId,
        address recipient,
        uint256 amount,
        bytes4 lockSource,
        bytes4 tokenSource,
        bytes32 tokenSourceAddress,
        bytes calldata signature
    ) external;
}

interface IWrappedTokenV0 {
    function changeAuthority(address newAuthority) external;
    function mint(address account, uint256 amount) external;
    function burn(address account, uint256 amount) external;
}

contract Bridge is AccessControl {
    using SafeERC20 for IERC20;

    bytes32 public constant TOKEN_MANAGER = keccak256("TOKEN_MANAGER");
    bytes32 public constant BRIDGE_MANAGER = keccak256("BRIDGE_MANAGER");
    bytes32 public constant STOP_MANAGER = keccak256("STOP_MANAGER");

    bool active;

    enum TokenType {
        Base,
        Native,
        WrappedV0,
        Wrapped
    }

    enum TokenStatus {
        Disabled,
        Enabled
    }

    uint256 private constant SYSTEM_PRECISION = 9;

    event Sent(
        bytes4 tokenSource,
        bytes32 tokenSourceAddress,
        address sender,
        bytes32 indexed recipient,
        uint256 amount,
        uint128 indexed lockId,
        bytes4 destination
    );
    event Received(address indexed recipient, address token, uint256 amount, uint128 indexed lockId, bytes4 source);

    // Validator contract address
    address public validator;

    // Address to collect fee
    address public feeCollector;

    // Fee manager address
    address public feeOracle;

    // Fee manager address
    address public unlockSigner;

    // Structure for token info
    struct TokenInfo {
        bytes4 tokenSource;
        bytes32 tokenSourceAddress;
        uint8 precision;
        TokenType tokenType;
        TokenStatus tokenStatus;
    }

    // Map to get token info by its address
    mapping(address => TokenInfo) public tokenInfos;

    // Structure for getting tokenAddress by tokenSource and tokenSourceAddress
    // tokenSource => tokenSourceAddress => nativeAddress
    mapping(bytes4 => mapping(bytes32 => address)) public tokenSourceMap;

    modifier isActive() {
        require(active, "Bridge: is not active");
        _;
    }

    constructor(
        address feeCollector_,
        address admin_,
        address validator_,
        address feeOracle_,
        address unlockSigner_
    ) {
        feeCollector = feeCollector_;
        validator = validator_;
        feeOracle = feeOracle_;
        _setupRole(DEFAULT_ADMIN_ROLE, admin_);
        unlockSigner = unlockSigner_;
        active = false;
    }

    // Method to lock tokens
    function lock(
        uint128 lockId,
        address tokenAddress,
        bytes32 recipient,
        bytes4 destination,
        uint256 amount
    ) external isActive {
        (uint256 amountToLock, uint256 fee, TokenInfo memory tokenInfo) = _createLock(
            lockId,
            tokenAddress,
            amount,
            recipient,
            destination
        );

        require(tokenInfo.tokenStatus == TokenStatus.Enabled, "Bridge: disabled token");

        if (tokenInfo.tokenType == TokenType.Native) {
            // If token is native - transfer tokens from user to contract
            IERC20(tokenAddress).safeTransferFrom(
                msg.sender,
                address(this),
                amountToLock
            );
        } else if (tokenInfo.tokenType == TokenType.Wrapped) {
            // If wrapped then butn the token
            WrappedToken(tokenAddress).burn(msg.sender, amountToLock);
        } else if (tokenInfo.tokenType == TokenType.WrappedV0) {
            // Legacy wrapped tokens burn
            IWrappedTokenV0(tokenAddress).burn(msg.sender, amountToLock);
        } else {
            revert("Bridge: invalid token type");
        }

        if (fee > 0) {
            // If there is fee - transfer it to fee collector address
            IERC20(tokenAddress).safeTransferFrom(
                msg.sender,
                feeCollector,
                fee
            );
        }
    }

    function lockBase(
        uint128 lockId, 
        address wrappedBaseTokenAddress, 
        bytes32 recipient, 
        bytes4 destination) external payable isActive {
        (, uint256 fee, TokenInfo memory tokenInfo) = _createLock(
            lockId,
            wrappedBaseTokenAddress,
            msg.value,
            recipient,
            destination
        );

        require(tokenInfo.tokenStatus == TokenStatus.Enabled, "Bridge: disabled token");
        require(tokenInfo.tokenType == TokenType.Base, "Bridge: invalid token type");

        if (fee > 0) {
            // If there is fee - transfer ETH to fee collector address
            payable(feeCollector).transfer(fee);
        }
    }

    // Method unlock funds. Amount has to be in system precision
    function unlock(
        uint128 lockId,
        address recipient, uint256 amount,
        bytes4 lockSource, bytes4 tokenSource,
        bytes32 tokenSourceAddress,
        bytes calldata signature) external isActive {
        // Create message hash and validate the signature
        IValidator(validator).createUnlock(
                lockId,
                recipient,
                amount,
                lockSource,
                tokenSource,
                tokenSourceAddress,
                signature);

        // Mark lock as received
        address tokenAddress = tokenSourceMap[tokenSource][tokenSourceAddress];
        require(tokenAddress != address(0), "Bridge: unsupported token");
        TokenInfo memory tokenInfo = tokenInfos[tokenAddress];

        // Transform amount form system to token precision
        uint256 amountWithTokenPrecision = fromSystemPrecision(amount, tokenInfo.precision);
        uint256 fee = 0;
        if (msg.sender == unlockSigner) {
            fee = FeeOracle(feeOracle).minFee(tokenAddress);
            require(amountWithTokenPrecision > fee, "Bridge: amount too small");
            amountWithTokenPrecision = amountWithTokenPrecision - fee;
        }

        if (tokenInfo.tokenType == TokenType.Base) {
            // If token is WETH - transfer ETH
            payable(recipient).transfer(amountWithTokenPrecision);
            if (fee > 0) {
                payable(feeCollector).transfer(fee);
            }
        } else if (tokenInfo.tokenType == TokenType.Native) {
            // If token is native - transfer the token
            IERC20(tokenAddress).safeTransfer(recipient, amountWithTokenPrecision);
            if (fee > 0) {
                IERC20(tokenAddress).safeTransfer(feeCollector, fee);
            }
        } else if (tokenInfo.tokenType == TokenType.Wrapped) {
            // Else token is wrapped - mint tokens to the user
            WrappedToken(tokenAddress).mint(recipient, amountWithTokenPrecision);
            if (fee > 0) {
                WrappedToken(tokenAddress).mint(feeCollector, fee);
            }
        } else if (tokenInfo.tokenType == TokenType.WrappedV0) {
            // Legacy wrapped token
            IWrappedTokenV0(tokenAddress).mint(recipient, amountWithTokenPrecision);
            if (fee > 0) {
                IWrappedTokenV0(tokenAddress).mint(feeCollector, fee);
            }
        }

        emit Received(recipient, tokenAddress, amountWithTokenPrecision, lockId, lockSource);
    }

    // Method to add token that already exist in the current blockchain
    // Fee has to be in system precision
    // If token is wrapped, but it was deployed manually, isManualWrapped must be true
    function addToken(
        bytes4 tokenSource, 
        bytes32 tokenSourceAddress, 
        address nativeTokenAddress, 
        TokenType tokenType) external onlyRole(TOKEN_MANAGER) {
        require(
            tokenInfos[nativeTokenAddress].tokenSourceAddress == bytes32(0) &&
            tokenSourceMap[tokenSource][tokenSourceAddress] == address(0), "Bridge: exists");
        uint8 precision = ERC20(nativeTokenAddress).decimals();

        tokenSourceMap[tokenSource][tokenSourceAddress] = nativeTokenAddress;
        tokenInfos[nativeTokenAddress] = TokenInfo(
            tokenSource, 
            tokenSourceAddress, 
            precision, 
            tokenType, 
            TokenStatus.Enabled);
    }

    // Method to remove token from lists
    function removeToken(
        bytes4 tokenSource, 
        bytes32 tokenSourceAddress, 
        address newAuthority) external onlyRole(TOKEN_MANAGER) {
        require(newAuthority != address(0), "Bridge: zero address authority");
        address tokenAddress = tokenSourceMap[tokenSource][tokenSourceAddress];
        require(tokenAddress != address(0), "Bridge: token not found");
        TokenInfo memory tokenInfo = tokenInfos[tokenAddress];

        if (tokenInfo.tokenType == TokenType.Base && address(this).balance > 0) {
            payable(newAuthority).transfer(address(this).balance);
        }

        uint256 tokenBalance = IERC20(tokenAddress).balanceOf(address(this));
        if (tokenBalance > 0) {
            IERC20(tokenAddress).safeTransfer(newAuthority, tokenBalance);
        }

        if (tokenInfo.tokenType == TokenType.Wrapped) {
            WrappedToken(tokenAddress).transferOwnership(newAuthority);
        } else if (tokenInfo.tokenType == TokenType.WrappedV0) {
            IWrappedTokenV0(tokenAddress).changeAuthority(newAuthority);
        }

        delete tokenInfos[tokenAddress];
        delete tokenSourceMap[tokenSource][tokenSourceAddress];
    }

    function setFeeOracle(address _feeOracle) external onlyRole(TOKEN_MANAGER) {
        feeOracle = _feeOracle;
    }

    function setFeeCollector(address _feeCollector) external onlyRole(TOKEN_MANAGER) {
        feeCollector = _feeCollector;
    }

    function setValidator(address _validator ) external onlyRole(BRIDGE_MANAGER) {
        validator = _validator;
    }

    function setUnlockSigner(address _unlockSigner ) external onlyRole(BRIDGE_MANAGER) {
        unlockSigner = _unlockSigner;
    }

    function setTokenStatus(address tokenAddress, TokenStatus status)  external onlyRole(TOKEN_MANAGER) {
        require(tokenInfos[tokenAddress].tokenSourceAddress != bytes32(0), "Bridge: unsupported token");
        tokenInfos[tokenAddress].tokenStatus = status;
    }

    function startBridge() external onlyRole(BRIDGE_MANAGER) {
        active = true;
    }

    function stopBridge() external onlyRole(STOP_MANAGER) {
        active = false;
    }

    // Private method to validate lock, create lock record, and emmit the event
    // Method returns amount to lock and token info structure
    function _createLock(
        uint128 lockId,
        address tokenAddress,
        uint256 amount,
        bytes32 recipient,
        bytes4 destination
    ) private returns (uint256, uint256, TokenInfo memory) {
        require(amount > 0, "Bridge: amount is 0");
        TokenInfo memory tokenInfo = tokenInfos[tokenAddress];
        require(
            tokenInfo.tokenSourceAddress != bytes32(0),
            "Bridge: unsupported token"
        );

        uint256 fee = FeeOracle(feeOracle).fee(tokenAddress, msg.sender, amount, destination);

        require(amount > fee, "Bridge: amount too small");

        // Amount to lock is amount without fee
        uint256 amountToLock = amount - fee;

        // Create and add lock structure to the locks list
        IValidator(validator).createLock(
            lockId,
            msg.sender,
            recipient,
            toSystemPrecision(amountToLock, tokenInfo.precision),
            destination,
            tokenInfo.tokenSource,
            tokenInfo.tokenSourceAddress
        );

        emit Sent(
            tokenInfo.tokenSource,
            tokenInfo.tokenSourceAddress,
            msg.sender,
            recipient,
            amountToLock,
            lockId,
            destination
        );
        return (amountToLock, fee, tokenInfo);
    }

    // Convert amount from token precision to system precision
    function toSystemPrecision(uint256 amount, uint8 precision)
        private
        pure
        returns (uint256)
    {
        if (precision > SYSTEM_PRECISION) {
            return amount / (10**(precision - SYSTEM_PRECISION));
        } else if (precision < SYSTEM_PRECISION) {
            return amount * (10**(SYSTEM_PRECISION - precision));
        } else {
            return amount;
        }
    }

    // Convert amount from system precision to token precision
    function fromSystemPrecision(uint256 amount, uint8 precision)
        private
        pure
        returns (uint256)
    {
        if (precision > SYSTEM_PRECISION) {
            return amount * (10**(precision - SYSTEM_PRECISION));
        } else if (precision < SYSTEM_PRECISION) {
            return amount / (10**(SYSTEM_PRECISION - precision));
        } else {
            return amount;
        }
    }
}