123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725 |
- const __$G = (typeof globalThis !== 'undefined' ? globalThis: typeof window !== 'undefined' ? window: typeof global !== 'undefined' ? global: typeof self !== 'undefined' ? self: {});
- /* Do NOT modify this file; see /src.ts/_admin/update-version.ts */
- /**
- * The current version of Ethers.
- */
- const version = "6.13.5";
- /**
- * Property helper functions.
- *
- * @_subsection api/utils:Properties [about-properties]
- */
- function checkType(value, type, name) {
- const types = type.split("|").map(t => t.trim());
- for (let i = 0; i < types.length; i++) {
- switch (type) {
- case "any":
- return;
- case "bigint":
- case "boolean":
- case "number":
- case "string":
- if (typeof (value) === type) {
- return;
- }
- }
- }
- const error = new Error(`invalid value for type ${type}`);
- error.code = "INVALID_ARGUMENT";
- error.argument = `value.${name}`;
- error.value = value;
- throw error;
- }
- /**
- * Resolves to a new object that is a copy of %%value%%, but with all
- * values resolved.
- */
- async function resolveProperties(value) {
- const keys = Object.keys(value);
- const results = await Promise.all(keys.map((k) => Promise.resolve(value[k])));
- return results.reduce((accum, v, index) => {
- accum[keys[index]] = v;
- return accum;
- }, {});
- }
- /**
- * Assigns the %%values%% to %%target%% as read-only values.
- *
- * It %%types%% is specified, the values are checked.
- */
- function defineProperties(target, values, types) {
- for (let key in values) {
- let value = values[key];
- const type = (types ? types[key] : null);
- if (type) {
- checkType(value, type, key);
- }
- Object.defineProperty(target, key, { enumerable: true, value, writable: false });
- }
- }
- /**
- * All errors in ethers include properties to ensure they are both
- * human-readable (i.e. ``.message``) and machine-readable (i.e. ``.code``).
- *
- * The [[isError]] function can be used to check the error ``code`` and
- * provide a type guard for the properties present on that error interface.
- *
- * @_section: api/utils/errors:Errors [about-errors]
- */
- function stringify$1(value) {
- if (value == null) {
- return "null";
- }
- if (Array.isArray(value)) {
- return "[ " + (value.map(stringify$1)).join(", ") + " ]";
- }
- if (value instanceof Uint8Array) {
- const HEX = "0123456789abcdef";
- let result = "0x";
- for (let i = 0; i < value.length; i++) {
- result += HEX[value[i] >> 4];
- result += HEX[value[i] & 0xf];
- }
- return result;
- }
- if (typeof (value) === "object" && typeof (value.toJSON) === "function") {
- return stringify$1(value.toJSON());
- }
- switch (typeof (value)) {
- case "boolean":
- case "symbol":
- return value.toString();
- case "bigint":
- return BigInt(value).toString();
- case "number":
- return (value).toString();
- case "string":
- return JSON.stringify(value);
- case "object": {
- const keys = Object.keys(value);
- keys.sort();
- return "{ " + keys.map((k) => `${stringify$1(k)}: ${stringify$1(value[k])}`).join(", ") + " }";
- }
- }
- return `[ COULD NOT SERIALIZE ]`;
- }
- /**
- * Returns true if the %%error%% matches an error thrown by ethers
- * that matches the error %%code%%.
- *
- * In TypeScript environments, this can be used to check that %%error%%
- * matches an EthersError type, which means the expected properties will
- * be set.
- *
- * @See [ErrorCodes](api:ErrorCode)
- * @example
- * try {
- * // code....
- * } catch (e) {
- * if (isError(e, "CALL_EXCEPTION")) {
- * // The Type Guard has validated this object
- * console.log(e.data);
- * }
- * }
- */
- function isError(error, code) {
- return (error && error.code === code);
- }
- /**
- * Returns true if %%error%% is a [[CallExceptionError].
- */
- function isCallException(error) {
- return isError(error, "CALL_EXCEPTION");
- }
- /**
- * Returns a new Error configured to the format ethers emits errors, with
- * the %%message%%, [[api:ErrorCode]] %%code%% and additional properties
- * for the corresponding EthersError.
- *
- * Each error in ethers includes the version of ethers, a
- * machine-readable [[ErrorCode]], and depending on %%code%%, additional
- * required properties. The error message will also include the %%message%%,
- * ethers version, %%code%% and all additional properties, serialized.
- */
- function makeError(message, code, info) {
- let shortMessage = message;
- {
- const details = [];
- if (info) {
- if ("message" in info || "code" in info || "name" in info) {
- throw new Error(`value will overwrite populated values: ${stringify$1(info)}`);
- }
- for (const key in info) {
- if (key === "shortMessage") {
- continue;
- }
- const value = (info[key]);
- // try {
- details.push(key + "=" + stringify$1(value));
- // } catch (error: any) {
- // console.log("MMM", error.message);
- // details.push(key + "=[could not serialize object]");
- // }
- }
- }
- details.push(`code=${code}`);
- details.push(`version=${version}`);
- if (details.length) {
- message += " (" + details.join(", ") + ")";
- }
- }
- let error;
- switch (code) {
- case "INVALID_ARGUMENT":
- error = new TypeError(message);
- break;
- case "NUMERIC_FAULT":
- case "BUFFER_OVERRUN":
- error = new RangeError(message);
- break;
- default:
- error = new Error(message);
- }
- defineProperties(error, { code });
- if (info) {
- Object.assign(error, info);
- }
- if (error.shortMessage == null) {
- defineProperties(error, { shortMessage });
- }
- return error;
- }
- /**
- * Throws an EthersError with %%message%%, %%code%% and additional error
- * %%info%% when %%check%% is falsish..
- *
- * @see [[api:makeError]]
- */
- function assert(check, message, code, info) {
- if (!check) {
- throw makeError(message, code, info);
- }
- }
- /**
- * A simple helper to simply ensuring provided arguments match expected
- * constraints, throwing if not.
- *
- * In TypeScript environments, the %%check%% has been asserted true, so
- * any further code does not need additional compile-time checks.
- */
- function assertArgument(check, message, name, value) {
- assert(check, message, "INVALID_ARGUMENT", { argument: name, value: value });
- }
- function assertArgumentCount(count, expectedCount, message) {
- if (message == null) {
- message = "";
- }
- if (message) {
- message = ": " + message;
- }
- assert(count >= expectedCount, "missing argument" + message, "MISSING_ARGUMENT", {
- count: count,
- expectedCount: expectedCount
- });
- assert(count <= expectedCount, "too many arguments" + message, "UNEXPECTED_ARGUMENT", {
- count: count,
- expectedCount: expectedCount
- });
- }
- const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
- try {
- // General test for normalize
- /* c8 ignore start */
- if ("test".normalize(form) !== "test") {
- throw new Error("bad");
- }
- ;
- /* c8 ignore stop */
- if (form === "NFD") {
- const check = String.fromCharCode(0xe9).normalize("NFD");
- const expected = String.fromCharCode(0x65, 0x0301);
- /* c8 ignore start */
- if (check !== expected) {
- throw new Error("broken");
- }
- /* c8 ignore stop */
- }
- accum.push(form);
- }
- catch (error) { }
- return accum;
- }, []);
- /**
- * Throws if the normalization %%form%% is not supported.
- */
- function assertNormalize(form) {
- assert(_normalizeForms.indexOf(form) >= 0, "platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
- operation: "String.prototype.normalize", info: { form }
- });
- }
- /**
- * Many classes use file-scoped values to guard the constructor,
- * making it effectively private. This facilitates that pattern
- * by ensuring the %%givenGaurd%% matches the file-scoped %%guard%%,
- * throwing if not, indicating the %%className%% if provided.
- */
- function assertPrivate(givenGuard, guard, className) {
- if (className == null) {
- className = "";
- }
- if (givenGuard !== guard) {
- let method = className, operation = "new";
- if (className) {
- method += ".";
- operation += " " + className;
- }
- assert(false, `private constructor; use ${method}from* methods`, "UNSUPPORTED_OPERATION", {
- operation
- });
- }
- }
- /**
- * Some data helpers.
- *
- *
- * @_subsection api/utils:Data Helpers [about-data]
- */
- function _getBytes(value, name, copy) {
- if (value instanceof Uint8Array) {
- if (copy) {
- return new Uint8Array(value);
- }
- return value;
- }
- if (typeof (value) === "string" && value.match(/^0x(?:[0-9a-f][0-9a-f])*$/i)) {
- const result = new Uint8Array((value.length - 2) / 2);
- let offset = 2;
- for (let i = 0; i < result.length; i++) {
- result[i] = parseInt(value.substring(offset, offset + 2), 16);
- offset += 2;
- }
- return result;
- }
- assertArgument(false, "invalid BytesLike value", name || "value", value);
- }
- /**
- * Get a typed Uint8Array for %%value%%. If already a Uint8Array
- * the original %%value%% is returned; if a copy is required use
- * [[getBytesCopy]].
- *
- * @see: getBytesCopy
- */
- function getBytes(value, name) {
- return _getBytes(value, name, false);
- }
- /**
- * Get a typed Uint8Array for %%value%%, creating a copy if necessary
- * to prevent any modifications of the returned value from being
- * reflected elsewhere.
- *
- * @see: getBytes
- */
- function getBytesCopy(value, name) {
- return _getBytes(value, name, true);
- }
- /**
- * Returns true if %%value%% is a valid [[HexString]].
- *
- * If %%length%% is ``true`` or a //number//, it also checks that
- * %%value%% is a valid [[DataHexString]] of %%length%% (if a //number//)
- * bytes of data (e.g. ``0x1234`` is 2 bytes).
- */
- function isHexString(value, length) {
- if (typeof (value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {
- return false;
- }
- if (typeof (length) === "number" && value.length !== 2 + 2 * length) {
- return false;
- }
- if (length === true && (value.length % 2) !== 0) {
- return false;
- }
- return true;
- }
- /**
- * Returns true if %%value%% is a valid representation of arbitrary
- * data (i.e. a valid [[DataHexString]] or a Uint8Array).
- */
- function isBytesLike(value) {
- return (isHexString(value, true) || (value instanceof Uint8Array));
- }
- const HexCharacters = "0123456789abcdef";
- /**
- * Returns a [[DataHexString]] representation of %%data%%.
- */
- function hexlify(data) {
- const bytes = getBytes(data);
- let result = "0x";
- for (let i = 0; i < bytes.length; i++) {
- const v = bytes[i];
- result += HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f];
- }
- return result;
- }
- /**
- * Returns a [[DataHexString]] by concatenating all values
- * within %%data%%.
- */
- function concat(datas) {
- return "0x" + datas.map((d) => hexlify(d).substring(2)).join("");
- }
- /**
- * Returns the length of %%data%%, in bytes.
- */
- function dataLength(data) {
- if (isHexString(data, true)) {
- return (data.length - 2) / 2;
- }
- return getBytes(data).length;
- }
- /**
- * Returns a [[DataHexString]] by slicing %%data%% from the %%start%%
- * offset to the %%end%% offset.
- *
- * By default %%start%% is 0 and %%end%% is the length of %%data%%.
- */
- function dataSlice(data, start, end) {
- const bytes = getBytes(data);
- if (end != null && end > bytes.length) {
- assert(false, "cannot slice beyond data bounds", "BUFFER_OVERRUN", {
- buffer: bytes, length: bytes.length, offset: end
- });
- }
- return hexlify(bytes.slice((start == null) ? 0 : start, (end == null) ? bytes.length : end));
- }
- /**
- * Return the [[DataHexString]] result by stripping all **leading**
- ** zero bytes from %%data%%.
- */
- function stripZerosLeft(data) {
- let bytes = hexlify(data).substring(2);
- while (bytes.startsWith("00")) {
- bytes = bytes.substring(2);
- }
- return "0x" + bytes;
- }
- function zeroPad(data, length, left) {
- const bytes = getBytes(data);
- assert(length >= bytes.length, "padding exceeds data length", "BUFFER_OVERRUN", {
- buffer: new Uint8Array(bytes),
- length: length,
- offset: length + 1
- });
- const result = new Uint8Array(length);
- result.fill(0);
- if (left) {
- result.set(bytes, length - bytes.length);
- }
- else {
- result.set(bytes, 0);
- }
- return hexlify(result);
- }
- /**
- * Return the [[DataHexString]] of %%data%% padded on the **left**
- * to %%length%% bytes.
- *
- * If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] is
- * thrown.
- *
- * This pads data the same as **values** are in Solidity
- * (e.g. ``uint128``).
- */
- function zeroPadValue(data, length) {
- return zeroPad(data, length, true);
- }
- /**
- * Return the [[DataHexString]] of %%data%% padded on the **right**
- * to %%length%% bytes.
- *
- * If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] is
- * thrown.
- *
- * This pads data the same as **bytes** are in Solidity
- * (e.g. ``bytes16``).
- */
- function zeroPadBytes(data, length) {
- return zeroPad(data, length, false);
- }
- /**
- * Some mathematic operations.
- *
- * @_subsection: api/utils:Math Helpers [about-maths]
- */
- const BN_0$a = BigInt(0);
- const BN_1$5 = BigInt(1);
- //const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
- // IEEE 754 support 53-bits of mantissa
- const maxValue = 0x1fffffffffffff;
- /**
- * Convert %%value%% from a twos-compliment representation of %%width%%
- * bits to its value.
- *
- * If the highest bit is ``1``, the result will be negative.
- */
- function fromTwos(_value, _width) {
- const value = getUint(_value, "value");
- const width = BigInt(getNumber(_width, "width"));
- assert((value >> width) === BN_0$a, "overflow", "NUMERIC_FAULT", {
- operation: "fromTwos", fault: "overflow", value: _value
- });
- // Top bit set; treat as a negative value
- if (value >> (width - BN_1$5)) {
- const mask = (BN_1$5 << width) - BN_1$5;
- return -(((~value) & mask) + BN_1$5);
- }
- return value;
- }
- /**
- * Convert %%value%% to a twos-compliment representation of
- * %%width%% bits.
- *
- * The result will always be positive.
- */
- function toTwos(_value, _width) {
- let value = getBigInt(_value, "value");
- const width = BigInt(getNumber(_width, "width"));
- const limit = (BN_1$5 << (width - BN_1$5));
- if (value < BN_0$a) {
- value = -value;
- assert(value <= limit, "too low", "NUMERIC_FAULT", {
- operation: "toTwos", fault: "overflow", value: _value
- });
- const mask = (BN_1$5 << width) - BN_1$5;
- return ((~value) & mask) + BN_1$5;
- }
- else {
- assert(value < limit, "too high", "NUMERIC_FAULT", {
- operation: "toTwos", fault: "overflow", value: _value
- });
- }
- return value;
- }
- /**
- * Mask %%value%% with a bitmask of %%bits%% ones.
- */
- function mask(_value, _bits) {
- const value = getUint(_value, "value");
- const bits = BigInt(getNumber(_bits, "bits"));
- return value & ((BN_1$5 << bits) - BN_1$5);
- }
- /**
- * Gets a BigInt from %%value%%. If it is an invalid value for
- * a BigInt, then an ArgumentError will be thrown for %%name%%.
- */
- function getBigInt(value, name) {
- switch (typeof (value)) {
- case "bigint": return value;
- case "number":
- assertArgument(Number.isInteger(value), "underflow", name || "value", value);
- assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
- return BigInt(value);
- case "string":
- try {
- if (value === "") {
- throw new Error("empty string");
- }
- if (value[0] === "-" && value[1] !== "-") {
- return -BigInt(value.substring(1));
- }
- return BigInt(value);
- }
- catch (e) {
- assertArgument(false, `invalid BigNumberish string: ${e.message}`, name || "value", value);
- }
- }
- assertArgument(false, "invalid BigNumberish value", name || "value", value);
- }
- /**
- * Returns %%value%% as a bigint, validating it is valid as a bigint
- * value and that it is positive.
- */
- function getUint(value, name) {
- const result = getBigInt(value, name);
- assert(result >= BN_0$a, "unsigned value cannot be negative", "NUMERIC_FAULT", {
- fault: "overflow", operation: "getUint", value
- });
- return result;
- }
- const Nibbles$1 = "0123456789abcdef";
- /*
- * Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it
- * is treated as Big Endian data.
- */
- function toBigInt(value) {
- if (value instanceof Uint8Array) {
- let result = "0x0";
- for (const v of value) {
- result += Nibbles$1[v >> 4];
- result += Nibbles$1[v & 0x0f];
- }
- return BigInt(result);
- }
- return getBigInt(value);
- }
- /**
- * Gets a //number// from %%value%%. If it is an invalid value for
- * a //number//, then an ArgumentError will be thrown for %%name%%.
- */
- function getNumber(value, name) {
- switch (typeof (value)) {
- case "bigint":
- assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
- return Number(value);
- case "number":
- assertArgument(Number.isInteger(value), "underflow", name || "value", value);
- assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
- return value;
- case "string":
- try {
- if (value === "") {
- throw new Error("empty string");
- }
- return getNumber(BigInt(value), name);
- }
- catch (e) {
- assertArgument(false, `invalid numeric string: ${e.message}`, name || "value", value);
- }
- }
- assertArgument(false, "invalid numeric value", name || "value", value);
- }
- /**
- * Converts %%value%% to a number. If %%value%% is a Uint8Array, it
- * is treated as Big Endian data. Throws if the value is not safe.
- */
- function toNumber(value) {
- return getNumber(toBigInt(value));
- }
- /**
- * Converts %%value%% to a Big Endian hexstring, optionally padded to
- * %%width%% bytes.
- */
- function toBeHex(_value, _width) {
- const value = getUint(_value, "value");
- let result = value.toString(16);
- if (_width == null) {
- // Ensure the value is of even length
- if (result.length % 2) {
- result = "0" + result;
- }
- }
- else {
- const width = getNumber(_width, "width");
- assert(width * 2 >= result.length, `value exceeds width (${width} bytes)`, "NUMERIC_FAULT", {
- operation: "toBeHex",
- fault: "overflow",
- value: _value
- });
- // Pad the value to the required width
- while (result.length < (width * 2)) {
- result = "0" + result;
- }
- }
- return "0x" + result;
- }
- /**
- * Converts %%value%% to a Big Endian Uint8Array.
- */
- function toBeArray(_value) {
- const value = getUint(_value, "value");
- if (value === BN_0$a) {
- return new Uint8Array([]);
- }
- let hex = value.toString(16);
- if (hex.length % 2) {
- hex = "0" + hex;
- }
- const result = new Uint8Array(hex.length / 2);
- for (let i = 0; i < result.length; i++) {
- const offset = i * 2;
- result[i] = parseInt(hex.substring(offset, offset + 2), 16);
- }
- return result;
- }
- /**
- * Returns a [[HexString]] for %%value%% safe to use as a //Quantity//.
- *
- * A //Quantity// does not have and leading 0 values unless the value is
- * the literal value `0x0`. This is most commonly used for JSSON-RPC
- * numeric values.
- */
- function toQuantity(value) {
- let result = hexlify(isBytesLike(value) ? value : toBeArray(value)).substring(2);
- while (result.startsWith("0")) {
- result = result.substring(1);
- }
- if (result === "") {
- result = "0";
- }
- return "0x" + result;
- }
- /**
- * The [Base58 Encoding](link-base58) scheme allows a **numeric** value
- * to be encoded as a compact string using a radix of 58 using only
- * alpha-numeric characters. Confusingly similar characters are omitted
- * (i.e. ``"l0O"``).
- *
- * Note that Base58 encodes a **numeric** value, not arbitrary bytes,
- * since any zero-bytes on the left would get removed. To mitigate this
- * issue most schemes that use Base58 choose specific high-order values
- * to ensure non-zero prefixes.
- *
- * @_subsection: api/utils:Base58 Encoding [about-base58]
- */
- const Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
- let Lookup = null;
- function getAlpha(letter) {
- if (Lookup == null) {
- Lookup = {};
- for (let i = 0; i < Alphabet.length; i++) {
- Lookup[Alphabet[i]] = BigInt(i);
- }
- }
- const result = Lookup[letter];
- assertArgument(result != null, `invalid base58 value`, "letter", letter);
- return result;
- }
- const BN_0$9 = BigInt(0);
- const BN_58 = BigInt(58);
- /**
- * Encode %%value%% as a Base58-encoded string.
- */
- function encodeBase58(_value) {
- const bytes = getBytes(_value);
- let value = toBigInt(bytes);
- let result = "";
- while (value) {
- result = Alphabet[Number(value % BN_58)] + result;
- value /= BN_58;
- }
- // Account for leading padding zeros
- for (let i = 0; i < bytes.length; i++) {
- if (bytes[i]) {
- break;
- }
- result = Alphabet[0] + result;
- }
- return result;
- }
- /**
- * Decode the Base58-encoded %%value%%.
- */
- function decodeBase58(value) {
- let result = BN_0$9;
- for (let i = 0; i < value.length; i++) {
- result *= BN_58;
- result += getAlpha(value[i]);
- }
- return result;
- }
- // utils/base64-browser
- function decodeBase64(textData) {
- textData = atob(textData);
- const data = new Uint8Array(textData.length);
- for (let i = 0; i < textData.length; i++) {
- data[i] = textData.charCodeAt(i);
- }
- return getBytes(data);
- }
- function encodeBase64(_data) {
- const data = getBytes(_data);
- let textData = "";
- for (let i = 0; i < data.length; i++) {
- textData += String.fromCharCode(data[i]);
- }
- return btoa(textData);
- }
- /**
- * Events allow for applications to use the observer pattern, which
- * allows subscribing and publishing events, outside the normal
- * execution paths.
- *
- * @_section api/utils/events:Events [about-events]
- */
- /**
- * When an [[EventEmitterable]] triggers a [[Listener]], the
- * callback always ahas one additional argument passed, which is
- * an **EventPayload**.
- */
- class EventPayload {
- /**
- * The event filter.
- */
- filter;
- /**
- * The **EventEmitterable**.
- */
- emitter;
- #listener;
- /**
- * Create a new **EventPayload** for %%emitter%% with
- * the %%listener%% and for %%filter%%.
- */
- constructor(emitter, listener, filter) {
- this.#listener = listener;
- defineProperties(this, { emitter, filter });
- }
- /**
- * Unregister the triggered listener for future events.
- */
- async removeListener() {
- if (this.#listener == null) {
- return;
- }
- await this.emitter.off(this.filter, this.#listener);
- }
- }
- /**
- * Using strings in Ethereum (or any security-basd system) requires
- * additional care. These utilities attempt to mitigate some of the
- * safety issues as well as provide the ability to recover and analyse
- * strings.
- *
- * @_subsection api/utils:Strings and UTF-8 [about-strings]
- */
- function errorFunc(reason, offset, bytes, output, badCodepoint) {
- assertArgument(false, `invalid codepoint at offset ${offset}; ${reason}`, "bytes", bytes);
- }
- function ignoreFunc(reason, offset, bytes, output, badCodepoint) {
- // If there is an invalid prefix (including stray continuation), skip any additional continuation bytes
- if (reason === "BAD_PREFIX" || reason === "UNEXPECTED_CONTINUE") {
- let i = 0;
- for (let o = offset + 1; o < bytes.length; o++) {
- if (bytes[o] >> 6 !== 0x02) {
- break;
- }
- i++;
- }
- return i;
- }
- // This byte runs us past the end of the string, so just jump to the end
- // (but the first byte was read already read and therefore skipped)
- if (reason === "OVERRUN") {
- return bytes.length - offset - 1;
- }
- // Nothing to skip
- return 0;
- }
- function replaceFunc(reason, offset, bytes, output, badCodepoint) {
- // Overlong representations are otherwise "valid" code points; just non-deistingtished
- if (reason === "OVERLONG") {
- assertArgument(typeof (badCodepoint) === "number", "invalid bad code point for replacement", "badCodepoint", badCodepoint);
- output.push(badCodepoint);
- return 0;
- }
- // Put the replacement character into the output
- output.push(0xfffd);
- // Otherwise, process as if ignoring errors
- return ignoreFunc(reason, offset, bytes);
- }
- /**
- * A handful of popular, built-in UTF-8 error handling strategies.
- *
- * **``"error"``** - throws on ANY illegal UTF-8 sequence or
- * non-canonical (overlong) codepoints (this is the default)
- *
- * **``"ignore"``** - silently drops any illegal UTF-8 sequence
- * and accepts non-canonical (overlong) codepoints
- *
- * **``"replace"``** - replace any illegal UTF-8 sequence with the
- * UTF-8 replacement character (i.e. ``"\\ufffd"``) and accepts
- * non-canonical (overlong) codepoints
- *
- * @returns: Record<"error" | "ignore" | "replace", Utf8ErrorFunc>
- */
- const Utf8ErrorFuncs = Object.freeze({
- error: errorFunc,
- ignore: ignoreFunc,
- replace: replaceFunc
- });
- // http://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript#13691499
- function getUtf8CodePoints(_bytes, onError) {
- if (onError == null) {
- onError = Utf8ErrorFuncs.error;
- }
- const bytes = getBytes(_bytes, "bytes");
- const result = [];
- let i = 0;
- // Invalid bytes are ignored
- while (i < bytes.length) {
- const c = bytes[i++];
- // 0xxx xxxx
- if (c >> 7 === 0) {
- result.push(c);
- continue;
- }
- // Multibyte; how many bytes left for this character?
- let extraLength = null;
- let overlongMask = null;
- // 110x xxxx 10xx xxxx
- if ((c & 0xe0) === 0xc0) {
- extraLength = 1;
- overlongMask = 0x7f;
- // 1110 xxxx 10xx xxxx 10xx xxxx
- }
- else if ((c & 0xf0) === 0xe0) {
- extraLength = 2;
- overlongMask = 0x7ff;
- // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
- }
- else if ((c & 0xf8) === 0xf0) {
- extraLength = 3;
- overlongMask = 0xffff;
- }
- else {
- if ((c & 0xc0) === 0x80) {
- i += onError("UNEXPECTED_CONTINUE", i - 1, bytes, result);
- }
- else {
- i += onError("BAD_PREFIX", i - 1, bytes, result);
- }
- continue;
- }
- // Do we have enough bytes in our data?
- if (i - 1 + extraLength >= bytes.length) {
- i += onError("OVERRUN", i - 1, bytes, result);
- continue;
- }
- // Remove the length prefix from the char
- let res = c & ((1 << (8 - extraLength - 1)) - 1);
- for (let j = 0; j < extraLength; j++) {
- let nextChar = bytes[i];
- // Invalid continuation byte
- if ((nextChar & 0xc0) != 0x80) {
- i += onError("MISSING_CONTINUE", i, bytes, result);
- res = null;
- break;
- }
- res = (res << 6) | (nextChar & 0x3f);
- i++;
- }
- // See above loop for invalid continuation byte
- if (res === null) {
- continue;
- }
- // Maximum code point
- if (res > 0x10ffff) {
- i += onError("OUT_OF_RANGE", i - 1 - extraLength, bytes, result, res);
- continue;
- }
- // Reserved for UTF-16 surrogate halves
- if (res >= 0xd800 && res <= 0xdfff) {
- i += onError("UTF16_SURROGATE", i - 1 - extraLength, bytes, result, res);
- continue;
- }
- // Check for overlong sequences (more bytes than needed)
- if (res <= overlongMask) {
- i += onError("OVERLONG", i - 1 - extraLength, bytes, result, res);
- continue;
- }
- result.push(res);
- }
- return result;
- }
- // http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
- /**
- * Returns the UTF-8 byte representation of %%str%%.
- *
- * If %%form%% is specified, the string is normalized.
- */
- function toUtf8Bytes(str, form) {
- assertArgument(typeof (str) === "string", "invalid string value", "str", str);
- if (form != null) {
- assertNormalize(form);
- str = str.normalize(form);
- }
- let result = [];
- for (let i = 0; i < str.length; i++) {
- const c = str.charCodeAt(i);
- if (c < 0x80) {
- result.push(c);
- }
- else if (c < 0x800) {
- result.push((c >> 6) | 0xc0);
- result.push((c & 0x3f) | 0x80);
- }
- else if ((c & 0xfc00) == 0xd800) {
- i++;
- const c2 = str.charCodeAt(i);
- assertArgument(i < str.length && ((c2 & 0xfc00) === 0xdc00), "invalid surrogate pair", "str", str);
- // Surrogate Pair
- const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
- result.push((pair >> 18) | 0xf0);
- result.push(((pair >> 12) & 0x3f) | 0x80);
- result.push(((pair >> 6) & 0x3f) | 0x80);
- result.push((pair & 0x3f) | 0x80);
- }
- else {
- result.push((c >> 12) | 0xe0);
- result.push(((c >> 6) & 0x3f) | 0x80);
- result.push((c & 0x3f) | 0x80);
- }
- }
- return new Uint8Array(result);
- }
- //export
- function _toUtf8String(codePoints) {
- return codePoints.map((codePoint) => {
- if (codePoint <= 0xffff) {
- return String.fromCharCode(codePoint);
- }
- codePoint -= 0x10000;
- return String.fromCharCode((((codePoint >> 10) & 0x3ff) + 0xd800), ((codePoint & 0x3ff) + 0xdc00));
- }).join("");
- }
- /**
- * Returns the string represented by the UTF-8 data %%bytes%%.
- *
- * When %%onError%% function is specified, it is called on UTF-8
- * errors allowing recovery using the [[Utf8ErrorFunc]] API.
- * (default: [error](Utf8ErrorFuncs))
- */
- function toUtf8String(bytes, onError) {
- return _toUtf8String(getUtf8CodePoints(bytes, onError));
- }
- /**
- * Returns the UTF-8 code-points for %%str%%.
- *
- * If %%form%% is specified, the string is normalized.
- */
- function toUtf8CodePoints(str, form) {
- return getUtf8CodePoints(toUtf8Bytes(str, form));
- }
- function createGetUrl(options) {
- async function getUrl(req, _signal) {
- assert(_signal == null || !_signal.cancelled, "request cancelled before sending", "CANCELLED");
- const protocol = req.url.split(":")[0].toLowerCase();
- assert(protocol === "http" || protocol === "https", `unsupported protocol ${protocol}`, "UNSUPPORTED_OPERATION", {
- info: { protocol },
- operation: "request"
- });
- assert(protocol === "https" || !req.credentials || req.allowInsecureAuthentication, "insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
- operation: "request"
- });
- let error = null;
- const controller = new AbortController();
- const timer = setTimeout(() => {
- error = makeError("request timeout", "TIMEOUT");
- controller.abort();
- }, req.timeout);
- if (_signal) {
- _signal.addListener(() => {
- error = makeError("request cancelled", "CANCELLED");
- controller.abort();
- });
- }
- const init = {
- method: req.method,
- headers: new Headers(Array.from(req)),
- body: req.body || undefined,
- signal: controller.signal
- };
- let resp;
- try {
- resp = await fetch(req.url, init);
- }
- catch (_error) {
- clearTimeout(timer);
- if (error) {
- throw error;
- }
- throw _error;
- }
- clearTimeout(timer);
- const headers = {};
- resp.headers.forEach((value, key) => {
- headers[key.toLowerCase()] = value;
- });
- const respBody = await resp.arrayBuffer();
- const body = (respBody == null) ? null : new Uint8Array(respBody);
- return {
- statusCode: resp.status,
- statusMessage: resp.statusText,
- headers, body
- };
- }
- return getUrl;
- }
- /**
- * Fetching content from the web is environment-specific, so Ethers
- * provides an abstraction that each environment can implement to provide
- * this service.
- *
- * On [Node.js](link-node), the ``http`` and ``https`` libs are used to
- * create a request object, register event listeners and process data
- * and populate the [[FetchResponse]].
- *
- * In a browser, the [DOM fetch](link-js-fetch) is used, and the resulting
- * ``Promise`` is waited on to retrieve the payload.
- *
- * The [[FetchRequest]] is responsible for handling many common situations,
- * such as redirects, server throttling, authentication, etc.
- *
- * It also handles common gateways, such as IPFS and data URIs.
- *
- * @_section api/utils/fetching:Fetching Web Content [about-fetch]
- */
- const MAX_ATTEMPTS = 12;
- const SLOT_INTERVAL = 250;
- // The global FetchGetUrlFunc implementation.
- let defaultGetUrlFunc = createGetUrl();
- const reData = new RegExp("^data:([^;:]*)?(;base64)?,(.*)$", "i");
- const reIpfs = new RegExp("^ipfs:/\/(ipfs/)?(.*)$", "i");
- // If locked, new Gateways cannot be added
- let locked$5 = false;
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
- async function dataGatewayFunc(url, signal) {
- try {
- const match = url.match(reData);
- if (!match) {
- throw new Error("invalid data");
- }
- return new FetchResponse(200, "OK", {
- "content-type": (match[1] || "text/plain"),
- }, (match[2] ? decodeBase64(match[3]) : unpercent(match[3])));
- }
- catch (error) {
- return new FetchResponse(599, "BAD REQUEST (invalid data: URI)", {}, null, new FetchRequest(url));
- }
- }
- /**
- * Returns a [[FetchGatewayFunc]] for fetching content from a standard
- * IPFS gateway hosted at %%baseUrl%%.
- */
- function getIpfsGatewayFunc(baseUrl) {
- async function gatewayIpfs(url, signal) {
- try {
- const match = url.match(reIpfs);
- if (!match) {
- throw new Error("invalid link");
- }
- return new FetchRequest(`${baseUrl}${match[2]}`);
- }
- catch (error) {
- return new FetchResponse(599, "BAD REQUEST (invalid IPFS URI)", {}, null, new FetchRequest(url));
- }
- }
- return gatewayIpfs;
- }
- const Gateways = {
- "data": dataGatewayFunc,
- "ipfs": getIpfsGatewayFunc("https:/\/gateway.ipfs.io/ipfs/")
- };
- const fetchSignals = new WeakMap();
- /**
- * @_ignore
- */
- class FetchCancelSignal {
- #listeners;
- #cancelled;
- constructor(request) {
- this.#listeners = [];
- this.#cancelled = false;
- fetchSignals.set(request, () => {
- if (this.#cancelled) {
- return;
- }
- this.#cancelled = true;
- for (const listener of this.#listeners) {
- setTimeout(() => { listener(); }, 0);
- }
- this.#listeners = [];
- });
- }
- addListener(listener) {
- assert(!this.#cancelled, "singal already cancelled", "UNSUPPORTED_OPERATION", {
- operation: "fetchCancelSignal.addCancelListener"
- });
- this.#listeners.push(listener);
- }
- get cancelled() { return this.#cancelled; }
- checkSignal() {
- assert(!this.cancelled, "cancelled", "CANCELLED", {});
- }
- }
- // Check the signal, throwing if it is cancelled
- function checkSignal(signal) {
- if (signal == null) {
- throw new Error("missing signal; should not happen");
- }
- signal.checkSignal();
- return signal;
- }
- /**
- * Represents a request for a resource using a URI.
- *
- * By default, the supported schemes are ``HTTP``, ``HTTPS``, ``data:``,
- * and ``IPFS:``.
- *
- * Additional schemes can be added globally using [[registerGateway]].
- *
- * @example:
- * req = new FetchRequest("https://www.ricmoo.com")
- * resp = await req.send()
- * resp.body.length
- * //_result:
- */
- class FetchRequest {
- #allowInsecure;
- #gzip;
- #headers;
- #method;
- #timeout;
- #url;
- #body;
- #bodyType;
- #creds;
- // Hooks
- #preflight;
- #process;
- #retry;
- #signal;
- #throttle;
- #getUrlFunc;
- /**
- * The fetch URL to request.
- */
- get url() { return this.#url; }
- set url(url) {
- this.#url = String(url);
- }
- /**
- * The fetch body, if any, to send as the request body. //(default: null)//
- *
- * When setting a body, the intrinsic ``Content-Type`` is automatically
- * set and will be used if **not overridden** by setting a custom
- * header.
- *
- * If %%body%% is null, the body is cleared (along with the
- * intrinsic ``Content-Type``).
- *
- * If %%body%% is a string, the intrinsic ``Content-Type`` is set to
- * ``text/plain``.
- *
- * If %%body%% is a Uint8Array, the intrinsic ``Content-Type`` is set to
- * ``application/octet-stream``.
- *
- * If %%body%% is any other object, the intrinsic ``Content-Type`` is
- * set to ``application/json``.
- */
- get body() {
- if (this.#body == null) {
- return null;
- }
- return new Uint8Array(this.#body);
- }
- set body(body) {
- if (body == null) {
- this.#body = undefined;
- this.#bodyType = undefined;
- }
- else if (typeof (body) === "string") {
- this.#body = toUtf8Bytes(body);
- this.#bodyType = "text/plain";
- }
- else if (body instanceof Uint8Array) {
- this.#body = body;
- this.#bodyType = "application/octet-stream";
- }
- else if (typeof (body) === "object") {
- this.#body = toUtf8Bytes(JSON.stringify(body));
- this.#bodyType = "application/json";
- }
- else {
- throw new Error("invalid body");
- }
- }
- /**
- * Returns true if the request has a body.
- */
- hasBody() {
- return (this.#body != null);
- }
- /**
- * The HTTP method to use when requesting the URI. If no method
- * has been explicitly set, then ``GET`` is used if the body is
- * null and ``POST`` otherwise.
- */
- get method() {
- if (this.#method) {
- return this.#method;
- }
- if (this.hasBody()) {
- return "POST";
- }
- return "GET";
- }
- set method(method) {
- if (method == null) {
- method = "";
- }
- this.#method = String(method).toUpperCase();
- }
- /**
- * The headers that will be used when requesting the URI. All
- * keys are lower-case.
- *
- * This object is a copy, so any changes will **NOT** be reflected
- * in the ``FetchRequest``.
- *
- * To set a header entry, use the ``setHeader`` method.
- */
- get headers() {
- const headers = Object.assign({}, this.#headers);
- if (this.#creds) {
- headers["authorization"] = `Basic ${encodeBase64(toUtf8Bytes(this.#creds))}`;
- }
- if (this.allowGzip) {
- headers["accept-encoding"] = "gzip";
- }
- if (headers["content-type"] == null && this.#bodyType) {
- headers["content-type"] = this.#bodyType;
- }
- if (this.body) {
- headers["content-length"] = String(this.body.length);
- }
- return headers;
- }
- /**
- * Get the header for %%key%%, ignoring case.
- */
- getHeader(key) {
- return this.headers[key.toLowerCase()];
- }
- /**
- * Set the header for %%key%% to %%value%%. All values are coerced
- * to a string.
- */
- setHeader(key, value) {
- this.#headers[String(key).toLowerCase()] = String(value);
- }
- /**
- * Clear all headers, resetting all intrinsic headers.
- */
- clearHeaders() {
- this.#headers = {};
- }
- [Symbol.iterator]() {
- const headers = this.headers;
- const keys = Object.keys(headers);
- let index = 0;
- return {
- next: () => {
- if (index < keys.length) {
- const key = keys[index++];
- return {
- value: [key, headers[key]], done: false
- };
- }
- return { value: undefined, done: true };
- }
- };
- }
- /**
- * The value that will be sent for the ``Authorization`` header.
- *
- * To set the credentials, use the ``setCredentials`` method.
- */
- get credentials() {
- return this.#creds || null;
- }
- /**
- * Sets an ``Authorization`` for %%username%% with %%password%%.
- */
- setCredentials(username, password) {
- assertArgument(!username.match(/:/), "invalid basic authentication username", "username", "[REDACTED]");
- this.#creds = `${username}:${password}`;
- }
- /**
- * Enable and request gzip-encoded responses. The response will
- * automatically be decompressed. //(default: true)//
- */
- get allowGzip() {
- return this.#gzip;
- }
- set allowGzip(value) {
- this.#gzip = !!value;
- }
- /**
- * Allow ``Authentication`` credentials to be sent over insecure
- * channels. //(default: false)//
- */
- get allowInsecureAuthentication() {
- return !!this.#allowInsecure;
- }
- set allowInsecureAuthentication(value) {
- this.#allowInsecure = !!value;
- }
- /**
- * The timeout (in milliseconds) to wait for a complete response.
- * //(default: 5 minutes)//
- */
- get timeout() { return this.#timeout; }
- set timeout(timeout) {
- assertArgument(timeout >= 0, "timeout must be non-zero", "timeout", timeout);
- this.#timeout = timeout;
- }
- /**
- * This function is called prior to each request, for example
- * during a redirection or retry in case of server throttling.
- *
- * This offers an opportunity to populate headers or update
- * content before sending a request.
- */
- get preflightFunc() {
- return this.#preflight || null;
- }
- set preflightFunc(preflight) {
- this.#preflight = preflight;
- }
- /**
- * This function is called after each response, offering an
- * opportunity to provide client-level throttling or updating
- * response data.
- *
- * Any error thrown in this causes the ``send()`` to throw.
- *
- * To schedule a retry attempt (assuming the maximum retry limit
- * has not been reached), use [[response.throwThrottleError]].
- */
- get processFunc() {
- return this.#process || null;
- }
- set processFunc(process) {
- this.#process = process;
- }
- /**
- * This function is called on each retry attempt.
- */
- get retryFunc() {
- return this.#retry || null;
- }
- set retryFunc(retry) {
- this.#retry = retry;
- }
- /**
- * This function is called to fetch content from HTTP and
- * HTTPS URLs and is platform specific (e.g. nodejs vs
- * browsers).
- *
- * This is by default the currently registered global getUrl
- * function, which can be changed using [[registerGetUrl]].
- * If this has been set, setting is to ``null`` will cause
- * this FetchRequest (and any future clones) to revert back to
- * using the currently registered global getUrl function.
- *
- * Setting this is generally not necessary, but may be useful
- * for developers that wish to intercept requests or to
- * configurege a proxy or other agent.
- */
- get getUrlFunc() {
- return this.#getUrlFunc || defaultGetUrlFunc;
- }
- set getUrlFunc(value) {
- this.#getUrlFunc = value;
- }
- /**
- * Create a new FetchRequest instance with default values.
- *
- * Once created, each property may be set before issuing a
- * ``.send()`` to make the request.
- */
- constructor(url) {
- this.#url = String(url);
- this.#allowInsecure = false;
- this.#gzip = true;
- this.#headers = {};
- this.#method = "";
- this.#timeout = 300000;
- this.#throttle = {
- slotInterval: SLOT_INTERVAL,
- maxAttempts: MAX_ATTEMPTS
- };
- this.#getUrlFunc = null;
- }
- toString() {
- return `<FetchRequest method=${JSON.stringify(this.method)} url=${JSON.stringify(this.url)} headers=${JSON.stringify(this.headers)} body=${this.#body ? hexlify(this.#body) : "null"}>`;
- }
- /**
- * Update the throttle parameters used to determine maximum
- * attempts and exponential-backoff properties.
- */
- setThrottleParams(params) {
- if (params.slotInterval != null) {
- this.#throttle.slotInterval = params.slotInterval;
- }
- if (params.maxAttempts != null) {
- this.#throttle.maxAttempts = params.maxAttempts;
- }
- }
- async #send(attempt, expires, delay, _request, _response) {
- if (attempt >= this.#throttle.maxAttempts) {
- return _response.makeServerError("exceeded maximum retry limit");
- }
- assert(getTime$2() <= expires, "timeout", "TIMEOUT", {
- operation: "request.send", reason: "timeout", request: _request
- });
- if (delay > 0) {
- await wait(delay);
- }
- let req = this.clone();
- const scheme = (req.url.split(":")[0] || "").toLowerCase();
- // Process any Gateways
- if (scheme in Gateways) {
- const result = await Gateways[scheme](req.url, checkSignal(_request.#signal));
- if (result instanceof FetchResponse) {
- let response = result;
- if (this.processFunc) {
- checkSignal(_request.#signal);
- try {
- response = await this.processFunc(req, response);
- }
- catch (error) {
- // Something went wrong during processing; throw a 5xx server error
- if (error.throttle == null || typeof (error.stall) !== "number") {
- response.makeServerError("error in post-processing function", error).assertOk();
- }
- // Ignore throttling
- }
- }
- return response;
- }
- req = result;
- }
- // We have a preflight function; update the request
- if (this.preflightFunc) {
- req = await this.preflightFunc(req);
- }
- const resp = await this.getUrlFunc(req, checkSignal(_request.#signal));
- let response = new FetchResponse(resp.statusCode, resp.statusMessage, resp.headers, resp.body, _request);
- if (response.statusCode === 301 || response.statusCode === 302) {
- // Redirect
- try {
- const location = response.headers.location || "";
- return req.redirect(location).#send(attempt + 1, expires, 0, _request, response);
- }
- catch (error) { }
- // Things won't get any better on another attempt; abort
- return response;
- }
- else if (response.statusCode === 429) {
- // Throttle
- if (this.retryFunc == null || (await this.retryFunc(req, response, attempt))) {
- const retryAfter = response.headers["retry-after"];
- let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));
- if (typeof (retryAfter) === "string" && retryAfter.match(/^[1-9][0-9]*$/)) {
- delay = parseInt(retryAfter);
- }
- return req.clone().#send(attempt + 1, expires, delay, _request, response);
- }
- }
- if (this.processFunc) {
- checkSignal(_request.#signal);
- try {
- response = await this.processFunc(req, response);
- }
- catch (error) {
- // Something went wrong during processing; throw a 5xx server error
- if (error.throttle == null || typeof (error.stall) !== "number") {
- response.makeServerError("error in post-processing function", error).assertOk();
- }
- // Throttle
- let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));
- if (error.stall >= 0) {
- delay = error.stall;
- }
- return req.clone().#send(attempt + 1, expires, delay, _request, response);
- }
- }
- return response;
- }
- /**
- * Resolves to the response by sending the request.
- */
- send() {
- assert(this.#signal == null, "request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
- this.#signal = new FetchCancelSignal(this);
- return this.#send(0, getTime$2() + this.timeout, 0, this, new FetchResponse(0, "", {}, null, this));
- }
- /**
- * Cancels the inflight response, causing a ``CANCELLED``
- * error to be rejected from the [[send]].
- */
- cancel() {
- assert(this.#signal != null, "request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
- const signal = fetchSignals.get(this);
- if (!signal) {
- throw new Error("missing signal; should not happen");
- }
- signal();
- }
- /**
- * Returns a new [[FetchRequest]] that represents the redirection
- * to %%location%%.
- */
- redirect(location) {
- // Redirection; for now we only support absolute locations
- const current = this.url.split(":")[0].toLowerCase();
- const target = location.split(":")[0].toLowerCase();
- // Don't allow redirecting:
- // - non-GET requests
- // - downgrading the security (e.g. https => http)
- // - to non-HTTP (or non-HTTPS) protocols [this could be relaxed?]
- assert(this.method === "GET" && (current !== "https" || target !== "http") && location.match(/^https?:/), `unsupported redirect`, "UNSUPPORTED_OPERATION", {
- operation: `redirect(${this.method} ${JSON.stringify(this.url)} => ${JSON.stringify(location)})`
- });
- // Create a copy of this request, with a new URL
- const req = new FetchRequest(location);
- req.method = "GET";
- req.allowGzip = this.allowGzip;
- req.timeout = this.timeout;
- req.#headers = Object.assign({}, this.#headers);
- if (this.#body) {
- req.#body = new Uint8Array(this.#body);
- }
- req.#bodyType = this.#bodyType;
- // Do not forward credentials unless on the same domain; only absolute
- //req.allowInsecure = false;
- // paths are currently supported; may want a way to specify to forward?
- //setStore(req.#props, "creds", getStore(this.#pros, "creds"));
- return req;
- }
- /**
- * Create a new copy of this request.
- */
- clone() {
- const clone = new FetchRequest(this.url);
- // Preserve "default method" (i.e. null)
- clone.#method = this.#method;
- // Preserve "default body" with type, copying the Uint8Array is present
- if (this.#body) {
- clone.#body = this.#body;
- }
- clone.#bodyType = this.#bodyType;
- // Preserve "default headers"
- clone.#headers = Object.assign({}, this.#headers);
- // Credentials is readonly, so we copy internally
- clone.#creds = this.#creds;
- if (this.allowGzip) {
- clone.allowGzip = true;
- }
- clone.timeout = this.timeout;
- if (this.allowInsecureAuthentication) {
- clone.allowInsecureAuthentication = true;
- }
- clone.#preflight = this.#preflight;
- clone.#process = this.#process;
- clone.#retry = this.#retry;
- clone.#throttle = Object.assign({}, this.#throttle);
- clone.#getUrlFunc = this.#getUrlFunc;
- return clone;
- }
- /**
- * Locks all static configuration for gateways and FetchGetUrlFunc
- * registration.
- */
- static lockConfig() {
- locked$5 = true;
- }
- /**
- * Get the current Gateway function for %%scheme%%.
- */
- static getGateway(scheme) {
- return Gateways[scheme.toLowerCase()] || null;
- }
- /**
- * Use the %%func%% when fetching URIs using %%scheme%%.
- *
- * This method affects all requests globally.
- *
- * If [[lockConfig]] has been called, no change is made and this
- * throws.
- */
- static registerGateway(scheme, func) {
- scheme = scheme.toLowerCase();
- if (scheme === "http" || scheme === "https") {
- throw new Error(`cannot intercept ${scheme}; use registerGetUrl`);
- }
- if (locked$5) {
- throw new Error("gateways locked");
- }
- Gateways[scheme] = func;
- }
- /**
- * Use %%getUrl%% when fetching URIs over HTTP and HTTPS requests.
- *
- * This method affects all requests globally.
- *
- * If [[lockConfig]] has been called, no change is made and this
- * throws.
- */
- static registerGetUrl(getUrl) {
- if (locked$5) {
- throw new Error("gateways locked");
- }
- defaultGetUrlFunc = getUrl;
- }
- /**
- * Creates a getUrl function that fetches content from HTTP and
- * HTTPS URLs.
- *
- * The available %%options%% are dependent on the platform
- * implementation of the default getUrl function.
- *
- * This is not generally something that is needed, but is useful
- * when trying to customize simple behaviour when fetching HTTP
- * content.
- */
- static createGetUrlFunc(options) {
- return createGetUrl();
- }
- /**
- * Creates a function that can "fetch" data URIs.
- *
- * Note that this is automatically done internally to support
- * data URIs, so it is not necessary to register it.
- *
- * This is not generally something that is needed, but may
- * be useful in a wrapper to perfom custom data URI functionality.
- */
- static createDataGateway() {
- return dataGatewayFunc;
- }
- /**
- * Creates a function that will fetch IPFS (unvalidated) from
- * a custom gateway baseUrl.
- *
- * The default IPFS gateway used internally is
- * ``"https:/\/gateway.ipfs.io/ipfs/"``.
- */
- static createIpfsGatewayFunc(baseUrl) {
- return getIpfsGatewayFunc(baseUrl);
- }
- }
- /**
- * The response for a FetchRequest.
- */
- class FetchResponse {
- #statusCode;
- #statusMessage;
- #headers;
- #body;
- #request;
- #error;
- toString() {
- return `<FetchResponse status=${this.statusCode} body=${this.#body ? hexlify(this.#body) : "null"}>`;
- }
- /**
- * The response status code.
- */
- get statusCode() { return this.#statusCode; }
- /**
- * The response status message.
- */
- get statusMessage() { return this.#statusMessage; }
- /**
- * The response headers. All keys are lower-case.
- */
- get headers() { return Object.assign({}, this.#headers); }
- /**
- * The response body, or ``null`` if there was no body.
- */
- get body() {
- return (this.#body == null) ? null : new Uint8Array(this.#body);
- }
- /**
- * The response body as a UTF-8 encoded string, or the empty
- * string (i.e. ``""``) if there was no body.
- *
- * An error is thrown if the body is invalid UTF-8 data.
- */
- get bodyText() {
- try {
- return (this.#body == null) ? "" : toUtf8String(this.#body);
- }
- catch (error) {
- assert(false, "response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
- operation: "bodyText", info: { response: this }
- });
- }
- }
- /**
- * The response body, decoded as JSON.
- *
- * An error is thrown if the body is invalid JSON-encoded data
- * or if there was no body.
- */
- get bodyJson() {
- try {
- return JSON.parse(this.bodyText);
- }
- catch (error) {
- assert(false, "response body is not valid JSON", "UNSUPPORTED_OPERATION", {
- operation: "bodyJson", info: { response: this }
- });
- }
- }
- [Symbol.iterator]() {
- const headers = this.headers;
- const keys = Object.keys(headers);
- let index = 0;
- return {
- next: () => {
- if (index < keys.length) {
- const key = keys[index++];
- return {
- value: [key, headers[key]], done: false
- };
- }
- return { value: undefined, done: true };
- }
- };
- }
- constructor(statusCode, statusMessage, headers, body, request) {
- this.#statusCode = statusCode;
- this.#statusMessage = statusMessage;
- this.#headers = Object.keys(headers).reduce((accum, k) => {
- accum[k.toLowerCase()] = String(headers[k]);
- return accum;
- }, {});
- this.#body = ((body == null) ? null : new Uint8Array(body));
- this.#request = (request || null);
- this.#error = { message: "" };
- }
- /**
- * Return a Response with matching headers and body, but with
- * an error status code (i.e. 599) and %%message%% with an
- * optional %%error%%.
- */
- makeServerError(message, error) {
- let statusMessage;
- if (!message) {
- message = `${this.statusCode} ${this.statusMessage}`;
- statusMessage = `CLIENT ESCALATED SERVER ERROR (${message})`;
- }
- else {
- statusMessage = `CLIENT ESCALATED SERVER ERROR (${this.statusCode} ${this.statusMessage}; ${message})`;
- }
- const response = new FetchResponse(599, statusMessage, this.headers, this.body, this.#request || undefined);
- response.#error = { message, error };
- return response;
- }
- /**
- * If called within a [request.processFunc](FetchRequest-processFunc)
- * call, causes the request to retry as if throttled for %%stall%%
- * milliseconds.
- */
- throwThrottleError(message, stall) {
- if (stall == null) {
- stall = -1;
- }
- else {
- assertArgument(Number.isInteger(stall) && stall >= 0, "invalid stall timeout", "stall", stall);
- }
- const error = new Error(message || "throttling requests");
- defineProperties(error, { stall, throttle: true });
- throw error;
- }
- /**
- * Get the header value for %%key%%, ignoring case.
- */
- getHeader(key) {
- return this.headers[key.toLowerCase()];
- }
- /**
- * Returns true if the response has a body.
- */
- hasBody() {
- return (this.#body != null);
- }
- /**
- * The request made for this response.
- */
- get request() { return this.#request; }
- /**
- * Returns true if this response was a success statusCode.
- */
- ok() {
- return (this.#error.message === "" && this.statusCode >= 200 && this.statusCode < 300);
- }
- /**
- * Throws a ``SERVER_ERROR`` if this response is not ok.
- */
- assertOk() {
- if (this.ok()) {
- return;
- }
- let { message, error } = this.#error;
- if (message === "") {
- message = `server response ${this.statusCode} ${this.statusMessage}`;
- }
- let requestUrl = null;
- if (this.request) {
- requestUrl = this.request.url;
- }
- let responseBody = null;
- try {
- if (this.#body) {
- responseBody = toUtf8String(this.#body);
- }
- }
- catch (e) { }
- assert(false, message, "SERVER_ERROR", {
- request: (this.request || "unknown request"), response: this, error,
- info: {
- requestUrl, responseBody,
- responseStatus: `${this.statusCode} ${this.statusMessage}`
- }
- });
- }
- }
- function getTime$2() { return (new Date()).getTime(); }
- function unpercent(value) {
- return toUtf8Bytes(value.replace(/%([0-9a-f][0-9a-f])/gi, (all, code) => {
- return String.fromCharCode(parseInt(code, 16));
- }));
- }
- function wait(delay) {
- return new Promise((resolve) => setTimeout(resolve, delay));
- }
- /**
- * The **FixedNumber** class permits using values with decimal places,
- * using fixed-pont math.
- *
- * Fixed-point math is still based on integers under-the-hood, but uses an
- * internal offset to store fractional components below, and each operation
- * corrects for this after each operation.
- *
- * @_section: api/utils/fixed-point-math:Fixed-Point Maths [about-fixed-point-math]
- */
- const BN_N1 = BigInt(-1);
- const BN_0$8 = BigInt(0);
- const BN_1$4 = BigInt(1);
- const BN_5 = BigInt(5);
- const _guard$5 = {};
- // Constant to pull zeros from for multipliers
- let Zeros$1 = "0000";
- while (Zeros$1.length < 80) {
- Zeros$1 += Zeros$1;
- }
- // Returns a string "1" followed by decimal "0"s
- function getTens(decimals) {
- let result = Zeros$1;
- while (result.length < decimals) {
- result += result;
- }
- return BigInt("1" + result.substring(0, decimals));
- }
- function checkValue(val, format, safeOp) {
- const width = BigInt(format.width);
- if (format.signed) {
- const limit = (BN_1$4 << (width - BN_1$4));
- assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
- operation: safeOp, fault: "overflow", value: val
- });
- if (val > BN_0$8) {
- val = fromTwos(mask(val, width), width);
- }
- else {
- val = -fromTwos(mask(-val, width), width);
- }
- }
- else {
- const limit = (BN_1$4 << width);
- assert(safeOp == null || (val >= 0 && val < limit), "overflow", "NUMERIC_FAULT", {
- operation: safeOp, fault: "overflow", value: val
- });
- val = (((val % limit) + limit) % limit) & (limit - BN_1$4);
- }
- return val;
- }
- function getFormat(value) {
- if (typeof (value) === "number") {
- value = `fixed128x${value}`;
- }
- let signed = true;
- let width = 128;
- let decimals = 18;
- if (typeof (value) === "string") {
- // Parse the format string
- if (value === "fixed") ;
- else if (value === "ufixed") {
- signed = false;
- }
- else {
- const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/);
- assertArgument(match, "invalid fixed format", "format", value);
- signed = (match[1] !== "u");
- width = parseInt(match[2]);
- decimals = parseInt(match[3]);
- }
- }
- else if (value) {
- // Extract the values from the object
- const v = value;
- const check = (key, type, defaultValue) => {
- if (v[key] == null) {
- return defaultValue;
- }
- assertArgument(typeof (v[key]) === type, "invalid fixed format (" + key + " not " + type + ")", "format." + key, v[key]);
- return v[key];
- };
- signed = check("signed", "boolean", signed);
- width = check("width", "number", width);
- decimals = check("decimals", "number", decimals);
- }
- assertArgument((width % 8) === 0, "invalid FixedNumber width (not byte aligned)", "format.width", width);
- assertArgument(decimals <= 80, "invalid FixedNumber decimals (too large)", "format.decimals", decimals);
- const name = (signed ? "" : "u") + "fixed" + String(width) + "x" + String(decimals);
- return { signed, width, decimals, name };
- }
- function toString(val, decimals) {
- let negative = "";
- if (val < BN_0$8) {
- negative = "-";
- val *= BN_N1;
- }
- let str = val.toString();
- // No decimal point for whole values
- if (decimals === 0) {
- return (negative + str);
- }
- // Pad out to the whole component (including a whole digit)
- while (str.length <= decimals) {
- str = Zeros$1 + str;
- }
- // Insert the decimal point
- const index = str.length - decimals;
- str = str.substring(0, index) + "." + str.substring(index);
- // Trim the whole component (leaving at least one 0)
- while (str[0] === "0" && str[1] !== ".") {
- str = str.substring(1);
- }
- // Trim the decimal component (leaving at least one 0)
- while (str[str.length - 1] === "0" && str[str.length - 2] !== ".") {
- str = str.substring(0, str.length - 1);
- }
- return (negative + str);
- }
- /**
- * A FixedNumber represents a value over its [[FixedFormat]]
- * arithmetic field.
- *
- * A FixedNumber can be used to perform math, losslessly, on
- * values which have decmial places.
- *
- * A FixedNumber has a fixed bit-width to store values in, and stores all
- * values internally by multiplying the value by 10 raised to the power of
- * %%decimals%%.
- *
- * If operations are performed that cause a value to grow too high (close to
- * positive infinity) or too low (close to negative infinity), the value
- * is said to //overflow//.
- *
- * For example, an 8-bit signed value, with 0 decimals may only be within
- * the range ``-128`` to ``127``; so ``-128 - 1`` will overflow and become
- * ``127``. Likewise, ``127 + 1`` will overflow and become ``-127``.
- *
- * Many operation have a normal and //unsafe// variant. The normal variant
- * will throw a [[NumericFaultError]] on any overflow, while the //unsafe//
- * variant will silently allow overflow, corrupting its value value.
- *
- * If operations are performed that cause a value to become too small
- * (close to zero), the value loses precison and is said to //underflow//.
- *
- * For example, an value with 1 decimal place may store a number as small
- * as ``0.1``, but the value of ``0.1 / 2`` is ``0.05``, which cannot fit
- * into 1 decimal place, so underflow occurs which means precision is lost
- * and the value becomes ``0``.
- *
- * Some operations have a normal and //signalling// variant. The normal
- * variant will silently ignore underflow, while the //signalling// variant
- * will thow a [[NumericFaultError]] on underflow.
- */
- class FixedNumber {
- /**
- * The specific fixed-point arithmetic field for this value.
- */
- format;
- #format;
- // The actual value (accounting for decimals)
- #val;
- // A base-10 value to multiple values by to maintain the magnitude
- #tens;
- /**
- * This is a property so console.log shows a human-meaningful value.
- *
- * @private
- */
- _value;
- // Use this when changing this file to get some typing info,
- // but then switch to any to mask the internal type
- //constructor(guard: any, value: bigint, format: _FixedFormat) {
- /**
- * @private
- */
- constructor(guard, value, format) {
- assertPrivate(guard, _guard$5, "FixedNumber");
- this.#val = value;
- this.#format = format;
- const _value = toString(value, format.decimals);
- defineProperties(this, { format: format.name, _value });
- this.#tens = getTens(format.decimals);
- }
- /**
- * If true, negative values are permitted, otherwise only
- * positive values and zero are allowed.
- */
- get signed() { return this.#format.signed; }
- /**
- * The number of bits available to store the value.
- */
- get width() { return this.#format.width; }
- /**
- * The number of decimal places in the fixed-point arithment field.
- */
- get decimals() { return this.#format.decimals; }
- /**
- * The value as an integer, based on the smallest unit the
- * [[decimals]] allow.
- */
- get value() { return this.#val; }
- #checkFormat(other) {
- assertArgument(this.format === other.format, "incompatible format; use fixedNumber.toFormat", "other", other);
- }
- #checkValue(val, safeOp) {
- /*
- const width = BigInt(this.width);
- if (this.signed) {
- const limit = (BN_1 << (width - BN_1));
- assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
- operation: <string>safeOp, fault: "overflow", value: val
- });
-
- if (val > BN_0) {
- val = fromTwos(mask(val, width), width);
- } else {
- val = -fromTwos(mask(-val, width), width);
- }
-
- } else {
- const masked = mask(val, width);
- assert(safeOp == null || (val >= 0 && val === masked), "overflow", "NUMERIC_FAULT", {
- operation: <string>safeOp, fault: "overflow", value: val
- });
- val = masked;
- }
- */
- val = checkValue(val, this.#format, safeOp);
- return new FixedNumber(_guard$5, val, this.#format);
- }
- #add(o, safeOp) {
- this.#checkFormat(o);
- return this.#checkValue(this.#val + o.#val, safeOp);
- }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% added
- * to %%other%%, ignoring overflow.
- */
- addUnsafe(other) { return this.#add(other); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% added
- * to %%other%%. A [[NumericFaultError]] is thrown if overflow
- * occurs.
- */
- add(other) { return this.#add(other, "add"); }
- #sub(o, safeOp) {
- this.#checkFormat(o);
- return this.#checkValue(this.#val - o.#val, safeOp);
- }
- /**
- * Returns a new [[FixedNumber]] with the result of %%other%% subtracted
- * from %%this%%, ignoring overflow.
- */
- subUnsafe(other) { return this.#sub(other); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%other%% subtracted
- * from %%this%%. A [[NumericFaultError]] is thrown if overflow
- * occurs.
- */
- sub(other) { return this.#sub(other, "sub"); }
- #mul(o, safeOp) {
- this.#checkFormat(o);
- return this.#checkValue((this.#val * o.#val) / this.#tens, safeOp);
- }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
- * by %%other%%, ignoring overflow and underflow (precision loss).
- */
- mulUnsafe(other) { return this.#mul(other); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
- * by %%other%%. A [[NumericFaultError]] is thrown if overflow
- * occurs.
- */
- mul(other) { return this.#mul(other, "mul"); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% multiplied
- * by %%other%%. A [[NumericFaultError]] is thrown if overflow
- * occurs or if underflow (precision loss) occurs.
- */
- mulSignal(other) {
- this.#checkFormat(other);
- const value = this.#val * other.#val;
- assert((value % this.#tens) === BN_0$8, "precision lost during signalling mul", "NUMERIC_FAULT", {
- operation: "mulSignal", fault: "underflow", value: this
- });
- return this.#checkValue(value / this.#tens, "mulSignal");
- }
- #div(o, safeOp) {
- assert(o.#val !== BN_0$8, "division by zero", "NUMERIC_FAULT", {
- operation: "div", fault: "divide-by-zero", value: this
- });
- this.#checkFormat(o);
- return this.#checkValue((this.#val * this.#tens) / o.#val, safeOp);
- }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% divided
- * by %%other%%, ignoring underflow (precision loss). A
- * [[NumericFaultError]] is thrown if overflow occurs.
- */
- divUnsafe(other) { return this.#div(other); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% divided
- * by %%other%%, ignoring underflow (precision loss). A
- * [[NumericFaultError]] is thrown if overflow occurs.
- */
- div(other) { return this.#div(other, "div"); }
- /**
- * Returns a new [[FixedNumber]] with the result of %%this%% divided
- * by %%other%%. A [[NumericFaultError]] is thrown if underflow
- * (precision loss) occurs.
- */
- divSignal(other) {
- assert(other.#val !== BN_0$8, "division by zero", "NUMERIC_FAULT", {
- operation: "div", fault: "divide-by-zero", value: this
- });
- this.#checkFormat(other);
- const value = (this.#val * this.#tens);
- assert((value % other.#val) === BN_0$8, "precision lost during signalling div", "NUMERIC_FAULT", {
- operation: "divSignal", fault: "underflow", value: this
- });
- return this.#checkValue(value / other.#val, "divSignal");
- }
- /**
- * Returns a comparison result between %%this%% and %%other%%.
- *
- * This is suitable for use in sorting, where ``-1`` implies %%this%%
- * is smaller, ``1`` implies %%this%% is larger and ``0`` implies
- * both are equal.
- */
- cmp(other) {
- let a = this.value, b = other.value;
- // Coerce a and b to the same magnitude
- const delta = this.decimals - other.decimals;
- if (delta > 0) {
- b *= getTens(delta);
- }
- else if (delta < 0) {
- a *= getTens(-delta);
- }
- // Comnpare
- if (a < b) {
- return -1;
- }
- if (a > b) {
- return 1;
- }
- return 0;
- }
- /**
- * Returns true if %%other%% is equal to %%this%%.
- */
- eq(other) { return this.cmp(other) === 0; }
- /**
- * Returns true if %%other%% is less than to %%this%%.
- */
- lt(other) { return this.cmp(other) < 0; }
- /**
- * Returns true if %%other%% is less than or equal to %%this%%.
- */
- lte(other) { return this.cmp(other) <= 0; }
- /**
- * Returns true if %%other%% is greater than to %%this%%.
- */
- gt(other) { return this.cmp(other) > 0; }
- /**
- * Returns true if %%other%% is greater than or equal to %%this%%.
- */
- gte(other) { return this.cmp(other) >= 0; }
- /**
- * Returns a new [[FixedNumber]] which is the largest **integer**
- * that is less than or equal to %%this%%.
- *
- * The decimal component of the result will always be ``0``.
- */
- floor() {
- let val = this.#val;
- if (this.#val < BN_0$8) {
- val -= this.#tens - BN_1$4;
- }
- val = (this.#val / this.#tens) * this.#tens;
- return this.#checkValue(val, "floor");
- }
- /**
- * Returns a new [[FixedNumber]] which is the smallest **integer**
- * that is greater than or equal to %%this%%.
- *
- * The decimal component of the result will always be ``0``.
- */
- ceiling() {
- let val = this.#val;
- if (this.#val > BN_0$8) {
- val += this.#tens - BN_1$4;
- }
- val = (this.#val / this.#tens) * this.#tens;
- return this.#checkValue(val, "ceiling");
- }
- /**
- * Returns a new [[FixedNumber]] with the decimal component
- * rounded up on ties at %%decimals%% places.
- */
- round(decimals) {
- if (decimals == null) {
- decimals = 0;
- }
- // Not enough precision to not already be rounded
- if (decimals >= this.decimals) {
- return this;
- }
- const delta = this.decimals - decimals;
- const bump = BN_5 * getTens(delta - 1);
- let value = this.value + bump;
- const tens = getTens(delta);
- value = (value / tens) * tens;
- checkValue(value, this.#format, "round");
- return new FixedNumber(_guard$5, value, this.#format);
- }
- /**
- * Returns true if %%this%% is equal to ``0``.
- */
- isZero() { return (this.#val === BN_0$8); }
- /**
- * Returns true if %%this%% is less than ``0``.
- */
- isNegative() { return (this.#val < BN_0$8); }
- /**
- * Returns the string representation of %%this%%.
- */
- toString() { return this._value; }
- /**
- * Returns a float approximation.
- *
- * Due to IEEE 754 precission (or lack thereof), this function
- * can only return an approximation and most values will contain
- * rounding errors.
- */
- toUnsafeFloat() { return parseFloat(this.toString()); }
- /**
- * Return a new [[FixedNumber]] with the same value but has had
- * its field set to %%format%%.
- *
- * This will throw if the value cannot fit into %%format%%.
- */
- toFormat(format) {
- return FixedNumber.fromString(this.toString(), format);
- }
- /**
- * Creates a new [[FixedNumber]] for %%value%% divided by
- * %%decimal%% places with %%format%%.
- *
- * This will throw a [[NumericFaultError]] if %%value%% (once adjusted
- * for %%decimals%%) cannot fit in %%format%%, either due to overflow
- * or underflow (precision loss).
- */
- static fromValue(_value, _decimals, _format) {
- const decimals = (_decimals == null) ? 0 : getNumber(_decimals);
- const format = getFormat(_format);
- let value = getBigInt(_value, "value");
- const delta = decimals - format.decimals;
- if (delta > 0) {
- const tens = getTens(delta);
- assert((value % tens) === BN_0$8, "value loses precision for format", "NUMERIC_FAULT", {
- operation: "fromValue", fault: "underflow", value: _value
- });
- value /= tens;
- }
- else if (delta < 0) {
- value *= getTens(-delta);
- }
- checkValue(value, format, "fromValue");
- return new FixedNumber(_guard$5, value, format);
- }
- /**
- * Creates a new [[FixedNumber]] for %%value%% with %%format%%.
- *
- * This will throw a [[NumericFaultError]] if %%value%% cannot fit
- * in %%format%%, either due to overflow or underflow (precision loss).
- */
- static fromString(_value, _format) {
- const match = _value.match(/^(-?)([0-9]*)\.?([0-9]*)$/);
- assertArgument(match && (match[2].length + match[3].length) > 0, "invalid FixedNumber string value", "value", _value);
- const format = getFormat(_format);
- let whole = (match[2] || "0"), decimal = (match[3] || "");
- // Pad out the decimals
- while (decimal.length < format.decimals) {
- decimal += Zeros$1;
- }
- // Check precision is safe
- assert(decimal.substring(format.decimals).match(/^0*$/), "too many decimals for format", "NUMERIC_FAULT", {
- operation: "fromString", fault: "underflow", value: _value
- });
- // Remove extra padding
- decimal = decimal.substring(0, format.decimals);
- const value = BigInt(match[1] + whole + decimal);
- checkValue(value, format, "fromString");
- return new FixedNumber(_guard$5, value, format);
- }
- /**
- * Creates a new [[FixedNumber]] with the big-endian representation
- * %%value%% with %%format%%.
- *
- * This will throw a [[NumericFaultError]] if %%value%% cannot fit
- * in %%format%% due to overflow.
- */
- static fromBytes(_value, _format) {
- let value = toBigInt(getBytes(_value, "value"));
- const format = getFormat(_format);
- if (format.signed) {
- value = fromTwos(value, format.width);
- }
- checkValue(value, format, "fromBytes");
- return new FixedNumber(_guard$5, value, format);
- }
- }
- //const f1 = FixedNumber.fromString("12.56", "fixed16x2");
- //const f2 = FixedNumber.fromString("0.3", "fixed16x2");
- //console.log(f1.divSignal(f2));
- //const BUMP = FixedNumber.from("0.5");
- //See: https://github.com/ethereum/wiki/wiki/RLP
- function hexlifyByte(value) {
- let result = value.toString(16);
- while (result.length < 2) {
- result = "0" + result;
- }
- return "0x" + result;
- }
- function unarrayifyInteger(data, offset, length) {
- let result = 0;
- for (let i = 0; i < length; i++) {
- result = (result * 256) + data[offset + i];
- }
- return result;
- }
- function _decodeChildren(data, offset, childOffset, length) {
- const result = [];
- while (childOffset < offset + 1 + length) {
- const decoded = _decode(data, childOffset);
- result.push(decoded.result);
- childOffset += decoded.consumed;
- assert(childOffset <= offset + 1 + length, "child data too short", "BUFFER_OVERRUN", {
- buffer: data, length, offset
- });
- }
- return { consumed: (1 + length), result: result };
- }
- // returns { consumed: number, result: Object }
- function _decode(data, offset) {
- assert(data.length !== 0, "data too short", "BUFFER_OVERRUN", {
- buffer: data, length: 0, offset: 1
- });
- const checkOffset = (offset) => {
- assert(offset <= data.length, "data short segment too short", "BUFFER_OVERRUN", {
- buffer: data, length: data.length, offset
- });
- };
- // Array with extra length prefix
- if (data[offset] >= 0xf8) {
- const lengthLength = data[offset] - 0xf7;
- checkOffset(offset + 1 + lengthLength);
- const length = unarrayifyInteger(data, offset + 1, lengthLength);
- checkOffset(offset + 1 + lengthLength + length);
- return _decodeChildren(data, offset, offset + 1 + lengthLength, lengthLength + length);
- }
- else if (data[offset] >= 0xc0) {
- const length = data[offset] - 0xc0;
- checkOffset(offset + 1 + length);
- return _decodeChildren(data, offset, offset + 1, length);
- }
- else if (data[offset] >= 0xb8) {
- const lengthLength = data[offset] - 0xb7;
- checkOffset(offset + 1 + lengthLength);
- const length = unarrayifyInteger(data, offset + 1, lengthLength);
- checkOffset(offset + 1 + lengthLength + length);
- const result = hexlify(data.slice(offset + 1 + lengthLength, offset + 1 + lengthLength + length));
- return { consumed: (1 + lengthLength + length), result: result };
- }
- else if (data[offset] >= 0x80) {
- const length = data[offset] - 0x80;
- checkOffset(offset + 1 + length);
- const result = hexlify(data.slice(offset + 1, offset + 1 + length));
- return { consumed: (1 + length), result: result };
- }
- return { consumed: 1, result: hexlifyByte(data[offset]) };
- }
- /**
- * Decodes %%data%% into the structured data it represents.
- */
- function decodeRlp(_data) {
- const data = getBytes(_data, "data");
- const decoded = _decode(data, 0);
- assertArgument(decoded.consumed === data.length, "unexpected junk after rlp payload", "data", _data);
- return decoded.result;
- }
- //See: https://github.com/ethereum/wiki/wiki/RLP
- function arrayifyInteger(value) {
- const result = [];
- while (value) {
- result.unshift(value & 0xff);
- value >>= 8;
- }
- return result;
- }
- function _encode(object) {
- if (Array.isArray(object)) {
- let payload = [];
- object.forEach(function (child) {
- payload = payload.concat(_encode(child));
- });
- if (payload.length <= 55) {
- payload.unshift(0xc0 + payload.length);
- return payload;
- }
- const length = arrayifyInteger(payload.length);
- length.unshift(0xf7 + length.length);
- return length.concat(payload);
- }
- const data = Array.prototype.slice.call(getBytes(object, "object"));
- if (data.length === 1 && data[0] <= 0x7f) {
- return data;
- }
- else if (data.length <= 55) {
- data.unshift(0x80 + data.length);
- return data;
- }
- const length = arrayifyInteger(data.length);
- length.unshift(0xb7 + length.length);
- return length.concat(data);
- }
- const nibbles = "0123456789abcdef";
- /**
- * Encodes %%object%% as an RLP-encoded [[DataHexString]].
- */
- function encodeRlp(object) {
- let result = "0x";
- for (const v of _encode(object)) {
- result += nibbles[v >> 4];
- result += nibbles[v & 0xf];
- }
- return result;
- }
- /**
- * Most interactions with Ethereum requires integer values, which use
- * the smallest magnitude unit.
- *
- * For example, imagine dealing with dollars and cents. Since dollars
- * are divisible, non-integer values are possible, such as ``$10.77``.
- * By using the smallest indivisible unit (i.e. cents), the value can
- * be kept as the integer ``1077``.
- *
- * When receiving decimal input from the user (as a decimal string),
- * the value should be converted to an integer and when showing a user
- * a value, the integer value should be converted to a decimal string.
- *
- * This creates a clear distinction, between values to be used by code
- * (integers) and values used for display logic to users (decimals).
- *
- * The native unit in Ethereum, //ether// is divisible to 18 decimal places,
- * where each individual unit is called a //wei//.
- *
- * @_subsection api/utils:Unit Conversion [about-units]
- */
- const names = [
- "wei",
- "kwei",
- "mwei",
- "gwei",
- "szabo",
- "finney",
- "ether",
- ];
- /**
- * Converts %%value%% into a //decimal string//, assuming %%unit%% decimal
- * places. The %%unit%% may be the number of decimal places or the name of
- * a unit (e.g. ``"gwei"`` for 9 decimal places).
- *
- */
- function formatUnits(value, unit) {
- let decimals = 18;
- if (typeof (unit) === "string") {
- const index = names.indexOf(unit);
- assertArgument(index >= 0, "invalid unit", "unit", unit);
- decimals = 3 * index;
- }
- else if (unit != null) {
- decimals = getNumber(unit, "unit");
- }
- return FixedNumber.fromValue(value, decimals, { decimals, width: 512 }).toString();
- }
- /**
- * Converts the //decimal string// %%value%% to a BigInt, assuming
- * %%unit%% decimal places. The %%unit%% may the number of decimal places
- * or the name of a unit (e.g. ``"gwei"`` for 9 decimal places).
- */
- function parseUnits$1(value, unit) {
- assertArgument(typeof (value) === "string", "value must be a string", "value", value);
- let decimals = 18;
- if (typeof (unit) === "string") {
- const index = names.indexOf(unit);
- assertArgument(index >= 0, "invalid unit", "unit", unit);
- decimals = 3 * index;
- }
- else if (unit != null) {
- decimals = getNumber(unit, "unit");
- }
- return FixedNumber.fromString(value, { decimals, width: 512 }).value;
- }
- /**
- * Converts %%value%% into a //decimal string// using 18 decimal places.
- */
- function formatEther(wei) {
- return formatUnits(wei, 18);
- }
- /**
- * Converts the //decimal string// %%ether%% to a BigInt, using 18
- * decimal places.
- */
- function parseEther(ether) {
- return parseUnits$1(ether, 18);
- }
- /**
- * Explain UUID and link to RFC here.
- *
- * @_subsection: api/utils:UUID [about-uuid]
- */
- /**
- * Returns the version 4 [[link-uuid]] for the %%randomBytes%%.
- *
- * @see: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
- */
- function uuidV4(randomBytes) {
- const bytes = getBytes(randomBytes, "randomBytes");
- // Section: 4.1.3:
- // - time_hi_and_version[12:16] = 0b0100
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
- // Section 4.4
- // - clock_seq_hi_and_reserved[6] = 0b0
- // - clock_seq_hi_and_reserved[7] = 0b1
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
- const value = hexlify(bytes);
- return [
- value.substring(2, 10),
- value.substring(10, 14),
- value.substring(14, 18),
- value.substring(18, 22),
- value.substring(22, 34),
- ].join("-");
- }
- /**
- * @_ignore:
- */
- const WordSize = 32;
- const Padding = new Uint8Array(WordSize);
- // Properties used to immediate pass through to the underlying object
- // - `then` is used to detect if an object is a Promise for await
- const passProperties$1 = ["then"];
- const _guard$4 = {};
- const resultNames = new WeakMap();
- function getNames(result) {
- return resultNames.get(result);
- }
- function setNames(result, names) {
- resultNames.set(result, names);
- }
- function throwError(name, error) {
- const wrapped = new Error(`deferred error during ABI decoding triggered accessing ${name}`);
- wrapped.error = error;
- throw wrapped;
- }
- function toObject(names, items, deep) {
- if (names.indexOf(null) >= 0) {
- return items.map((item, index) => {
- if (item instanceof Result) {
- return toObject(getNames(item), item, deep);
- }
- return item;
- });
- }
- return names.reduce((accum, name, index) => {
- let item = items.getValue(name);
- if (!(name in accum)) {
- if (deep && item instanceof Result) {
- item = toObject(getNames(item), item, deep);
- }
- accum[name] = item;
- }
- return accum;
- }, {});
- }
- /**
- * A [[Result]] is a sub-class of Array, which allows accessing any
- * of its values either positionally by its index or, if keys are
- * provided by its name.
- *
- * @_docloc: api/abi
- */
- class Result extends Array {
- // No longer used; but cannot be removed as it will remove the
- // #private field from the .d.ts which may break backwards
- // compatibility
- #names;
- /**
- * @private
- */
- constructor(...args) {
- // To properly sub-class Array so the other built-in
- // functions work, the constructor has to behave fairly
- // well. So, in the event we are created via fromItems()
- // we build the read-only Result object we want, but on
- // any other input, we use the default constructor
- // constructor(guard: any, items: Array<any>, keys?: Array<null | string>);
- const guard = args[0];
- let items = args[1];
- let names = (args[2] || []).slice();
- let wrap = true;
- if (guard !== _guard$4) {
- items = args;
- names = [];
- wrap = false;
- }
- // Can't just pass in ...items since an array of length 1
- // is a special case in the super.
- super(items.length);
- items.forEach((item, index) => { this[index] = item; });
- // Find all unique keys
- const nameCounts = names.reduce((accum, name) => {
- if (typeof (name) === "string") {
- accum.set(name, (accum.get(name) || 0) + 1);
- }
- return accum;
- }, (new Map()));
- // Remove any key thats not unique
- setNames(this, Object.freeze(items.map((item, index) => {
- const name = names[index];
- if (name != null && nameCounts.get(name) === 1) {
- return name;
- }
- return null;
- })));
- // Dummy operations to prevent TypeScript from complaining
- this.#names = [];
- if (this.#names == null) {
- void (this.#names);
- }
- if (!wrap) {
- return;
- }
- // A wrapped Result is immutable
- Object.freeze(this);
- // Proxy indices and names so we can trap deferred errors
- const proxy = new Proxy(this, {
- get: (target, prop, receiver) => {
- if (typeof (prop) === "string") {
- // Index accessor
- if (prop.match(/^[0-9]+$/)) {
- const index = getNumber(prop, "%index");
- if (index < 0 || index >= this.length) {
- throw new RangeError("out of result range");
- }
- const item = target[index];
- if (item instanceof Error) {
- throwError(`index ${index}`, item);
- }
- return item;
- }
- // Pass important checks (like `then` for Promise) through
- if (passProperties$1.indexOf(prop) >= 0) {
- return Reflect.get(target, prop, receiver);
- }
- const value = target[prop];
- if (value instanceof Function) {
- // Make sure functions work with private variables
- // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#no_private_property_forwarding
- return function (...args) {
- return value.apply((this === receiver) ? target : this, args);
- };
- }
- else if (!(prop in target)) {
- // Possible name accessor
- return target.getValue.apply((this === receiver) ? target : this, [prop]);
- }
- }
- return Reflect.get(target, prop, receiver);
- }
- });
- setNames(proxy, getNames(this));
- return proxy;
- }
- /**
- * Returns the Result as a normal Array. If %%deep%%, any children
- * which are Result objects are also converted to a normal Array.
- *
- * This will throw if there are any outstanding deferred
- * errors.
- */
- toArray(deep) {
- const result = [];
- this.forEach((item, index) => {
- if (item instanceof Error) {
- throwError(`index ${index}`, item);
- }
- if (deep && item instanceof Result) {
- item = item.toArray(deep);
- }
- result.push(item);
- });
- return result;
- }
- /**
- * Returns the Result as an Object with each name-value pair. If
- * %%deep%%, any children which are Result objects are also
- * converted to an Object.
- *
- * This will throw if any value is unnamed, or if there are
- * any outstanding deferred errors.
- */
- toObject(deep) {
- const names = getNames(this);
- return names.reduce((accum, name, index) => {
- assert(name != null, `value at index ${index} unnamed`, "UNSUPPORTED_OPERATION", {
- operation: "toObject()"
- });
- return toObject(names, this, deep);
- }, {});
- }
- /**
- * @_ignore
- */
- slice(start, end) {
- if (start == null) {
- start = 0;
- }
- if (start < 0) {
- start += this.length;
- if (start < 0) {
- start = 0;
- }
- }
- if (end == null) {
- end = this.length;
- }
- if (end < 0) {
- end += this.length;
- if (end < 0) {
- end = 0;
- }
- }
- if (end > this.length) {
- end = this.length;
- }
- const _names = getNames(this);
- const result = [], names = [];
- for (let i = start; i < end; i++) {
- result.push(this[i]);
- names.push(_names[i]);
- }
- return new Result(_guard$4, result, names);
- }
- /**
- * @_ignore
- */
- filter(callback, thisArg) {
- const _names = getNames(this);
- const result = [], names = [];
- for (let i = 0; i < this.length; i++) {
- const item = this[i];
- if (item instanceof Error) {
- throwError(`index ${i}`, item);
- }
- if (callback.call(thisArg, item, i, this)) {
- result.push(item);
- names.push(_names[i]);
- }
- }
- return new Result(_guard$4, result, names);
- }
- /**
- * @_ignore
- */
- map(callback, thisArg) {
- const result = [];
- for (let i = 0; i < this.length; i++) {
- const item = this[i];
- if (item instanceof Error) {
- throwError(`index ${i}`, item);
- }
- result.push(callback.call(thisArg, item, i, this));
- }
- return result;
- }
- /**
- * Returns the value for %%name%%.
- *
- * Since it is possible to have a key whose name conflicts with
- * a method on a [[Result]] or its superclass Array, or any
- * JavaScript keyword, this ensures all named values are still
- * accessible by name.
- */
- getValue(name) {
- const index = getNames(this).indexOf(name);
- if (index === -1) {
- return undefined;
- }
- const value = this[index];
- if (value instanceof Error) {
- throwError(`property ${JSON.stringify(name)}`, value.error);
- }
- return value;
- }
- /**
- * Creates a new [[Result]] for %%items%% with each entry
- * also accessible by its corresponding name in %%keys%%.
- */
- static fromItems(items, keys) {
- return new Result(_guard$4, items, keys);
- }
- }
- /**
- * Returns all errors found in a [[Result]].
- *
- * Since certain errors encountered when creating a [[Result]] do
- * not impact the ability to continue parsing data, they are
- * deferred until they are actually accessed. Hence a faulty string
- * in an Event that is never used does not impact the program flow.
- *
- * However, sometimes it may be useful to access, identify or
- * validate correctness of a [[Result]].
- *
- * @_docloc api/abi
- */
- function checkResultErrors(result) {
- // Find the first error (if any)
- const errors = [];
- const checkErrors = function (path, object) {
- if (!Array.isArray(object)) {
- return;
- }
- for (let key in object) {
- const childPath = path.slice();
- childPath.push(key);
- try {
- checkErrors(childPath, object[key]);
- }
- catch (error) {
- errors.push({ path: childPath, error: error });
- }
- }
- };
- checkErrors([], result);
- return errors;
- }
- function getValue$1(value) {
- let bytes = toBeArray(value);
- assert(bytes.length <= WordSize, "value out-of-bounds", "BUFFER_OVERRUN", { buffer: bytes, length: WordSize, offset: bytes.length });
- if (bytes.length !== WordSize) {
- bytes = getBytesCopy(concat([Padding.slice(bytes.length % WordSize), bytes]));
- }
- return bytes;
- }
- /**
- * @_ignore
- */
- class Coder {
- // The coder name:
- // - address, uint256, tuple, array, etc.
- name;
- // The fully expanded type, including composite types:
- // - address, uint256, tuple(address,bytes), uint256[3][4][], etc.
- type;
- // The localName bound in the signature, in this example it is "baz":
- // - tuple(address foo, uint bar) baz
- localName;
- // Whether this type is dynamic:
- // - Dynamic: bytes, string, address[], tuple(boolean[]), etc.
- // - Not Dynamic: address, uint256, boolean[3], tuple(address, uint8)
- dynamic;
- constructor(name, type, localName, dynamic) {
- defineProperties(this, { name, type, localName, dynamic }, {
- name: "string", type: "string", localName: "string", dynamic: "boolean"
- });
- }
- _throwError(message, value) {
- assertArgument(false, message, this.localName, value);
- }
- }
- /**
- * @_ignore
- */
- class Writer {
- // An array of WordSize lengthed objects to concatenation
- #data;
- #dataLength;
- constructor() {
- this.#data = [];
- this.#dataLength = 0;
- }
- get data() {
- return concat(this.#data);
- }
- get length() { return this.#dataLength; }
- #writeData(data) {
- this.#data.push(data);
- this.#dataLength += data.length;
- return data.length;
- }
- appendWriter(writer) {
- return this.#writeData(getBytesCopy(writer.data));
- }
- // Arrayish item; pad on the right to *nearest* WordSize
- writeBytes(value) {
- let bytes = getBytesCopy(value);
- const paddingOffset = bytes.length % WordSize;
- if (paddingOffset) {
- bytes = getBytesCopy(concat([bytes, Padding.slice(paddingOffset)]));
- }
- return this.#writeData(bytes);
- }
- // Numeric item; pad on the left *to* WordSize
- writeValue(value) {
- return this.#writeData(getValue$1(value));
- }
- // Inserts a numeric place-holder, returning a callback that can
- // be used to asjust the value later
- writeUpdatableValue() {
- const offset = this.#data.length;
- this.#data.push(Padding);
- this.#dataLength += WordSize;
- return (value) => {
- this.#data[offset] = getValue$1(value);
- };
- }
- }
- /**
- * @_ignore
- */
- class Reader {
- // Allows incomplete unpadded data to be read; otherwise an error
- // is raised if attempting to overrun the buffer. This is required
- // to deal with an old Solidity bug, in which event data for
- // external (not public thoguh) was tightly packed.
- allowLoose;
- #data;
- #offset;
- #bytesRead;
- #parent;
- #maxInflation;
- constructor(data, allowLoose, maxInflation) {
- defineProperties(this, { allowLoose: !!allowLoose });
- this.#data = getBytesCopy(data);
- this.#bytesRead = 0;
- this.#parent = null;
- this.#maxInflation = (maxInflation != null) ? maxInflation : 1024;
- this.#offset = 0;
- }
- get data() { return hexlify(this.#data); }
- get dataLength() { return this.#data.length; }
- get consumed() { return this.#offset; }
- get bytes() { return new Uint8Array(this.#data); }
- #incrementBytesRead(count) {
- if (this.#parent) {
- return this.#parent.#incrementBytesRead(count);
- }
- this.#bytesRead += count;
- // Check for excessive inflation (see: #4537)
- assert(this.#maxInflation < 1 || this.#bytesRead <= this.#maxInflation * this.dataLength, `compressed ABI data exceeds inflation ratio of ${this.#maxInflation} ( see: https:/\/github.com/ethers-io/ethers.js/issues/4537 )`, "BUFFER_OVERRUN", {
- buffer: getBytesCopy(this.#data), offset: this.#offset,
- length: count, info: {
- bytesRead: this.#bytesRead,
- dataLength: this.dataLength
- }
- });
- }
- #peekBytes(offset, length, loose) {
- let alignedLength = Math.ceil(length / WordSize) * WordSize;
- if (this.#offset + alignedLength > this.#data.length) {
- if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {
- alignedLength = length;
- }
- else {
- assert(false, "data out-of-bounds", "BUFFER_OVERRUN", {
- buffer: getBytesCopy(this.#data),
- length: this.#data.length,
- offset: this.#offset + alignedLength
- });
- }
- }
- return this.#data.slice(this.#offset, this.#offset + alignedLength);
- }
- // Create a sub-reader with the same underlying data, but offset
- subReader(offset) {
- const reader = new Reader(this.#data.slice(this.#offset + offset), this.allowLoose, this.#maxInflation);
- reader.#parent = this;
- return reader;
- }
- // Read bytes
- readBytes(length, loose) {
- let bytes = this.#peekBytes(0, length, !!loose);
- this.#incrementBytesRead(length);
- this.#offset += bytes.length;
- // @TODO: Make sure the length..end bytes are all 0?
- return bytes.slice(0, length);
- }
- // Read a numeric values
- readValue() {
- return toBigInt(this.readBytes(WordSize));
- }
- readIndex() {
- return toNumber(this.readBytes(WordSize));
- }
- }
- function number(n) {
- if (!Number.isSafeInteger(n) || n < 0)
- throw new Error(`Wrong positive integer: ${n}`);
- }
- function bytes(b, ...lengths) {
- if (!(b instanceof Uint8Array))
- throw new Error('Expected Uint8Array');
- if (lengths.length > 0 && !lengths.includes(b.length))
- throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
- }
- function hash(hash) {
- if (typeof hash !== 'function' || typeof hash.create !== 'function')
- throw new Error('Hash should be wrapped by utils.wrapConstructor');
- number(hash.outputLen);
- number(hash.blockLen);
- }
- function exists(instance, checkFinished = true) {
- if (instance.destroyed)
- throw new Error('Hash instance has been destroyed');
- if (checkFinished && instance.finished)
- throw new Error('Hash#digest() has already been called');
- }
- function output(out, instance) {
- bytes(out);
- const min = instance.outputLen;
- if (out.length < min) {
- throw new Error(`digestInto() expects output buffer of length at least ${min}`);
- }
- }
- const crypto$1 = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
- /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
- // node.js versions earlier than v19 don't declare it in global scope.
- // For node.js, package.json#exports field mapping rewrites import
- // from `crypto` to `cryptoNode`, which imports native module.
- // Makes the utils un-importable in browsers without a bundler.
- // Once node.js 18 is deprecated, we can just drop the import.
- const u8a$1 = (a) => a instanceof Uint8Array;
- const u32 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
- // Cast array to view
- const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
- // The rotate right (circular right shift) operation for uint32
- const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
- // big-endian hardware is rare. Just in case someone still decides to run hashes:
- // early-throw an error because we don't support BE yet.
- const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
- if (!isLE)
- throw new Error('Non little-endian hardware is not supported');
- // There is no setImmediate in browser and setTimeout is slow.
- // call of async fn will return Promise, which will be fullfiled only on
- // next scheduler queue processing step and this is exactly what we need.
- const nextTick = async () => { };
- // Returns control to thread each 'tick' ms to avoid blocking
- async function asyncLoop(iters, tick, cb) {
- let ts = Date.now();
- for (let i = 0; i < iters; i++) {
- cb(i);
- // Date.now() is not monotonic, so in case if clock goes backwards we return return control too
- const diff = Date.now() - ts;
- if (diff >= 0 && diff < tick)
- continue;
- await nextTick();
- ts += diff;
- }
- }
- /**
- * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
- */
- function utf8ToBytes$1(str) {
- if (typeof str !== 'string')
- throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
- return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
- }
- /**
- * Normalizes (non-hex) string or Uint8Array to Uint8Array.
- * Warning: when Uint8Array is passed, it would NOT get copied.
- * Keep in mind for future mutable operations.
- */
- function toBytes(data) {
- if (typeof data === 'string')
- data = utf8ToBytes$1(data);
- if (!u8a$1(data))
- throw new Error(`expected Uint8Array, got ${typeof data}`);
- return data;
- }
- /**
- * Copies several Uint8Arrays into one.
- */
- function concatBytes$1(...arrays) {
- const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0));
- let pad = 0; // walk through each item, ensure they have proper type
- arrays.forEach((a) => {
- if (!u8a$1(a))
- throw new Error('Uint8Array expected');
- r.set(a, pad);
- pad += a.length;
- });
- return r;
- }
- // For runtime check if class implements interface
- class Hash {
- // Safe version that clones internal state
- clone() {
- return this._cloneInto();
- }
- }
- const toStr = {}.toString;
- function checkOpts(defaults, opts) {
- if (opts !== undefined && toStr.call(opts) !== '[object Object]')
- throw new Error('Options should be object or undefined');
- const merged = Object.assign(defaults, opts);
- return merged;
- }
- function wrapConstructor(hashCons) {
- const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
- const tmp = hashCons();
- hashC.outputLen = tmp.outputLen;
- hashC.blockLen = tmp.blockLen;
- hashC.create = () => hashCons();
- return hashC;
- }
- /**
- * Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
- */
- function randomBytes$2(bytesLength = 32) {
- if (crypto$1 && typeof crypto$1.getRandomValues === 'function') {
- return crypto$1.getRandomValues(new Uint8Array(bytesLength));
- }
- throw new Error('crypto.getRandomValues must be defined');
- }
- // HMAC (RFC 2104)
- class HMAC extends Hash {
- constructor(hash$1, _key) {
- super();
- this.finished = false;
- this.destroyed = false;
- hash(hash$1);
- const key = toBytes(_key);
- this.iHash = hash$1.create();
- if (typeof this.iHash.update !== 'function')
- throw new Error('Expected instance of class which extends utils.Hash');
- this.blockLen = this.iHash.blockLen;
- this.outputLen = this.iHash.outputLen;
- const blockLen = this.blockLen;
- const pad = new Uint8Array(blockLen);
- // blockLen can be bigger than outputLen
- pad.set(key.length > blockLen ? hash$1.create().update(key).digest() : key);
- for (let i = 0; i < pad.length; i++)
- pad[i] ^= 0x36;
- this.iHash.update(pad);
- // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
- this.oHash = hash$1.create();
- // Undo internal XOR && apply outer XOR
- for (let i = 0; i < pad.length; i++)
- pad[i] ^= 0x36 ^ 0x5c;
- this.oHash.update(pad);
- pad.fill(0);
- }
- update(buf) {
- exists(this);
- this.iHash.update(buf);
- return this;
- }
- digestInto(out) {
- exists(this);
- bytes(out, this.outputLen);
- this.finished = true;
- this.iHash.digestInto(out);
- this.oHash.update(out);
- this.oHash.digestInto(out);
- this.destroy();
- }
- digest() {
- const out = new Uint8Array(this.oHash.outputLen);
- this.digestInto(out);
- return out;
- }
- _cloneInto(to) {
- // Create new instance without calling constructor since key already in state and we don't know it.
- to || (to = Object.create(Object.getPrototypeOf(this), {}));
- const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
- to = to;
- to.finished = finished;
- to.destroyed = destroyed;
- to.blockLen = blockLen;
- to.outputLen = outputLen;
- to.oHash = oHash._cloneInto(to.oHash);
- to.iHash = iHash._cloneInto(to.iHash);
- return to;
- }
- destroy() {
- this.destroyed = true;
- this.oHash.destroy();
- this.iHash.destroy();
- }
- }
- /**
- * HMAC: RFC2104 message authentication code.
- * @param hash - function that would be used e.g. sha256
- * @param key - message key
- * @param message - message data
- */
- const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
- hmac.create = (hash, key) => new HMAC(hash, key);
- // Common prologue and epilogue for sync/async functions
- function pbkdf2Init(hash$1, _password, _salt, _opts) {
- hash(hash$1);
- const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
- const { c, dkLen, asyncTick } = opts;
- number(c);
- number(dkLen);
- number(asyncTick);
- if (c < 1)
- throw new Error('PBKDF2: iterations (c) should be >= 1');
- const password = toBytes(_password);
- const salt = toBytes(_salt);
- // DK = PBKDF2(PRF, Password, Salt, c, dkLen);
- const DK = new Uint8Array(dkLen);
- // U1 = PRF(Password, Salt + INT_32_BE(i))
- const PRF = hmac.create(hash$1, password);
- const PRFSalt = PRF._cloneInto().update(salt);
- return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
- }
- function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
- PRF.destroy();
- PRFSalt.destroy();
- if (prfW)
- prfW.destroy();
- u.fill(0);
- return DK;
- }
- /**
- * PBKDF2-HMAC: RFC 2898 key derivation function
- * @param hash - hash function that would be used e.g. sha256
- * @param password - password from which a derived key is generated
- * @param salt - cryptographic salt
- * @param opts - {c, dkLen} where c is work factor and dkLen is output message size
- */
- function pbkdf2$1(hash, password, salt, opts) {
- const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
- let prfW; // Working copy
- const arr = new Uint8Array(4);
- const view = createView(arr);
- const u = new Uint8Array(PRF.outputLen);
- // DK = T1 + T2 + ⋯ + Tdklen/hlen
- for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
- // Ti = F(Password, Salt, c, i)
- const Ti = DK.subarray(pos, pos + PRF.outputLen);
- view.setInt32(0, ti, false);
- // F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
- // U1 = PRF(Password, Salt + INT_32_BE(i))
- (prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
- Ti.set(u.subarray(0, Ti.length));
- for (let ui = 1; ui < c; ui++) {
- // Uc = PRF(Password, Uc−1)
- PRF._cloneInto(prfW).update(u).digestInto(u);
- for (let i = 0; i < Ti.length; i++)
- Ti[i] ^= u[i];
- }
- }
- return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
- }
- // Polyfill for Safari 14
- function setBigUint64(view, byteOffset, value, isLE) {
- if (typeof view.setBigUint64 === 'function')
- return view.setBigUint64(byteOffset, value, isLE);
- const _32n = BigInt(32);
- const _u32_max = BigInt(0xffffffff);
- const wh = Number((value >> _32n) & _u32_max);
- const wl = Number(value & _u32_max);
- const h = isLE ? 4 : 0;
- const l = isLE ? 0 : 4;
- view.setUint32(byteOffset + h, wh, isLE);
- view.setUint32(byteOffset + l, wl, isLE);
- }
- // Base SHA2 class (RFC 6234)
- class SHA2 extends Hash {
- constructor(blockLen, outputLen, padOffset, isLE) {
- super();
- this.blockLen = blockLen;
- this.outputLen = outputLen;
- this.padOffset = padOffset;
- this.isLE = isLE;
- this.finished = false;
- this.length = 0;
- this.pos = 0;
- this.destroyed = false;
- this.buffer = new Uint8Array(blockLen);
- this.view = createView(this.buffer);
- }
- update(data) {
- exists(this);
- const { view, buffer, blockLen } = this;
- data = toBytes(data);
- const len = data.length;
- for (let pos = 0; pos < len;) {
- const take = Math.min(blockLen - this.pos, len - pos);
- // Fast path: we have at least one block in input, cast it to view and process
- if (take === blockLen) {
- const dataView = createView(data);
- for (; blockLen <= len - pos; pos += blockLen)
- this.process(dataView, pos);
- continue;
- }
- buffer.set(data.subarray(pos, pos + take), this.pos);
- this.pos += take;
- pos += take;
- if (this.pos === blockLen) {
- this.process(view, 0);
- this.pos = 0;
- }
- }
- this.length += data.length;
- this.roundClean();
- return this;
- }
- digestInto(out) {
- exists(this);
- output(out, this);
- this.finished = true;
- // Padding
- // We can avoid allocation of buffer for padding completely if it
- // was previously not allocated here. But it won't change performance.
- const { buffer, view, blockLen, isLE } = this;
- let { pos } = this;
- // append the bit '1' to the message
- buffer[pos++] = 0b10000000;
- this.buffer.subarray(pos).fill(0);
- // we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
- if (this.padOffset > blockLen - pos) {
- this.process(view, 0);
- pos = 0;
- }
- // Pad until full block byte with zeros
- for (let i = pos; i < blockLen; i++)
- buffer[i] = 0;
- // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
- // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
- // So we just write lowest 64 bits of that value.
- setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
- this.process(view, 0);
- const oview = createView(out);
- const len = this.outputLen;
- // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
- if (len % 4)
- throw new Error('_sha2: outputLen should be aligned to 32bit');
- const outLen = len / 4;
- const state = this.get();
- if (outLen > state.length)
- throw new Error('_sha2: outputLen bigger than state');
- for (let i = 0; i < outLen; i++)
- oview.setUint32(4 * i, state[i], isLE);
- }
- digest() {
- const { buffer, outputLen } = this;
- this.digestInto(buffer);
- const res = buffer.slice(0, outputLen);
- this.destroy();
- return res;
- }
- _cloneInto(to) {
- to || (to = new this.constructor());
- to.set(...this.get());
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
- to.length = length;
- to.pos = pos;
- to.finished = finished;
- to.destroyed = destroyed;
- if (length % blockLen)
- to.buffer.set(buffer);
- return to;
- }
- }
- // SHA2-256 need to try 2^128 hashes to execute birthday attack.
- // BTC network is doing 2^67 hashes/sec as per early 2023.
- // Choice: a ? b : c
- const Chi = (a, b, c) => (a & b) ^ (~a & c);
- // Majority function, true if any two inpust is true
- const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
- // Round constants:
- // first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
- // prettier-ignore
- const SHA256_K = /* @__PURE__ */ new Uint32Array([
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
- ]);
- // Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
- // prettier-ignore
- const IV = /* @__PURE__ */ new Uint32Array([
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
- ]);
- // Temporary buffer, not used to store anything between runs
- // Named this way because it matches specification.
- const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
- class SHA256 extends SHA2 {
- constructor() {
- super(64, 32, 8, false);
- // We cannot use array here since array allows indexing by variable
- // which means optimizer/compiler cannot use registers.
- this.A = IV[0] | 0;
- this.B = IV[1] | 0;
- this.C = IV[2] | 0;
- this.D = IV[3] | 0;
- this.E = IV[4] | 0;
- this.F = IV[5] | 0;
- this.G = IV[6] | 0;
- this.H = IV[7] | 0;
- }
- get() {
- const { A, B, C, D, E, F, G, H } = this;
- return [A, B, C, D, E, F, G, H];
- }
- // prettier-ignore
- set(A, B, C, D, E, F, G, H) {
- this.A = A | 0;
- this.B = B | 0;
- this.C = C | 0;
- this.D = D | 0;
- this.E = E | 0;
- this.F = F | 0;
- this.G = G | 0;
- this.H = H | 0;
- }
- process(view, offset) {
- // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
- for (let i = 0; i < 16; i++, offset += 4)
- SHA256_W[i] = view.getUint32(offset, false);
- for (let i = 16; i < 64; i++) {
- const W15 = SHA256_W[i - 15];
- const W2 = SHA256_W[i - 2];
- const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
- const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
- SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
- }
- // Compression function main loop, 64 rounds
- let { A, B, C, D, E, F, G, H } = this;
- for (let i = 0; i < 64; i++) {
- const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
- const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
- const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
- const T2 = (sigma0 + Maj(A, B, C)) | 0;
- H = G;
- G = F;
- F = E;
- E = (D + T1) | 0;
- D = C;
- C = B;
- B = A;
- A = (T1 + T2) | 0;
- }
- // Add the compressed chunk to the current hash value
- A = (A + this.A) | 0;
- B = (B + this.B) | 0;
- C = (C + this.C) | 0;
- D = (D + this.D) | 0;
- E = (E + this.E) | 0;
- F = (F + this.F) | 0;
- G = (G + this.G) | 0;
- H = (H + this.H) | 0;
- this.set(A, B, C, D, E, F, G, H);
- }
- roundClean() {
- SHA256_W.fill(0);
- }
- destroy() {
- this.set(0, 0, 0, 0, 0, 0, 0, 0);
- this.buffer.fill(0);
- }
- }
- /**
- * SHA2-256 hash function
- * @param message - data that would be hashed
- */
- const sha256$1 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
- const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
- const _32n = /* @__PURE__ */ BigInt(32);
- // We are not using BigUint64Array, because they are extremely slow as per 2022
- function fromBig(n, le = false) {
- if (le)
- return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };
- return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
- }
- function split$1(lst, le = false) {
- let Ah = new Uint32Array(lst.length);
- let Al = new Uint32Array(lst.length);
- for (let i = 0; i < lst.length; i++) {
- const { h, l } = fromBig(lst[i], le);
- [Ah[i], Al[i]] = [h, l];
- }
- return [Ah, Al];
- }
- const toBig = (h, l) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);
- // for Shift in [0, 32)
- const shrSH = (h, _l, s) => h >>> s;
- const shrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);
- // Right rotate for Shift in [1, 32)
- const rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s));
- const rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);
- // Right rotate for Shift in (32, 64), NOTE: 32 is special case.
- const rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32));
- const rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s));
- // Right rotate for shift===32 (just swaps l&h)
- const rotr32H = (_h, l) => l;
- const rotr32L = (h, _l) => h;
- // Left rotate for Shift in [1, 32)
- const rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s));
- const rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s));
- // Left rotate for Shift in (32, 64), NOTE: 32 is special case.
- const rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s));
- const rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s));
- // JS uses 32-bit signed integers for bitwise operations which means we cannot
- // simple take carry out of low bit sum by shift, we need to use division.
- function add(Ah, Al, Bh, Bl) {
- const l = (Al >>> 0) + (Bl >>> 0);
- return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };
- }
- // Addition with more than 2 elements
- const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
- const add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;
- const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
- const add4H = (low, Ah, Bh, Ch, Dh) => (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;
- const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
- const add5H = (low, Ah, Bh, Ch, Dh, Eh) => (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;
- // prettier-ignore
- const u64 = {
- fromBig, split: split$1, toBig,
- shrSH, shrSL,
- rotrSH, rotrSL, rotrBH, rotrBL,
- rotr32H, rotr32L,
- rotlSH, rotlSL, rotlBH, rotlBL,
- add, add3L, add3H, add4L, add4H, add5H, add5L,
- };
- // Round contants (first 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409):
- // prettier-ignore
- const [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (() => u64.split([
- '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',
- '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',
- '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',
- '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',
- '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',
- '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',
- '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',
- '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',
- '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',
- '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',
- '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',
- '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',
- '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',
- '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',
- '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',
- '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',
- '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',
- '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',
- '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',
- '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'
- ].map(n => BigInt(n))))();
- // Temporary buffer, not used to store anything between runs
- const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
- const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
- class SHA512 extends SHA2 {
- constructor() {
- super(128, 64, 16, false);
- // We cannot use array here since array allows indexing by variable which means optimizer/compiler cannot use registers.
- // Also looks cleaner and easier to verify with spec.
- // Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
- // h -- high 32 bits, l -- low 32 bits
- this.Ah = 0x6a09e667 | 0;
- this.Al = 0xf3bcc908 | 0;
- this.Bh = 0xbb67ae85 | 0;
- this.Bl = 0x84caa73b | 0;
- this.Ch = 0x3c6ef372 | 0;
- this.Cl = 0xfe94f82b | 0;
- this.Dh = 0xa54ff53a | 0;
- this.Dl = 0x5f1d36f1 | 0;
- this.Eh = 0x510e527f | 0;
- this.El = 0xade682d1 | 0;
- this.Fh = 0x9b05688c | 0;
- this.Fl = 0x2b3e6c1f | 0;
- this.Gh = 0x1f83d9ab | 0;
- this.Gl = 0xfb41bd6b | 0;
- this.Hh = 0x5be0cd19 | 0;
- this.Hl = 0x137e2179 | 0;
- }
- // prettier-ignore
- get() {
- const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
- return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
- }
- // prettier-ignore
- set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
- this.Ah = Ah | 0;
- this.Al = Al | 0;
- this.Bh = Bh | 0;
- this.Bl = Bl | 0;
- this.Ch = Ch | 0;
- this.Cl = Cl | 0;
- this.Dh = Dh | 0;
- this.Dl = Dl | 0;
- this.Eh = Eh | 0;
- this.El = El | 0;
- this.Fh = Fh | 0;
- this.Fl = Fl | 0;
- this.Gh = Gh | 0;
- this.Gl = Gl | 0;
- this.Hh = Hh | 0;
- this.Hl = Hl | 0;
- }
- process(view, offset) {
- // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array
- for (let i = 0; i < 16; i++, offset += 4) {
- SHA512_W_H[i] = view.getUint32(offset);
- SHA512_W_L[i] = view.getUint32((offset += 4));
- }
- for (let i = 16; i < 80; i++) {
- // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)
- const W15h = SHA512_W_H[i - 15] | 0;
- const W15l = SHA512_W_L[i - 15] | 0;
- const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);
- const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);
- // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)
- const W2h = SHA512_W_H[i - 2] | 0;
- const W2l = SHA512_W_L[i - 2] | 0;
- const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);
- const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);
- // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];
- const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
- const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);
- SHA512_W_H[i] = SUMh | 0;
- SHA512_W_L[i] = SUMl | 0;
- }
- let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
- // Compression function main loop, 80 rounds
- for (let i = 0; i < 80; i++) {
- // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)
- const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);
- const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);
- //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
- const CHIh = (Eh & Fh) ^ (~Eh & Gh);
- const CHIl = (El & Fl) ^ (~El & Gl);
- // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]
- // prettier-ignore
- const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
- const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
- const T1l = T1ll | 0;
- // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)
- const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);
- const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);
- const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);
- const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);
- Hh = Gh | 0;
- Hl = Gl | 0;
- Gh = Fh | 0;
- Gl = Fl | 0;
- Fh = Eh | 0;
- Fl = El | 0;
- ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
- Dh = Ch | 0;
- Dl = Cl | 0;
- Ch = Bh | 0;
- Cl = Bl | 0;
- Bh = Ah | 0;
- Bl = Al | 0;
- const All = u64.add3L(T1l, sigma0l, MAJl);
- Ah = u64.add3H(All, T1h, sigma0h, MAJh);
- Al = All | 0;
- }
- // Add the compressed chunk to the current hash value
- ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
- ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
- ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
- ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
- ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
- ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
- ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
- ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
- this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
- }
- roundClean() {
- SHA512_W_H.fill(0);
- SHA512_W_L.fill(0);
- }
- destroy() {
- this.buffer.fill(0);
- this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- }
- }
- const sha512$1 = /* @__PURE__ */ wrapConstructor(() => new SHA512());
- /* Browser Crypto Shims */
- function getGlobal$1() {
- if (typeof self !== 'undefined') {
- return self;
- }
- if (typeof window !== 'undefined') {
- return window;
- }
- if (typeof global !== 'undefined') {
- return global;
- }
- throw new Error('unable to locate global object');
- }
- const anyGlobal = getGlobal$1();
- const crypto = anyGlobal.crypto || anyGlobal.msCrypto;
- function createHash(algo) {
- switch (algo) {
- case "sha256": return sha256$1.create();
- case "sha512": return sha512$1.create();
- }
- assertArgument(false, "invalid hashing algorithm name", "algorithm", algo);
- }
- function createHmac(_algo, key) {
- const algo = ({ sha256: sha256$1, sha512: sha512$1 }[_algo]);
- assertArgument(algo != null, "invalid hmac algorithm", "algorithm", _algo);
- return hmac.create(algo, key);
- }
- function pbkdf2Sync(password, salt, iterations, keylen, _algo) {
- const algo = ({ sha256: sha256$1, sha512: sha512$1 }[_algo]);
- assertArgument(algo != null, "invalid pbkdf2 algorithm", "algorithm", _algo);
- return pbkdf2$1(algo, password, salt, { c: iterations, dkLen: keylen });
- }
- function randomBytes$1(length) {
- assert(crypto != null, "platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
- operation: "randomBytes"
- });
- assertArgument(Number.isInteger(length) && length > 0 && length <= 1024, "invalid length", "length", length);
- const result = new Uint8Array(length);
- crypto.getRandomValues(result);
- return result;
- }
- /**
- * An **HMAC** enables verification that a given key was used
- * to authenticate a payload.
- *
- * See: [[link-wiki-hmac]]
- *
- * @_subsection: api/crypto:HMAC [about-hmac]
- */
- let locked$4 = false;
- const _computeHmac = function (algorithm, key, data) {
- return createHmac(algorithm, key).update(data).digest();
- };
- let __computeHmac = _computeHmac;
- /**
- * Return the HMAC for %%data%% using the %%key%% key with the underlying
- * %%algo%% used for compression.
- *
- * @example:
- * key = id("some-secret")
- *
- * // Compute the HMAC
- * computeHmac("sha256", key, "0x1337")
- * //_result:
- *
- * // To compute the HMAC of UTF-8 data, the data must be
- * // converted to UTF-8 bytes
- * computeHmac("sha256", key, toUtf8Bytes("Hello World"))
- * //_result:
- *
- */
- function computeHmac(algorithm, _key, _data) {
- const key = getBytes(_key, "key");
- const data = getBytes(_data, "data");
- return hexlify(__computeHmac(algorithm, key, data));
- }
- computeHmac._ = _computeHmac;
- computeHmac.lock = function () { locked$4 = true; };
- computeHmac.register = function (func) {
- if (locked$4) {
- throw new Error("computeHmac is locked");
- }
- __computeHmac = func;
- };
- Object.freeze(computeHmac);
- // SHA3 (keccak) is based on a new design: basically, the internal state is bigger than output size.
- // It's called a sponge function.
- // Various per round constants calculations
- const [SHA3_PI, SHA3_ROTL, _SHA3_IOTA] = [[], [], []];
- const _0n$4 = /* @__PURE__ */ BigInt(0);
- const _1n$5 = /* @__PURE__ */ BigInt(1);
- const _2n$3 = /* @__PURE__ */ BigInt(2);
- const _7n = /* @__PURE__ */ BigInt(7);
- const _256n = /* @__PURE__ */ BigInt(256);
- const _0x71n = /* @__PURE__ */ BigInt(0x71);
- for (let round = 0, R = _1n$5, x = 1, y = 0; round < 24; round++) {
- // Pi
- [x, y] = [y, (2 * x + 3 * y) % 5];
- SHA3_PI.push(2 * (5 * y + x));
- // Rotational
- SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);
- // Iota
- let t = _0n$4;
- for (let j = 0; j < 7; j++) {
- R = ((R << _1n$5) ^ ((R >> _7n) * _0x71n)) % _256n;
- if (R & _2n$3)
- t ^= _1n$5 << ((_1n$5 << /* @__PURE__ */ BigInt(j)) - _1n$5);
- }
- _SHA3_IOTA.push(t);
- }
- const [SHA3_IOTA_H, SHA3_IOTA_L] = /* @__PURE__ */ split$1(_SHA3_IOTA, true);
- // Left rotation (without 0, 32, 64)
- const rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s));
- const rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s));
- // Same as keccakf1600, but allows to skip some rounds
- function keccakP(s, rounds = 24) {
- const B = new Uint32Array(5 * 2);
- // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
- for (let round = 24 - rounds; round < 24; round++) {
- // Theta θ
- for (let x = 0; x < 10; x++)
- B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
- for (let x = 0; x < 10; x += 2) {
- const idx1 = (x + 8) % 10;
- const idx0 = (x + 2) % 10;
- const B0 = B[idx0];
- const B1 = B[idx0 + 1];
- const Th = rotlH(B0, B1, 1) ^ B[idx1];
- const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
- for (let y = 0; y < 50; y += 10) {
- s[x + y] ^= Th;
- s[x + y + 1] ^= Tl;
- }
- }
- // Rho (ρ) and Pi (π)
- let curH = s[2];
- let curL = s[3];
- for (let t = 0; t < 24; t++) {
- const shift = SHA3_ROTL[t];
- const Th = rotlH(curH, curL, shift);
- const Tl = rotlL(curH, curL, shift);
- const PI = SHA3_PI[t];
- curH = s[PI];
- curL = s[PI + 1];
- s[PI] = Th;
- s[PI + 1] = Tl;
- }
- // Chi (χ)
- for (let y = 0; y < 50; y += 10) {
- for (let x = 0; x < 10; x++)
- B[x] = s[y + x];
- for (let x = 0; x < 10; x++)
- s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
- }
- // Iota (ι)
- s[0] ^= SHA3_IOTA_H[round];
- s[1] ^= SHA3_IOTA_L[round];
- }
- B.fill(0);
- }
- class Keccak extends Hash {
- // NOTE: we accept arguments in bytes instead of bits here.
- constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
- super();
- this.blockLen = blockLen;
- this.suffix = suffix;
- this.outputLen = outputLen;
- this.enableXOF = enableXOF;
- this.rounds = rounds;
- this.pos = 0;
- this.posOut = 0;
- this.finished = false;
- this.destroyed = false;
- // Can be passed from user as dkLen
- number(outputLen);
- // 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
- if (0 >= this.blockLen || this.blockLen >= 200)
- throw new Error('Sha3 supports only keccak-f1600 function');
- this.state = new Uint8Array(200);
- this.state32 = u32(this.state);
- }
- keccak() {
- keccakP(this.state32, this.rounds);
- this.posOut = 0;
- this.pos = 0;
- }
- update(data) {
- exists(this);
- const { blockLen, state } = this;
- data = toBytes(data);
- const len = data.length;
- for (let pos = 0; pos < len;) {
- const take = Math.min(blockLen - this.pos, len - pos);
- for (let i = 0; i < take; i++)
- state[this.pos++] ^= data[pos++];
- if (this.pos === blockLen)
- this.keccak();
- }
- return this;
- }
- finish() {
- if (this.finished)
- return;
- this.finished = true;
- const { state, suffix, pos, blockLen } = this;
- // Do the padding
- state[pos] ^= suffix;
- if ((suffix & 0x80) !== 0 && pos === blockLen - 1)
- this.keccak();
- state[blockLen - 1] ^= 0x80;
- this.keccak();
- }
- writeInto(out) {
- exists(this, false);
- bytes(out);
- this.finish();
- const bufferOut = this.state;
- const { blockLen } = this;
- for (let pos = 0, len = out.length; pos < len;) {
- if (this.posOut >= blockLen)
- this.keccak();
- const take = Math.min(blockLen - this.posOut, len - pos);
- out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
- this.posOut += take;
- pos += take;
- }
- return out;
- }
- xofInto(out) {
- // Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
- if (!this.enableXOF)
- throw new Error('XOF is not possible for this instance');
- return this.writeInto(out);
- }
- xof(bytes) {
- number(bytes);
- return this.xofInto(new Uint8Array(bytes));
- }
- digestInto(out) {
- output(out, this);
- if (this.finished)
- throw new Error('digest() was already called');
- this.writeInto(out);
- this.destroy();
- return out;
- }
- digest() {
- return this.digestInto(new Uint8Array(this.outputLen));
- }
- destroy() {
- this.destroyed = true;
- this.state.fill(0);
- }
- _cloneInto(to) {
- const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
- to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
- to.state32.set(this.state32);
- to.pos = this.pos;
- to.posOut = this.posOut;
- to.finished = this.finished;
- to.rounds = rounds;
- // Suffix can change in cSHAKE
- to.suffix = suffix;
- to.outputLen = outputLen;
- to.enableXOF = enableXOF;
- to.destroyed = this.destroyed;
- return to;
- }
- }
- const gen = (suffix, blockLen, outputLen) => wrapConstructor(() => new Keccak(blockLen, suffix, outputLen));
- /**
- * keccak-256 hash function. Different from SHA3-256.
- * @param message - that would be hashed
- */
- const keccak_256 = /* @__PURE__ */ gen(0x01, 136, 256 / 8);
- /**
- * Cryptographic hashing functions
- *
- * @_subsection: api/crypto:Hash Functions [about-crypto-hashing]
- */
- let locked$3 = false;
- const _keccak256 = function (data) {
- return keccak_256(data);
- };
- let __keccak256 = _keccak256;
- /**
- * Compute the cryptographic KECCAK256 hash of %%data%%.
- *
- * The %%data%% **must** be a data representation, to compute the
- * hash of UTF-8 data use the [[id]] function.
- *
- * @returns DataHexstring
- * @example:
- * keccak256("0x")
- * //_result:
- *
- * keccak256("0x1337")
- * //_result:
- *
- * keccak256(new Uint8Array([ 0x13, 0x37 ]))
- * //_result:
- *
- * // Strings are assumed to be DataHexString, otherwise it will
- * // throw. To hash UTF-8 data, see the note above.
- * keccak256("Hello World")
- * //_error:
- */
- function keccak256(_data) {
- const data = getBytes(_data, "data");
- return hexlify(__keccak256(data));
- }
- keccak256._ = _keccak256;
- keccak256.lock = function () { locked$3 = true; };
- keccak256.register = function (func) {
- if (locked$3) {
- throw new TypeError("keccak256 is locked");
- }
- __keccak256 = func;
- };
- Object.freeze(keccak256);
- // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
- // https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
- const Rho = /* @__PURE__ */ new Uint8Array([7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8]);
- const Id = /* @__PURE__ */ Uint8Array.from({ length: 16 }, (_, i) => i);
- const Pi = /* @__PURE__ */ Id.map((i) => (9 * i + 5) % 16);
- let idxL = [Id];
- let idxR = [Pi];
- for (let i = 0; i < 4; i++)
- for (let j of [idxL, idxR])
- j.push(j[i].map((k) => Rho[k]));
- const shifts = /* @__PURE__ */ [
- [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
- [12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
- [13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
- [14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
- [15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],
- ].map((i) => new Uint8Array(i));
- const shiftsL = /* @__PURE__ */ idxL.map((idx, i) => idx.map((j) => shifts[i][j]));
- const shiftsR = /* @__PURE__ */ idxR.map((idx, i) => idx.map((j) => shifts[i][j]));
- const Kl = /* @__PURE__ */ new Uint32Array([
- 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e,
- ]);
- const Kr = /* @__PURE__ */ new Uint32Array([
- 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000,
- ]);
- // The rotate left (circular left shift) operation for uint32
- const rotl$1 = (word, shift) => (word << shift) | (word >>> (32 - shift));
- // It's called f() in spec.
- function f(group, x, y, z) {
- if (group === 0)
- return x ^ y ^ z;
- else if (group === 1)
- return (x & y) | (~x & z);
- else if (group === 2)
- return (x | ~y) ^ z;
- else if (group === 3)
- return (x & z) | (y & ~z);
- else
- return x ^ (y | ~z);
- }
- // Temporary buffer, not used to store anything between runs
- const BUF = /* @__PURE__ */ new Uint32Array(16);
- class RIPEMD160 extends SHA2 {
- constructor() {
- super(64, 20, 8, true);
- this.h0 = 0x67452301 | 0;
- this.h1 = 0xefcdab89 | 0;
- this.h2 = 0x98badcfe | 0;
- this.h3 = 0x10325476 | 0;
- this.h4 = 0xc3d2e1f0 | 0;
- }
- get() {
- const { h0, h1, h2, h3, h4 } = this;
- return [h0, h1, h2, h3, h4];
- }
- set(h0, h1, h2, h3, h4) {
- this.h0 = h0 | 0;
- this.h1 = h1 | 0;
- this.h2 = h2 | 0;
- this.h3 = h3 | 0;
- this.h4 = h4 | 0;
- }
- process(view, offset) {
- for (let i = 0; i < 16; i++, offset += 4)
- BUF[i] = view.getUint32(offset, true);
- // prettier-ignore
- let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el;
- // Instead of iterating 0 to 80, we split it into 5 groups
- // And use the groups in constants, functions, etc. Much simpler
- for (let group = 0; group < 5; group++) {
- const rGroup = 4 - group;
- const hbl = Kl[group], hbr = Kr[group]; // prettier-ignore
- const rl = idxL[group], rr = idxR[group]; // prettier-ignore
- const sl = shiftsL[group], sr = shiftsR[group]; // prettier-ignore
- for (let i = 0; i < 16; i++) {
- const tl = (rotl$1(al + f(group, bl, cl, dl) + BUF[rl[i]] + hbl, sl[i]) + el) | 0;
- al = el, el = dl, dl = rotl$1(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore
- }
- // 2 loops are 10% faster
- for (let i = 0; i < 16; i++) {
- const tr = (rotl$1(ar + f(rGroup, br, cr, dr) + BUF[rr[i]] + hbr, sr[i]) + er) | 0;
- ar = er, er = dr, dr = rotl$1(cr, 10) | 0, cr = br, br = tr; // prettier-ignore
- }
- }
- // Add the compressed chunk to the current hash value
- this.set((this.h1 + cl + dr) | 0, (this.h2 + dl + er) | 0, (this.h3 + el + ar) | 0, (this.h4 + al + br) | 0, (this.h0 + bl + cr) | 0);
- }
- roundClean() {
- BUF.fill(0);
- }
- destroy() {
- this.destroyed = true;
- this.buffer.fill(0);
- this.set(0, 0, 0, 0, 0);
- }
- }
- /**
- * RIPEMD-160 - a hash function from 1990s.
- * @param message - msg that would be hashed
- */
- const ripemd160$1 = /* @__PURE__ */ wrapConstructor(() => new RIPEMD160());
- let locked$2 = false;
- const _ripemd160 = function (data) {
- return ripemd160$1(data);
- };
- let __ripemd160 = _ripemd160;
- /**
- * Compute the cryptographic RIPEMD-160 hash of %%data%%.
- *
- * @_docloc: api/crypto:Hash Functions
- * @returns DataHexstring
- *
- * @example:
- * ripemd160("0x")
- * //_result:
- *
- * ripemd160("0x1337")
- * //_result:
- *
- * ripemd160(new Uint8Array([ 0x13, 0x37 ]))
- * //_result:
- *
- */
- function ripemd160(_data) {
- const data = getBytes(_data, "data");
- return hexlify(__ripemd160(data));
- }
- ripemd160._ = _ripemd160;
- ripemd160.lock = function () { locked$2 = true; };
- ripemd160.register = function (func) {
- if (locked$2) {
- throw new TypeError("ripemd160 is locked");
- }
- __ripemd160 = func;
- };
- Object.freeze(ripemd160);
- /**
- * A **Password-Based Key-Derivation Function** is designed to create
- * a sequence of bytes suitible as a **key** from a human-rememberable
- * password.
- *
- * @_subsection: api/crypto:Passwords [about-pbkdf]
- */
- let locked$1 = false;
- const _pbkdf2 = function (password, salt, iterations, keylen, algo) {
- return pbkdf2Sync(password, salt, iterations, keylen, algo);
- };
- let __pbkdf2 = _pbkdf2;
- /**
- * Return the [[link-pbkdf2]] for %%keylen%% bytes for %%password%% using
- * the %%salt%% and using %%iterations%% of %%algo%%.
- *
- * This PBKDF is outdated and should not be used in new projects, but is
- * required to decrypt older files.
- *
- * @example:
- * // The password must be converted to bytes, and it is generally
- * // best practices to ensure the string has been normalized. Many
- * // formats explicitly indicate the normalization form to use.
- * password = "hello"
- * passwordBytes = toUtf8Bytes(password, "NFKC")
- *
- * salt = id("some-salt")
- *
- * // Compute the PBKDF2
- * pbkdf2(passwordBytes, salt, 1024, 16, "sha256")
- * //_result:
- */
- function pbkdf2(_password, _salt, iterations, keylen, algo) {
- const password = getBytes(_password, "password");
- const salt = getBytes(_salt, "salt");
- return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
- }
- pbkdf2._ = _pbkdf2;
- pbkdf2.lock = function () { locked$1 = true; };
- pbkdf2.register = function (func) {
- if (locked$1) {
- throw new Error("pbkdf2 is locked");
- }
- __pbkdf2 = func;
- };
- Object.freeze(pbkdf2);
- /**
- * A **Cryptographically Secure Random Value** is one that has been
- * generated with additional care take to prevent side-channels
- * from allowing others to detect it and prevent others from through
- * coincidence generate the same values.
- *
- * @_subsection: api/crypto:Random Values [about-crypto-random]
- */
- let locked = false;
- const _randomBytes = function (length) {
- return new Uint8Array(randomBytes$1(length));
- };
- let __randomBytes = _randomBytes;
- /**
- * Return %%length%% bytes of cryptographically secure random data.
- *
- * @example:
- * randomBytes(8)
- * //_result:
- */
- function randomBytes(length) {
- return __randomBytes(length);
- }
- randomBytes._ = _randomBytes;
- randomBytes.lock = function () { locked = true; };
- randomBytes.register = function (func) {
- if (locked) {
- throw new Error("randomBytes is locked");
- }
- __randomBytes = func;
- };
- Object.freeze(randomBytes);
- // RFC 7914 Scrypt KDF
- // Left rotate for uint32
- const rotl = (a, b) => (a << b) | (a >>> (32 - b));
- // The main Scrypt loop: uses Salsa extensively.
- // Six versions of the function were tried, this is the fastest one.
- // prettier-ignore
- function XorAndSalsa(prev, pi, input, ii, out, oi) {
- // Based on https://cr.yp.to/salsa20.html
- // Xor blocks
- let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
- let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
- let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
- let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
- let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
- let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
- let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
- let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
- // Save state to temporary variables (salsa)
- let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
- // Main loop (salsa)
- for (let i = 0; i < 8; i += 2) {
- x04 ^= rotl(x00 + x12 | 0, 7);
- x08 ^= rotl(x04 + x00 | 0, 9);
- x12 ^= rotl(x08 + x04 | 0, 13);
- x00 ^= rotl(x12 + x08 | 0, 18);
- x09 ^= rotl(x05 + x01 | 0, 7);
- x13 ^= rotl(x09 + x05 | 0, 9);
- x01 ^= rotl(x13 + x09 | 0, 13);
- x05 ^= rotl(x01 + x13 | 0, 18);
- x14 ^= rotl(x10 + x06 | 0, 7);
- x02 ^= rotl(x14 + x10 | 0, 9);
- x06 ^= rotl(x02 + x14 | 0, 13);
- x10 ^= rotl(x06 + x02 | 0, 18);
- x03 ^= rotl(x15 + x11 | 0, 7);
- x07 ^= rotl(x03 + x15 | 0, 9);
- x11 ^= rotl(x07 + x03 | 0, 13);
- x15 ^= rotl(x11 + x07 | 0, 18);
- x01 ^= rotl(x00 + x03 | 0, 7);
- x02 ^= rotl(x01 + x00 | 0, 9);
- x03 ^= rotl(x02 + x01 | 0, 13);
- x00 ^= rotl(x03 + x02 | 0, 18);
- x06 ^= rotl(x05 + x04 | 0, 7);
- x07 ^= rotl(x06 + x05 | 0, 9);
- x04 ^= rotl(x07 + x06 | 0, 13);
- x05 ^= rotl(x04 + x07 | 0, 18);
- x11 ^= rotl(x10 + x09 | 0, 7);
- x08 ^= rotl(x11 + x10 | 0, 9);
- x09 ^= rotl(x08 + x11 | 0, 13);
- x10 ^= rotl(x09 + x08 | 0, 18);
- x12 ^= rotl(x15 + x14 | 0, 7);
- x13 ^= rotl(x12 + x15 | 0, 9);
- x14 ^= rotl(x13 + x12 | 0, 13);
- x15 ^= rotl(x14 + x13 | 0, 18);
- }
- // Write output (salsa)
- out[oi++] = (y00 + x00) | 0;
- out[oi++] = (y01 + x01) | 0;
- out[oi++] = (y02 + x02) | 0;
- out[oi++] = (y03 + x03) | 0;
- out[oi++] = (y04 + x04) | 0;
- out[oi++] = (y05 + x05) | 0;
- out[oi++] = (y06 + x06) | 0;
- out[oi++] = (y07 + x07) | 0;
- out[oi++] = (y08 + x08) | 0;
- out[oi++] = (y09 + x09) | 0;
- out[oi++] = (y10 + x10) | 0;
- out[oi++] = (y11 + x11) | 0;
- out[oi++] = (y12 + x12) | 0;
- out[oi++] = (y13 + x13) | 0;
- out[oi++] = (y14 + x14) | 0;
- out[oi++] = (y15 + x15) | 0;
- }
- function BlockMix(input, ii, out, oi, r) {
- // The block B is r 128-byte chunks (which is equivalent of 2r 64-byte chunks)
- let head = oi + 0;
- let tail = oi + 16 * r;
- for (let i = 0; i < 16; i++)
- out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; // X ← B[2r−1]
- for (let i = 0; i < r; i++, head += 16, ii += 16) {
- // We write odd & even Yi at same time. Even: 0bXXXXX0 Odd: 0bXXXXX1
- XorAndSalsa(out, tail, input, ii, out, head); // head[i] = Salsa(blockIn[2*i] ^ tail[i-1])
- if (i > 0)
- tail += 16; // First iteration overwrites tmp value in tail
- XorAndSalsa(out, head, input, (ii += 16), out, tail); // tail[i] = Salsa(blockIn[2*i+1] ^ head[i])
- }
- }
- // Common prologue and epilogue for sync/async functions
- function scryptInit(password, salt, _opts) {
- // Maxmem - 1GB+1KB by default
- const opts = checkOpts({
- dkLen: 32,
- asyncTick: 10,
- maxmem: 1024 ** 3 + 1024,
- }, _opts);
- const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
- number(N);
- number(r);
- number(p);
- number(dkLen);
- number(asyncTick);
- number(maxmem);
- if (onProgress !== undefined && typeof onProgress !== 'function')
- throw new Error('progressCb should be function');
- const blockSize = 128 * r;
- const blockSize32 = blockSize / 4;
- if (N <= 1 || (N & (N - 1)) !== 0 || N >= 2 ** (blockSize / 8) || N > 2 ** 32) {
- // NOTE: we limit N to be less than 2**32 because of 32 bit variant of Integrify function
- // There is no JS engines that allows alocate more than 4GB per single Uint8Array for now, but can change in future.
- throw new Error('Scrypt: N must be larger than 1, a power of 2, less than 2^(128 * r / 8) and less than 2^32');
- }
- if (p < 0 || p > ((2 ** 32 - 1) * 32) / blockSize) {
- throw new Error('Scrypt: p must be a positive integer less than or equal to ((2^32 - 1) * 32) / (128 * r)');
- }
- if (dkLen < 0 || dkLen > (2 ** 32 - 1) * 32) {
- throw new Error('Scrypt: dkLen should be positive integer less than or equal to (2^32 - 1) * 32');
- }
- const memUsed = blockSize * (N + p);
- if (memUsed > maxmem) {
- throw new Error(`Scrypt: parameters too large, ${memUsed} (128 * r * (N + p)) > ${maxmem} (maxmem)`);
- }
- // [B0...Bp−1] ← PBKDF2HMAC-SHA256(Passphrase, Salt, 1, blockSize*ParallelizationFactor)
- // Since it has only one iteration there is no reason to use async variant
- const B = pbkdf2$1(sha256$1, password, salt, { c: 1, dkLen: blockSize * p });
- const B32 = u32(B);
- // Re-used between parallel iterations. Array(iterations) of B
- const V = u32(new Uint8Array(blockSize * N));
- const tmp = u32(new Uint8Array(blockSize));
- let blockMixCb = () => { };
- if (onProgress) {
- const totalBlockMix = 2 * N * p;
- // Invoke callback if progress changes from 10.01 to 10.02
- // Allows to draw smooth progress bar on up to 8K screen
- const callbackPer = Math.max(Math.floor(totalBlockMix / 10000), 1);
- let blockMixCnt = 0;
- blockMixCb = () => {
- blockMixCnt++;
- if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix))
- onProgress(blockMixCnt / totalBlockMix);
- };
- }
- return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick };
- }
- function scryptOutput(password, dkLen, B, V, tmp) {
- const res = pbkdf2$1(sha256$1, password, B, { c: 1, dkLen });
- B.fill(0);
- V.fill(0);
- tmp.fill(0);
- return res;
- }
- /**
- * Scrypt KDF from RFC 7914.
- * @param password - pass
- * @param salt - salt
- * @param opts - parameters
- * - `N` is cpu/mem work factor (power of 2 e.g. 2**18)
- * - `r` is block size (8 is common), fine-tunes sequential memory read size and performance
- * - `p` is parallelization factor (1 is common)
- * - `dkLen` is output key length in bytes e.g. 32.
- * - `asyncTick` - (default: 10) max time in ms for which async function can block execution
- * - `maxmem` - (default: `1024 ** 3 + 1024` aka 1GB+1KB). A limit that the app could use for scrypt
- * - `onProgress` - callback function that would be executed for progress report
- * @returns Derived key
- */
- function scrypt$1(password, salt, opts) {
- const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts);
- for (let pi = 0; pi < p; pi++) {
- const Pi = blockSize32 * pi;
- for (let i = 0; i < blockSize32; i++)
- V[i] = B32[Pi + i]; // V[0] = B[i]
- for (let i = 0, pos = 0; i < N - 1; i++) {
- BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
- blockMixCb();
- }
- BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
- blockMixCb();
- for (let i = 0; i < N; i++) {
- // First u32 of the last 64-byte block (u32 is LE)
- const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
- for (let k = 0; k < blockSize32; k++)
- tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
- BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
- blockMixCb();
- }
- }
- return scryptOutput(password, dkLen, B, V, tmp);
- }
- /**
- * Scrypt KDF from RFC 7914.
- */
- async function scryptAsync(password, salt, opts) {
- const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick } = scryptInit(password, salt, opts);
- for (let pi = 0; pi < p; pi++) {
- const Pi = blockSize32 * pi;
- for (let i = 0; i < blockSize32; i++)
- V[i] = B32[Pi + i]; // V[0] = B[i]
- let pos = 0;
- await asyncLoop(N - 1, asyncTick, () => {
- BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
- blockMixCb();
- });
- BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
- blockMixCb();
- await asyncLoop(N, asyncTick, () => {
- // First u32 of the last 64-byte block (u32 is LE)
- const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
- for (let k = 0; k < blockSize32; k++)
- tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
- BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
- blockMixCb();
- });
- }
- return scryptOutput(password, dkLen, B, V, tmp);
- }
- let lockedSync = false, lockedAsync = false;
- const _scryptAsync = async function (passwd, salt, N, r, p, dkLen, onProgress) {
- return await scryptAsync(passwd, salt, { N, r, p, dkLen, onProgress });
- };
- const _scryptSync = function (passwd, salt, N, r, p, dkLen) {
- return scrypt$1(passwd, salt, { N, r, p, dkLen });
- };
- let __scryptAsync = _scryptAsync;
- let __scryptSync = _scryptSync;
- /**
- * The [[link-wiki-scrypt]] uses a memory and cpu hard method of
- * derivation to increase the resource cost to brute-force a password
- * for a given key.
- *
- * This means this algorithm is intentionally slow, and can be tuned to
- * become slower. As computation and memory speed improve over time,
- * increasing the difficulty maintains the cost of an attacker.
- *
- * For example, if a target time of 5 seconds is used, a legitimate user
- * which knows their password requires only 5 seconds to unlock their
- * account. A 6 character password has 68 billion possibilities, which
- * would require an attacker to invest over 10,000 years of CPU time. This
- * is of course a crude example (as password generally aren't random),
- * but demonstrates to value of imposing large costs to decryption.
- *
- * For this reason, if building a UI which involved decrypting or
- * encrypting datsa using scrypt, it is recommended to use a
- * [[ProgressCallback]] (as event short periods can seem lik an eternity
- * if the UI freezes). Including the phrase //"decrypting"// in the UI
- * can also help, assuring the user their waiting is for a good reason.
- *
- * @_docloc: api/crypto:Passwords
- *
- * @example:
- * // The password must be converted to bytes, and it is generally
- * // best practices to ensure the string has been normalized. Many
- * // formats explicitly indicate the normalization form to use.
- * password = "hello"
- * passwordBytes = toUtf8Bytes(password, "NFKC")
- *
- * salt = id("some-salt")
- *
- * // Compute the scrypt
- * scrypt(passwordBytes, salt, 1024, 8, 1, 16)
- * //_result:
- */
- async function scrypt(_passwd, _salt, N, r, p, dkLen, progress) {
- const passwd = getBytes(_passwd, "passwd");
- const salt = getBytes(_salt, "salt");
- return hexlify(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
- }
- scrypt._ = _scryptAsync;
- scrypt.lock = function () { lockedAsync = true; };
- scrypt.register = function (func) {
- if (lockedAsync) {
- throw new Error("scrypt is locked");
- }
- __scryptAsync = func;
- };
- Object.freeze(scrypt);
- /**
- * Provides a synchronous variant of [[scrypt]].
- *
- * This will completely lock up and freeze the UI in a browser and will
- * prevent any event loop from progressing. For this reason, it is
- * preferred to use the [async variant](scrypt).
- *
- * @_docloc: api/crypto:Passwords
- *
- * @example:
- * // The password must be converted to bytes, and it is generally
- * // best practices to ensure the string has been normalized. Many
- * // formats explicitly indicate the normalization form to use.
- * password = "hello"
- * passwordBytes = toUtf8Bytes(password, "NFKC")
- *
- * salt = id("some-salt")
- *
- * // Compute the scrypt
- * scryptSync(passwordBytes, salt, 1024, 8, 1, 16)
- * //_result:
- */
- function scryptSync(_passwd, _salt, N, r, p, dkLen) {
- const passwd = getBytes(_passwd, "passwd");
- const salt = getBytes(_salt, "salt");
- return hexlify(__scryptSync(passwd, salt, N, r, p, dkLen));
- }
- scryptSync._ = _scryptSync;
- scryptSync.lock = function () { lockedSync = true; };
- scryptSync.register = function (func) {
- if (lockedSync) {
- throw new Error("scryptSync is locked");
- }
- __scryptSync = func;
- };
- Object.freeze(scryptSync);
- const _sha256 = function (data) {
- return createHash("sha256").update(data).digest();
- };
- const _sha512 = function (data) {
- return createHash("sha512").update(data).digest();
- };
- let __sha256 = _sha256;
- let __sha512 = _sha512;
- let locked256 = false, locked512 = false;
- /**
- * Compute the cryptographic SHA2-256 hash of %%data%%.
- *
- * @_docloc: api/crypto:Hash Functions
- * @returns DataHexstring
- *
- * @example:
- * sha256("0x")
- * //_result:
- *
- * sha256("0x1337")
- * //_result:
- *
- * sha256(new Uint8Array([ 0x13, 0x37 ]))
- * //_result:
- *
- */
- function sha256(_data) {
- const data = getBytes(_data, "data");
- return hexlify(__sha256(data));
- }
- sha256._ = _sha256;
- sha256.lock = function () { locked256 = true; };
- sha256.register = function (func) {
- if (locked256) {
- throw new Error("sha256 is locked");
- }
- __sha256 = func;
- };
- Object.freeze(sha256);
- /**
- * Compute the cryptographic SHA2-512 hash of %%data%%.
- *
- * @_docloc: api/crypto:Hash Functions
- * @returns DataHexstring
- *
- * @example:
- * sha512("0x")
- * //_result:
- *
- * sha512("0x1337")
- * //_result:
- *
- * sha512(new Uint8Array([ 0x13, 0x37 ]))
- * //_result:
- */
- function sha512(_data) {
- const data = getBytes(_data, "data");
- return hexlify(__sha512(data));
- }
- sha512._ = _sha512;
- sha512.lock = function () { locked512 = true; };
- sha512.register = function (func) {
- if (locked512) {
- throw new Error("sha512 is locked");
- }
- __sha512 = func;
- };
- Object.freeze(sha256);
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // 100 lines of code in the file are duplicated from noble-hashes (utils).
- // This is OK: `abstract` directory does not use noble-hashes.
- // User may opt-in into using different hashing library. This way, noble-hashes
- // won't be included into their bundle.
- const _0n$3 = BigInt(0);
- const _1n$4 = BigInt(1);
- const _2n$2 = BigInt(2);
- const u8a = (a) => a instanceof Uint8Array;
- const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
- /**
- * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
- */
- function bytesToHex(bytes) {
- if (!u8a(bytes))
- throw new Error('Uint8Array expected');
- // pre-caching improves the speed 6x
- let hex = '';
- for (let i = 0; i < bytes.length; i++) {
- hex += hexes[bytes[i]];
- }
- return hex;
- }
- function numberToHexUnpadded(num) {
- const hex = num.toString(16);
- return hex.length & 1 ? `0${hex}` : hex;
- }
- function hexToNumber(hex) {
- if (typeof hex !== 'string')
- throw new Error('hex string expected, got ' + typeof hex);
- // Big Endian
- return BigInt(hex === '' ? '0' : `0x${hex}`);
- }
- /**
- * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
- */
- function hexToBytes(hex) {
- if (typeof hex !== 'string')
- throw new Error('hex string expected, got ' + typeof hex);
- const len = hex.length;
- if (len % 2)
- throw new Error('padded hex string expected, got unpadded hex of length ' + len);
- const array = new Uint8Array(len / 2);
- for (let i = 0; i < array.length; i++) {
- const j = i * 2;
- const hexByte = hex.slice(j, j + 2);
- const byte = Number.parseInt(hexByte, 16);
- if (Number.isNaN(byte) || byte < 0)
- throw new Error('Invalid byte sequence');
- array[i] = byte;
- }
- return array;
- }
- // BE: Big Endian, LE: Little Endian
- function bytesToNumberBE(bytes) {
- return hexToNumber(bytesToHex(bytes));
- }
- function bytesToNumberLE(bytes) {
- if (!u8a(bytes))
- throw new Error('Uint8Array expected');
- return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
- }
- function numberToBytesBE(n, len) {
- return hexToBytes(n.toString(16).padStart(len * 2, '0'));
- }
- function numberToBytesLE(n, len) {
- return numberToBytesBE(n, len).reverse();
- }
- // Unpadded, rarely used
- function numberToVarBytesBE(n) {
- return hexToBytes(numberToHexUnpadded(n));
- }
- /**
- * Takes hex string or Uint8Array, converts to Uint8Array.
- * Validates output length.
- * Will throw error for other types.
- * @param title descriptive title for an error e.g. 'private key'
- * @param hex hex string or Uint8Array
- * @param expectedLength optional, will compare to result array's length
- * @returns
- */
- function ensureBytes(title, hex, expectedLength) {
- let res;
- if (typeof hex === 'string') {
- try {
- res = hexToBytes(hex);
- }
- catch (e) {
- throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
- }
- }
- else if (u8a(hex)) {
- // Uint8Array.from() instead of hash.slice() because node.js Buffer
- // is instance of Uint8Array, and its slice() creates **mutable** copy
- res = Uint8Array.from(hex);
- }
- else {
- throw new Error(`${title} must be hex string or Uint8Array`);
- }
- const len = res.length;
- if (typeof expectedLength === 'number' && len !== expectedLength)
- throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);
- return res;
- }
- /**
- * Copies several Uint8Arrays into one.
- */
- function concatBytes(...arrays) {
- const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0));
- let pad = 0; // walk through each item, ensure they have proper type
- arrays.forEach((a) => {
- if (!u8a(a))
- throw new Error('Uint8Array expected');
- r.set(a, pad);
- pad += a.length;
- });
- return r;
- }
- function equalBytes(b1, b2) {
- // We don't care about timing attacks here
- if (b1.length !== b2.length)
- return false;
- for (let i = 0; i < b1.length; i++)
- if (b1[i] !== b2[i])
- return false;
- return true;
- }
- /**
- * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
- */
- function utf8ToBytes(str) {
- if (typeof str !== 'string')
- throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
- return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
- }
- // Bit operations
- /**
- * Calculates amount of bits in a bigint.
- * Same as `n.toString(2).length`
- */
- function bitLen(n) {
- let len;
- for (len = 0; n > _0n$3; n >>= _1n$4, len += 1)
- ;
- return len;
- }
- /**
- * Gets single bit at position.
- * NOTE: first bit position is 0 (same as arrays)
- * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
- */
- function bitGet(n, pos) {
- return (n >> BigInt(pos)) & _1n$4;
- }
- /**
- * Sets single bit at position.
- */
- const bitSet = (n, pos, value) => {
- return n | ((value ? _1n$4 : _0n$3) << BigInt(pos));
- };
- /**
- * Calculate mask for N bits. Not using ** operator with bigints because of old engines.
- * Same as BigInt(`0b${Array(i).fill('1').join('')}`)
- */
- const bitMask = (n) => (_2n$2 << BigInt(n - 1)) - _1n$4;
- // DRBG
- const u8n = (data) => new Uint8Array(data); // creates Uint8Array
- const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
- /**
- * Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
- * @returns function that will call DRBG until 2nd arg returns something meaningful
- * @example
- * const drbg = createHmacDRBG<Key>(32, 32, hmac);
- * drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
- */
- function createHmacDrbg(hashLen, qByteLen, hmacFn) {
- if (typeof hashLen !== 'number' || hashLen < 2)
- throw new Error('hashLen must be a number');
- if (typeof qByteLen !== 'number' || qByteLen < 2)
- throw new Error('qByteLen must be a number');
- if (typeof hmacFn !== 'function')
- throw new Error('hmacFn must be a function');
- // Step B, Step C: set hashLen to 8*ceil(hlen/8)
- let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
- let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
- let i = 0; // Iterations counter, will throw when over 1000
- const reset = () => {
- v.fill(1);
- k.fill(0);
- i = 0;
- };
- const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
- const reseed = (seed = u8n()) => {
- // HMAC-DRBG reseed() function. Steps D-G
- k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
- v = h(); // v = hmac(k || v)
- if (seed.length === 0)
- return;
- k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
- v = h(); // v = hmac(k || v)
- };
- const gen = () => {
- // HMAC-DRBG generate() function
- if (i++ >= 1000)
- throw new Error('drbg: tried 1000 values');
- let len = 0;
- const out = [];
- while (len < qByteLen) {
- v = h();
- const sl = v.slice();
- out.push(sl);
- len += v.length;
- }
- return concatBytes(...out);
- };
- const genUntil = (seed, pred) => {
- reset();
- reseed(seed); // Steps D-G
- let res = undefined; // Step H: grind until k is in [1..n-1]
- while (!(res = pred(gen())))
- reseed();
- reset();
- return res;
- };
- return genUntil;
- }
- // Validating curves and fields
- const validatorFns = {
- bigint: (val) => typeof val === 'bigint',
- function: (val) => typeof val === 'function',
- boolean: (val) => typeof val === 'boolean',
- string: (val) => typeof val === 'string',
- stringOrUint8Array: (val) => typeof val === 'string' || val instanceof Uint8Array,
- isSafeInteger: (val) => Number.isSafeInteger(val),
- array: (val) => Array.isArray(val),
- field: (val, object) => object.Fp.isValid(val),
- hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
- };
- // type Record<K extends string | number | symbol, T> = { [P in K]: T; }
- function validateObject(object, validators, optValidators = {}) {
- const checkField = (fieldName, type, isOptional) => {
- const checkVal = validatorFns[type];
- if (typeof checkVal !== 'function')
- throw new Error(`Invalid validator "${type}", expected function`);
- const val = object[fieldName];
- if (isOptional && val === undefined)
- return;
- if (!checkVal(val, object)) {
- throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
- }
- };
- for (const [fieldName, type] of Object.entries(validators))
- checkField(fieldName, type, false);
- for (const [fieldName, type] of Object.entries(optValidators))
- checkField(fieldName, type, true);
- return object;
- }
- // validate type tests
- // const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
- // const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
- // // Should fail type-check
- // const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
- // const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
- // const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
- // const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
- var ut = /*#__PURE__*/Object.freeze({
- __proto__: null,
- bitGet: bitGet,
- bitLen: bitLen,
- bitMask: bitMask,
- bitSet: bitSet,
- bytesToHex: bytesToHex,
- bytesToNumberBE: bytesToNumberBE,
- bytesToNumberLE: bytesToNumberLE,
- concatBytes: concatBytes,
- createHmacDrbg: createHmacDrbg,
- ensureBytes: ensureBytes,
- equalBytes: equalBytes,
- hexToBytes: hexToBytes,
- hexToNumber: hexToNumber,
- numberToBytesBE: numberToBytesBE,
- numberToBytesLE: numberToBytesLE,
- numberToHexUnpadded: numberToHexUnpadded,
- numberToVarBytesBE: numberToVarBytesBE,
- utf8ToBytes: utf8ToBytes,
- validateObject: validateObject
- });
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // Utilities for modular arithmetics and finite fields
- // prettier-ignore
- const _0n$2 = BigInt(0), _1n$3 = BigInt(1), _2n$1 = BigInt(2), _3n$1 = BigInt(3);
- // prettier-ignore
- const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
- // prettier-ignore
- BigInt(9); BigInt(16);
- // Calculates a modulo b
- function mod(a, b) {
- const result = a % b;
- return result >= _0n$2 ? result : b + result;
- }
- /**
- * Efficiently raise num to power and do modular division.
- * Unsafe in some contexts: uses ladder, so can expose bigint bits.
- * @example
- * pow(2n, 6n, 11n) // 64n % 11n == 9n
- */
- // TODO: use field version && remove
- function pow(num, power, modulo) {
- if (modulo <= _0n$2 || power < _0n$2)
- throw new Error('Expected power/modulo > 0');
- if (modulo === _1n$3)
- return _0n$2;
- let res = _1n$3;
- while (power > _0n$2) {
- if (power & _1n$3)
- res = (res * num) % modulo;
- num = (num * num) % modulo;
- power >>= _1n$3;
- }
- return res;
- }
- // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
- function pow2(x, power, modulo) {
- let res = x;
- while (power-- > _0n$2) {
- res *= res;
- res %= modulo;
- }
- return res;
- }
- // Inverses number over modulo
- function invert(number, modulo) {
- if (number === _0n$2 || modulo <= _0n$2) {
- throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
- }
- // Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
- // Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
- let a = mod(number, modulo);
- let b = modulo;
- // prettier-ignore
- let x = _0n$2, u = _1n$3;
- while (a !== _0n$2) {
- // JIT applies optimization if those two lines follow each other
- const q = b / a;
- const r = b % a;
- const m = x - u * q;
- // prettier-ignore
- b = a, a = r, x = u, u = m;
- }
- const gcd = b;
- if (gcd !== _1n$3)
- throw new Error('invert: does not exist');
- return mod(x, modulo);
- }
- /**
- * Tonelli-Shanks square root search algorithm.
- * 1. https://eprint.iacr.org/2012/685.pdf (page 12)
- * 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
- * Will start an infinite loop if field order P is not prime.
- * @param P field order
- * @returns function that takes field Fp (created from P) and number n
- */
- function tonelliShanks(P) {
- // Legendre constant: used to calculate Legendre symbol (a | p),
- // which denotes the value of a^((p-1)/2) (mod p).
- // (a | p) ≡ 1 if a is a square (mod p)
- // (a | p) ≡ -1 if a is not a square (mod p)
- // (a | p) ≡ 0 if a ≡ 0 (mod p)
- const legendreC = (P - _1n$3) / _2n$1;
- let Q, S, Z;
- // Step 1: By factoring out powers of 2 from p - 1,
- // find q and s such that p - 1 = q*(2^s) with q odd
- for (Q = P - _1n$3, S = 0; Q % _2n$1 === _0n$2; Q /= _2n$1, S++)
- ;
- // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
- for (Z = _2n$1; Z < P && pow(Z, legendreC, P) !== P - _1n$3; Z++)
- ;
- // Fast-path
- if (S === 1) {
- const p1div4 = (P + _1n$3) / _4n;
- return function tonelliFast(Fp, n) {
- const root = Fp.pow(n, p1div4);
- if (!Fp.eql(Fp.sqr(root), n))
- throw new Error('Cannot find square root');
- return root;
- };
- }
- // Slow-path
- const Q1div2 = (Q + _1n$3) / _2n$1;
- return function tonelliSlow(Fp, n) {
- // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
- if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
- throw new Error('Cannot find square root');
- let r = S;
- // TODO: will fail at Fp2/etc
- let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
- let x = Fp.pow(n, Q1div2); // first guess at the square root
- let b = Fp.pow(n, Q); // first guess at the fudge factor
- while (!Fp.eql(b, Fp.ONE)) {
- if (Fp.eql(b, Fp.ZERO))
- return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
- // Find m such b^(2^m)==1
- let m = 1;
- for (let t2 = Fp.sqr(b); m < r; m++) {
- if (Fp.eql(t2, Fp.ONE))
- break;
- t2 = Fp.sqr(t2); // t2 *= t2
- }
- // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
- const ge = Fp.pow(g, _1n$3 << BigInt(r - m - 1)); // ge = 2^(r-m-1)
- g = Fp.sqr(ge); // g = ge * ge
- x = Fp.mul(x, ge); // x *= ge
- b = Fp.mul(b, g); // b *= g
- r = m;
- }
- return x;
- };
- }
- function FpSqrt(P) {
- // NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
- // For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
- // P ≡ 3 (mod 4)
- // √n = n^((P+1)/4)
- if (P % _4n === _3n$1) {
- // Not all roots possible!
- // const ORDER =
- // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
- // const NUM = 72057594037927816n;
- const p1div4 = (P + _1n$3) / _4n;
- return function sqrt3mod4(Fp, n) {
- const root = Fp.pow(n, p1div4);
- // Throw if root**2 != n
- if (!Fp.eql(Fp.sqr(root), n))
- throw new Error('Cannot find square root');
- return root;
- };
- }
- // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
- if (P % _8n === _5n) {
- const c1 = (P - _5n) / _8n;
- return function sqrt5mod8(Fp, n) {
- const n2 = Fp.mul(n, _2n$1);
- const v = Fp.pow(n2, c1);
- const nv = Fp.mul(n, v);
- const i = Fp.mul(Fp.mul(nv, _2n$1), v);
- const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
- if (!Fp.eql(Fp.sqr(root), n))
- throw new Error('Cannot find square root');
- return root;
- };
- }
- // Other cases: Tonelli-Shanks algorithm
- return tonelliShanks(P);
- }
- // prettier-ignore
- const FIELD_FIELDS = [
- 'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
- 'eql', 'add', 'sub', 'mul', 'pow', 'div',
- 'addN', 'subN', 'mulN', 'sqrN'
- ];
- function validateField(field) {
- const initial = {
- ORDER: 'bigint',
- MASK: 'bigint',
- BYTES: 'isSafeInteger',
- BITS: 'isSafeInteger',
- };
- const opts = FIELD_FIELDS.reduce((map, val) => {
- map[val] = 'function';
- return map;
- }, initial);
- return validateObject(field, opts);
- }
- // Generic field functions
- /**
- * Same as `pow` but for Fp: non-constant-time.
- * Unsafe in some contexts: uses ladder, so can expose bigint bits.
- */
- function FpPow(f, num, power) {
- // Should have same speed as pow for bigints
- // TODO: benchmark!
- if (power < _0n$2)
- throw new Error('Expected power > 0');
- if (power === _0n$2)
- return f.ONE;
- if (power === _1n$3)
- return num;
- let p = f.ONE;
- let d = num;
- while (power > _0n$2) {
- if (power & _1n$3)
- p = f.mul(p, d);
- d = f.sqr(d);
- power >>= _1n$3;
- }
- return p;
- }
- /**
- * Efficiently invert an array of Field elements.
- * `inv(0)` will return `undefined` here: make sure to throw an error.
- */
- function FpInvertBatch(f, nums) {
- const tmp = new Array(nums.length);
- // Walk from first to last, multiply them by each other MOD p
- const lastMultiplied = nums.reduce((acc, num, i) => {
- if (f.is0(num))
- return acc;
- tmp[i] = acc;
- return f.mul(acc, num);
- }, f.ONE);
- // Invert last element
- const inverted = f.inv(lastMultiplied);
- // Walk from last to first, multiply them by inverted each other MOD p
- nums.reduceRight((acc, num, i) => {
- if (f.is0(num))
- return acc;
- tmp[i] = f.mul(acc, tmp[i]);
- return f.mul(acc, num);
- }, inverted);
- return tmp;
- }
- // CURVE.n lengths
- function nLength(n, nBitLength) {
- // Bit size, byte size of CURVE.n
- const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
- const nByteLength = Math.ceil(_nBitLength / 8);
- return { nBitLength: _nBitLength, nByteLength };
- }
- /**
- * Initializes a finite field over prime. **Non-primes are not supported.**
- * Do not init in loop: slow. Very fragile: always run a benchmark on a change.
- * Major performance optimizations:
- * * a) denormalized operations like mulN instead of mul
- * * b) same object shape: never add or remove keys
- * * c) Object.freeze
- * @param ORDER prime positive bigint
- * @param bitLen how many bits the field consumes
- * @param isLE (def: false) if encoding / decoding should be in little-endian
- * @param redef optional faster redefinitions of sqrt and other methods
- */
- function Field(ORDER, bitLen, isLE = false, redef = {}) {
- if (ORDER <= _0n$2)
- throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
- const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
- if (BYTES > 2048)
- throw new Error('Field lengths over 2048 bytes are not supported');
- const sqrtP = FpSqrt(ORDER);
- const f = Object.freeze({
- ORDER,
- BITS,
- BYTES,
- MASK: bitMask(BITS),
- ZERO: _0n$2,
- ONE: _1n$3,
- create: (num) => mod(num, ORDER),
- isValid: (num) => {
- if (typeof num !== 'bigint')
- throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
- return _0n$2 <= num && num < ORDER; // 0 is valid element, but it's not invertible
- },
- is0: (num) => num === _0n$2,
- isOdd: (num) => (num & _1n$3) === _1n$3,
- neg: (num) => mod(-num, ORDER),
- eql: (lhs, rhs) => lhs === rhs,
- sqr: (num) => mod(num * num, ORDER),
- add: (lhs, rhs) => mod(lhs + rhs, ORDER),
- sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
- mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
- pow: (num, power) => FpPow(f, num, power),
- div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
- // Same as above, but doesn't normalize
- sqrN: (num) => num * num,
- addN: (lhs, rhs) => lhs + rhs,
- subN: (lhs, rhs) => lhs - rhs,
- mulN: (lhs, rhs) => lhs * rhs,
- inv: (num) => invert(num, ORDER),
- sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
- invertBatch: (lst) => FpInvertBatch(f, lst),
- // TODO: do we really need constant cmov?
- // We don't have const-time bigints anyway, so probably will be not very useful
- cmov: (a, b, c) => (c ? b : a),
- toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
- fromBytes: (bytes) => {
- if (bytes.length !== BYTES)
- throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
- return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
- },
- });
- return Object.freeze(f);
- }
- /**
- * Returns total number of bytes consumed by the field element.
- * For example, 32 bytes for usual 256-bit weierstrass curve.
- * @param fieldOrder number of field elements, usually CURVE.n
- * @returns byte length of field
- */
- function getFieldBytesLength(fieldOrder) {
- if (typeof fieldOrder !== 'bigint')
- throw new Error('field order must be bigint');
- const bitLength = fieldOrder.toString(2).length;
- return Math.ceil(bitLength / 8);
- }
- /**
- * Returns minimal amount of bytes that can be safely reduced
- * by field order.
- * Should be 2^-128 for 128-bit curve such as P256.
- * @param fieldOrder number of field elements, usually CURVE.n
- * @returns byte length of target hash
- */
- function getMinHashLength(fieldOrder) {
- const length = getFieldBytesLength(fieldOrder);
- return length + Math.ceil(length / 2);
- }
- /**
- * "Constant-time" private key generation utility.
- * Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
- * and convert them into private scalar, with the modulo bias being negligible.
- * Needs at least 48 bytes of input for 32-byte private key.
- * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
- * FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
- * RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
- * @param hash hash output from SHA3 or a similar function
- * @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
- * @param isLE interpret hash bytes as LE num
- * @returns valid private scalar
- */
- function mapHashToField(key, fieldOrder, isLE = false) {
- const len = key.length;
- const fieldLen = getFieldBytesLength(fieldOrder);
- const minLen = getMinHashLength(fieldOrder);
- // No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
- if (len < 16 || len < minLen || len > 1024)
- throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
- const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
- // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
- const reduced = mod(num, fieldOrder - _1n$3) + _1n$3;
- return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
- }
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // Abelian group utilities
- const _0n$1 = BigInt(0);
- const _1n$2 = BigInt(1);
- // Elliptic curve multiplication of Point by scalar. Fragile.
- // Scalars should always be less than curve order: this should be checked inside of a curve itself.
- // Creates precomputation tables for fast multiplication:
- // - private scalar is split by fixed size windows of W bits
- // - every window point is collected from window's table & added to accumulator
- // - since windows are different, same point inside tables won't be accessed more than once per calc
- // - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
- // - +1 window is neccessary for wNAF
- // - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
- // TODO: Research returning 2d JS array of windows, instead of a single window. This would allow
- // windows to be in different memory locations
- function wNAF(c, bits) {
- const constTimeNegate = (condition, item) => {
- const neg = item.negate();
- return condition ? neg : item;
- };
- const opts = (W) => {
- const windows = Math.ceil(bits / W) + 1; // +1, because
- const windowSize = 2 ** (W - 1); // -1 because we skip zero
- return { windows, windowSize };
- };
- return {
- constTimeNegate,
- // non-const time multiplication ladder
- unsafeLadder(elm, n) {
- let p = c.ZERO;
- let d = elm;
- while (n > _0n$1) {
- if (n & _1n$2)
- p = p.add(d);
- d = d.double();
- n >>= _1n$2;
- }
- return p;
- },
- /**
- * Creates a wNAF precomputation window. Used for caching.
- * Default window size is set by `utils.precompute()` and is equal to 8.
- * Number of precomputed points depends on the curve size:
- * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
- * - 𝑊 is the window size
- * - 𝑛 is the bitlength of the curve order.
- * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
- * @returns precomputed point tables flattened to a single array
- */
- precomputeWindow(elm, W) {
- const { windows, windowSize } = opts(W);
- const points = [];
- let p = elm;
- let base = p;
- for (let window = 0; window < windows; window++) {
- base = p;
- points.push(base);
- // =1, because we skip zero
- for (let i = 1; i < windowSize; i++) {
- base = base.add(p);
- points.push(base);
- }
- p = base.double();
- }
- return points;
- },
- /**
- * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
- * @param W window size
- * @param precomputes precomputed tables
- * @param n scalar (we don't check here, but should be less than curve order)
- * @returns real and fake (for const-time) points
- */
- wNAF(W, precomputes, n) {
- // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise
- // But need to carefully remove other checks before wNAF. ORDER == bits here
- const { windows, windowSize } = opts(W);
- let p = c.ZERO;
- let f = c.BASE;
- const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.
- const maxNumber = 2 ** W;
- const shiftBy = BigInt(W);
- for (let window = 0; window < windows; window++) {
- const offset = window * windowSize;
- // Extract W bits.
- let wbits = Number(n & mask);
- // Shift number by W bits.
- n >>= shiftBy;
- // If the bits are bigger than max size, we'll split those.
- // +224 => 256 - 32
- if (wbits > windowSize) {
- wbits -= maxNumber;
- n += _1n$2;
- }
- // This code was first written with assumption that 'f' and 'p' will never be infinity point:
- // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
- // there is negate now: it is possible that negated element from low value
- // would be the same as high element, which will create carry into next window.
- // It's not obvious how this can fail, but still worth investigating later.
- // Check if we're onto Zero point.
- // Add random point inside current window to f.
- const offset1 = offset;
- const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero
- const cond1 = window % 2 !== 0;
- const cond2 = wbits < 0;
- if (wbits === 0) {
- // The most important part for const-time getPublicKey
- f = f.add(constTimeNegate(cond1, precomputes[offset1]));
- }
- else {
- p = p.add(constTimeNegate(cond2, precomputes[offset2]));
- }
- }
- // JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()
- // Even if the variable is still unused, there are some checks which will
- // throw an exception, so compiler needs to prove they won't happen, which is hard.
- // At this point there is a way to F be infinity-point even if p is not,
- // which makes it less const-time: around 1 bigint multiply.
- return { p, f };
- },
- wNAFCached(P, precomputesMap, n, transform) {
- // @ts-ignore
- const W = P._WINDOW_SIZE || 1;
- // Calculate precomputes on a first run, reuse them after
- let comp = precomputesMap.get(P);
- if (!comp) {
- comp = this.precomputeWindow(P, W);
- if (W !== 1) {
- precomputesMap.set(P, transform(comp));
- }
- }
- return this.wNAF(W, comp, n);
- },
- };
- }
- function validateBasic(curve) {
- validateField(curve.Fp);
- validateObject(curve, {
- n: 'bigint',
- h: 'bigint',
- Gx: 'field',
- Gy: 'field',
- }, {
- nBitLength: 'isSafeInteger',
- nByteLength: 'isSafeInteger',
- });
- // Set defaults
- return Object.freeze({
- ...nLength(curve.n, curve.nBitLength),
- ...curve,
- ...{ p: curve.Fp.ORDER },
- });
- }
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // Short Weierstrass curve. The formula is: y² = x³ + ax + b
- function validatePointOpts(curve) {
- const opts = validateBasic(curve);
- validateObject(opts, {
- a: 'field',
- b: 'field',
- }, {
- allowedPrivateKeyLengths: 'array',
- wrapPrivateKey: 'boolean',
- isTorsionFree: 'function',
- clearCofactor: 'function',
- allowInfinityPoint: 'boolean',
- fromBytes: 'function',
- toBytes: 'function',
- });
- const { endo, Fp, a } = opts;
- if (endo) {
- if (!Fp.eql(a, Fp.ZERO)) {
- throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
- }
- if (typeof endo !== 'object' ||
- typeof endo.beta !== 'bigint' ||
- typeof endo.splitScalar !== 'function') {
- throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
- }
- }
- return Object.freeze({ ...opts });
- }
- // ASN.1 DER encoding utilities
- const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
- const DER = {
- // asn.1 DER encoding utils
- Err: class DERErr extends Error {
- constructor(m = '') {
- super(m);
- }
- },
- _parseInt(data) {
- const { Err: E } = DER;
- if (data.length < 2 || data[0] !== 0x02)
- throw new E('Invalid signature integer tag');
- const len = data[1];
- const res = data.subarray(2, len + 2);
- if (!len || res.length !== len)
- throw new E('Invalid signature integer: wrong length');
- // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
- // since we always use positive integers here. It must always be empty:
- // - add zero byte if exists
- // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
- if (res[0] & 0b10000000)
- throw new E('Invalid signature integer: negative');
- if (res[0] === 0x00 && !(res[1] & 0b10000000))
- throw new E('Invalid signature integer: unnecessary leading zero');
- return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
- },
- toSig(hex) {
- // parse DER signature
- const { Err: E } = DER;
- const data = typeof hex === 'string' ? h2b(hex) : hex;
- if (!(data instanceof Uint8Array))
- throw new Error('ui8a expected');
- let l = data.length;
- if (l < 2 || data[0] != 0x30)
- throw new E('Invalid signature tag');
- if (data[1] !== l - 2)
- throw new E('Invalid signature: incorrect length');
- const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
- const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
- if (rBytesLeft.length)
- throw new E('Invalid signature: left bytes after parsing');
- return { r, s };
- },
- hexFromSig(sig) {
- // Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
- const slice = (s) => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
- const h = (num) => {
- const hex = num.toString(16);
- return hex.length & 1 ? `0${hex}` : hex;
- };
- const s = slice(h(sig.s));
- const r = slice(h(sig.r));
- const shl = s.length / 2;
- const rhl = r.length / 2;
- const sl = h(shl);
- const rl = h(rhl);
- return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
- },
- };
- // Be friendly to bad ECMAScript parsers by not using bigint literals
- // prettier-ignore
- const _0n = BigInt(0), _1n$1 = BigInt(1); BigInt(2); const _3n = BigInt(3); BigInt(4);
- function weierstrassPoints(opts) {
- const CURVE = validatePointOpts(opts);
- const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
- const toBytes = CURVE.toBytes ||
- ((_c, point, _isCompressed) => {
- const a = point.toAffine();
- return concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
- });
- const fromBytes = CURVE.fromBytes ||
- ((bytes) => {
- // const head = bytes[0];
- const tail = bytes.subarray(1);
- // if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');
- const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
- const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
- return { x, y };
- });
- /**
- * y² = x³ + ax + b: Short weierstrass curve formula
- * @returns y²
- */
- function weierstrassEquation(x) {
- const { a, b } = CURVE;
- const x2 = Fp.sqr(x); // x * x
- const x3 = Fp.mul(x2, x); // x2 * x
- return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
- }
- // Validate whether the passed curve params are valid.
- // We check if curve equation works for generator point.
- // `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
- // ProjectivePoint class has not been initialized yet.
- if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
- throw new Error('bad generator point: equation left != right');
- // Valid group elements reside in range 1..n-1
- function isWithinCurveOrder(num) {
- return typeof num === 'bigint' && _0n < num && num < CURVE.n;
- }
- function assertGE(num) {
- if (!isWithinCurveOrder(num))
- throw new Error('Expected valid bigint: 0 < bigint < curve.n');
- }
- // Validates if priv key is valid and converts it to bigint.
- // Supports options allowedPrivateKeyLengths and wrapPrivateKey.
- function normPrivateKeyToScalar(key) {
- const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
- if (lengths && typeof key !== 'bigint') {
- if (key instanceof Uint8Array)
- key = bytesToHex(key);
- // Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
- if (typeof key !== 'string' || !lengths.includes(key.length))
- throw new Error('Invalid key');
- key = key.padStart(nByteLength * 2, '0');
- }
- let num;
- try {
- num =
- typeof key === 'bigint'
- ? key
- : bytesToNumberBE(ensureBytes('private key', key, nByteLength));
- }
- catch (error) {
- throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
- }
- if (wrapPrivateKey)
- num = mod(num, n); // disabled by default, enabled for BLS
- assertGE(num); // num in range [1..N-1]
- return num;
- }
- const pointPrecomputes = new Map();
- function assertPrjPoint(other) {
- if (!(other instanceof Point))
- throw new Error('ProjectivePoint expected');
- }
- /**
- * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
- * Default Point works in 2d / affine coordinates: (x, y)
- * We're doing calculations in projective, because its operations don't require costly inversion.
- */
- class Point {
- constructor(px, py, pz) {
- this.px = px;
- this.py = py;
- this.pz = pz;
- if (px == null || !Fp.isValid(px))
- throw new Error('x required');
- if (py == null || !Fp.isValid(py))
- throw new Error('y required');
- if (pz == null || !Fp.isValid(pz))
- throw new Error('z required');
- }
- // Does not validate if the point is on-curve.
- // Use fromHex instead, or call assertValidity() later.
- static fromAffine(p) {
- const { x, y } = p || {};
- if (!p || !Fp.isValid(x) || !Fp.isValid(y))
- throw new Error('invalid affine point');
- if (p instanceof Point)
- throw new Error('projective point not allowed');
- const is0 = (i) => Fp.eql(i, Fp.ZERO);
- // fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
- if (is0(x) && is0(y))
- return Point.ZERO;
- return new Point(x, y, Fp.ONE);
- }
- get x() {
- return this.toAffine().x;
- }
- get y() {
- return this.toAffine().y;
- }
- /**
- * Takes a bunch of Projective Points but executes only one
- * inversion on all of them. Inversion is very slow operation,
- * so this improves performance massively.
- * Optimization: converts a list of projective points to a list of identical points with Z=1.
- */
- static normalizeZ(points) {
- const toInv = Fp.invertBatch(points.map((p) => p.pz));
- return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
- }
- /**
- * Converts hash string or Uint8Array to Point.
- * @param hex short/long ECDSA hex
- */
- static fromHex(hex) {
- const P = Point.fromAffine(fromBytes(ensureBytes('pointHex', hex)));
- P.assertValidity();
- return P;
- }
- // Multiplies generator point by privateKey.
- static fromPrivateKey(privateKey) {
- return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
- }
- // "Private method", don't use it directly
- _setWindowSize(windowSize) {
- this._WINDOW_SIZE = windowSize;
- pointPrecomputes.delete(this);
- }
- // A point on curve is valid if it conforms to equation.
- assertValidity() {
- if (this.is0()) {
- // (0, 1, 0) aka ZERO is invalid in most contexts.
- // In BLS, ZERO can be serialized, so we allow it.
- // (0, 0, 0) is wrong representation of ZERO and is always invalid.
- if (CURVE.allowInfinityPoint && !Fp.is0(this.py))
- return;
- throw new Error('bad point: ZERO');
- }
- // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
- const { x, y } = this.toAffine();
- // Check if x, y are valid field elements
- if (!Fp.isValid(x) || !Fp.isValid(y))
- throw new Error('bad point: x or y not FE');
- const left = Fp.sqr(y); // y²
- const right = weierstrassEquation(x); // x³ + ax + b
- if (!Fp.eql(left, right))
- throw new Error('bad point: equation left != right');
- if (!this.isTorsionFree())
- throw new Error('bad point: not in prime-order subgroup');
- }
- hasEvenY() {
- const { y } = this.toAffine();
- if (Fp.isOdd)
- return !Fp.isOdd(y);
- throw new Error("Field doesn't support isOdd");
- }
- /**
- * Compare one point to another.
- */
- equals(other) {
- assertPrjPoint(other);
- const { px: X1, py: Y1, pz: Z1 } = this;
- const { px: X2, py: Y2, pz: Z2 } = other;
- const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
- const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
- return U1 && U2;
- }
- /**
- * Flips point to one corresponding to (x, -y) in Affine coordinates.
- */
- negate() {
- return new Point(this.px, Fp.neg(this.py), this.pz);
- }
- // Renes-Costello-Batina exception-free doubling formula.
- // There is 30% faster Jacobian formula, but it is not complete.
- // https://eprint.iacr.org/2015/1060, algorithm 3
- // Cost: 8M + 3S + 3*a + 2*b3 + 15add.
- double() {
- const { a, b } = CURVE;
- const b3 = Fp.mul(b, _3n);
- const { px: X1, py: Y1, pz: Z1 } = this;
- let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
- let t0 = Fp.mul(X1, X1); // step 1
- let t1 = Fp.mul(Y1, Y1);
- let t2 = Fp.mul(Z1, Z1);
- let t3 = Fp.mul(X1, Y1);
- t3 = Fp.add(t3, t3); // step 5
- Z3 = Fp.mul(X1, Z1);
- Z3 = Fp.add(Z3, Z3);
- X3 = Fp.mul(a, Z3);
- Y3 = Fp.mul(b3, t2);
- Y3 = Fp.add(X3, Y3); // step 10
- X3 = Fp.sub(t1, Y3);
- Y3 = Fp.add(t1, Y3);
- Y3 = Fp.mul(X3, Y3);
- X3 = Fp.mul(t3, X3);
- Z3 = Fp.mul(b3, Z3); // step 15
- t2 = Fp.mul(a, t2);
- t3 = Fp.sub(t0, t2);
- t3 = Fp.mul(a, t3);
- t3 = Fp.add(t3, Z3);
- Z3 = Fp.add(t0, t0); // step 20
- t0 = Fp.add(Z3, t0);
- t0 = Fp.add(t0, t2);
- t0 = Fp.mul(t0, t3);
- Y3 = Fp.add(Y3, t0);
- t2 = Fp.mul(Y1, Z1); // step 25
- t2 = Fp.add(t2, t2);
- t0 = Fp.mul(t2, t3);
- X3 = Fp.sub(X3, t0);
- Z3 = Fp.mul(t2, t1);
- Z3 = Fp.add(Z3, Z3); // step 30
- Z3 = Fp.add(Z3, Z3);
- return new Point(X3, Y3, Z3);
- }
- // Renes-Costello-Batina exception-free addition formula.
- // There is 30% faster Jacobian formula, but it is not complete.
- // https://eprint.iacr.org/2015/1060, algorithm 1
- // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
- add(other) {
- assertPrjPoint(other);
- const { px: X1, py: Y1, pz: Z1 } = this;
- const { px: X2, py: Y2, pz: Z2 } = other;
- let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
- const a = CURVE.a;
- const b3 = Fp.mul(CURVE.b, _3n);
- let t0 = Fp.mul(X1, X2); // step 1
- let t1 = Fp.mul(Y1, Y2);
- let t2 = Fp.mul(Z1, Z2);
- let t3 = Fp.add(X1, Y1);
- let t4 = Fp.add(X2, Y2); // step 5
- t3 = Fp.mul(t3, t4);
- t4 = Fp.add(t0, t1);
- t3 = Fp.sub(t3, t4);
- t4 = Fp.add(X1, Z1);
- let t5 = Fp.add(X2, Z2); // step 10
- t4 = Fp.mul(t4, t5);
- t5 = Fp.add(t0, t2);
- t4 = Fp.sub(t4, t5);
- t5 = Fp.add(Y1, Z1);
- X3 = Fp.add(Y2, Z2); // step 15
- t5 = Fp.mul(t5, X3);
- X3 = Fp.add(t1, t2);
- t5 = Fp.sub(t5, X3);
- Z3 = Fp.mul(a, t4);
- X3 = Fp.mul(b3, t2); // step 20
- Z3 = Fp.add(X3, Z3);
- X3 = Fp.sub(t1, Z3);
- Z3 = Fp.add(t1, Z3);
- Y3 = Fp.mul(X3, Z3);
- t1 = Fp.add(t0, t0); // step 25
- t1 = Fp.add(t1, t0);
- t2 = Fp.mul(a, t2);
- t4 = Fp.mul(b3, t4);
- t1 = Fp.add(t1, t2);
- t2 = Fp.sub(t0, t2); // step 30
- t2 = Fp.mul(a, t2);
- t4 = Fp.add(t4, t2);
- t0 = Fp.mul(t1, t4);
- Y3 = Fp.add(Y3, t0);
- t0 = Fp.mul(t5, t4); // step 35
- X3 = Fp.mul(t3, X3);
- X3 = Fp.sub(X3, t0);
- t0 = Fp.mul(t3, t1);
- Z3 = Fp.mul(t5, Z3);
- Z3 = Fp.add(Z3, t0); // step 40
- return new Point(X3, Y3, Z3);
- }
- subtract(other) {
- return this.add(other.negate());
- }
- is0() {
- return this.equals(Point.ZERO);
- }
- wNAF(n) {
- return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
- const toInv = Fp.invertBatch(comp.map((p) => p.pz));
- return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
- });
- }
- /**
- * Non-constant-time multiplication. Uses double-and-add algorithm.
- * It's faster, but should only be used when you don't care about
- * an exposed private key e.g. sig verification, which works over *public* keys.
- */
- multiplyUnsafe(n) {
- const I = Point.ZERO;
- if (n === _0n)
- return I;
- assertGE(n); // Will throw on 0
- if (n === _1n$1)
- return this;
- const { endo } = CURVE;
- if (!endo)
- return wnaf.unsafeLadder(this, n);
- // Apply endomorphism
- let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
- let k1p = I;
- let k2p = I;
- let d = this;
- while (k1 > _0n || k2 > _0n) {
- if (k1 & _1n$1)
- k1p = k1p.add(d);
- if (k2 & _1n$1)
- k2p = k2p.add(d);
- d = d.double();
- k1 >>= _1n$1;
- k2 >>= _1n$1;
- }
- if (k1neg)
- k1p = k1p.negate();
- if (k2neg)
- k2p = k2p.negate();
- k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
- return k1p.add(k2p);
- }
- /**
- * Constant time multiplication.
- * Uses wNAF method. Windowed method may be 10% faster,
- * but takes 2x longer to generate and consumes 2x memory.
- * Uses precomputes when available.
- * Uses endomorphism for Koblitz curves.
- * @param scalar by which the point would be multiplied
- * @returns New point
- */
- multiply(scalar) {
- assertGE(scalar);
- let n = scalar;
- let point, fake; // Fake point is used to const-time mult
- const { endo } = CURVE;
- if (endo) {
- const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
- let { p: k1p, f: f1p } = this.wNAF(k1);
- let { p: k2p, f: f2p } = this.wNAF(k2);
- k1p = wnaf.constTimeNegate(k1neg, k1p);
- k2p = wnaf.constTimeNegate(k2neg, k2p);
- k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
- point = k1p.add(k2p);
- fake = f1p.add(f2p);
- }
- else {
- const { p, f } = this.wNAF(n);
- point = p;
- fake = f;
- }
- // Normalize `z` for both points, but return only real one
- return Point.normalizeZ([point, fake])[0];
- }
- /**
- * Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
- * Not using Strauss-Shamir trick: precomputation tables are faster.
- * The trick could be useful if both P and Q are not G (not in our case).
- * @returns non-zero affine point
- */
- multiplyAndAddUnsafe(Q, a, b) {
- const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
- const mul = (P, a // Select faster multiply() method
- ) => (a === _0n || a === _1n$1 || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
- const sum = mul(this, a).add(mul(Q, b));
- return sum.is0() ? undefined : sum;
- }
- // Converts Projective point to affine (x, y) coordinates.
- // Can accept precomputed Z^-1 - for example, from invertBatch.
- // (x, y, z) ∋ (x=x/z, y=y/z)
- toAffine(iz) {
- const { px: x, py: y, pz: z } = this;
- const is0 = this.is0();
- // If invZ was 0, we return zero point. However we still want to execute
- // all operations, so we replace invZ with a random number, 1.
- if (iz == null)
- iz = is0 ? Fp.ONE : Fp.inv(z);
- const ax = Fp.mul(x, iz);
- const ay = Fp.mul(y, iz);
- const zz = Fp.mul(z, iz);
- if (is0)
- return { x: Fp.ZERO, y: Fp.ZERO };
- if (!Fp.eql(zz, Fp.ONE))
- throw new Error('invZ was invalid');
- return { x: ax, y: ay };
- }
- isTorsionFree() {
- const { h: cofactor, isTorsionFree } = CURVE;
- if (cofactor === _1n$1)
- return true; // No subgroups, always torsion-free
- if (isTorsionFree)
- return isTorsionFree(Point, this);
- throw new Error('isTorsionFree() has not been declared for the elliptic curve');
- }
- clearCofactor() {
- const { h: cofactor, clearCofactor } = CURVE;
- if (cofactor === _1n$1)
- return this; // Fast-path
- if (clearCofactor)
- return clearCofactor(Point, this);
- return this.multiplyUnsafe(CURVE.h);
- }
- toRawBytes(isCompressed = true) {
- this.assertValidity();
- return toBytes(Point, this, isCompressed);
- }
- toHex(isCompressed = true) {
- return bytesToHex(this.toRawBytes(isCompressed));
- }
- }
- Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
- Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
- const _bits = CURVE.nBitLength;
- const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
- // Validate if generator point is on curve
- return {
- CURVE,
- ProjectivePoint: Point,
- normPrivateKeyToScalar,
- weierstrassEquation,
- isWithinCurveOrder,
- };
- }
- function validateOpts(curve) {
- const opts = validateBasic(curve);
- validateObject(opts, {
- hash: 'hash',
- hmac: 'function',
- randomBytes: 'function',
- }, {
- bits2int: 'function',
- bits2int_modN: 'function',
- lowS: 'boolean',
- });
- return Object.freeze({ lowS: true, ...opts });
- }
- function weierstrass(curveDef) {
- const CURVE = validateOpts(curveDef);
- const { Fp, n: CURVE_ORDER } = CURVE;
- const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
- const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
- function isValidFieldElement(num) {
- return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
- }
- function modN(a) {
- return mod(a, CURVE_ORDER);
- }
- function invN(a) {
- return invert(a, CURVE_ORDER);
- }
- const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
- ...CURVE,
- toBytes(_c, point, isCompressed) {
- const a = point.toAffine();
- const x = Fp.toBytes(a.x);
- const cat = concatBytes;
- if (isCompressed) {
- return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
- }
- else {
- return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
- }
- },
- fromBytes(bytes) {
- const len = bytes.length;
- const head = bytes[0];
- const tail = bytes.subarray(1);
- // this.assertValidity() is done inside of fromHex
- if (len === compressedLen && (head === 0x02 || head === 0x03)) {
- const x = bytesToNumberBE(tail);
- if (!isValidFieldElement(x))
- throw new Error('Point is not on curve');
- const y2 = weierstrassEquation(x); // y² = x³ + ax + b
- let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
- const isYOdd = (y & _1n$1) === _1n$1;
- // ECDSA
- const isHeadOdd = (head & 1) === 1;
- if (isHeadOdd !== isYOdd)
- y = Fp.neg(y);
- return { x, y };
- }
- else if (len === uncompressedLen && head === 0x04) {
- const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
- const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
- return { x, y };
- }
- else {
- throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
- }
- },
- });
- const numToNByteStr = (num) => bytesToHex(numberToBytesBE(num, CURVE.nByteLength));
- function isBiggerThanHalfOrder(number) {
- const HALF = CURVE_ORDER >> _1n$1;
- return number > HALF;
- }
- function normalizeS(s) {
- return isBiggerThanHalfOrder(s) ? modN(-s) : s;
- }
- // slice bytes num
- const slcNum = (b, from, to) => bytesToNumberBE(b.slice(from, to));
- /**
- * ECDSA signature with its (r, s) properties. Supports DER & compact representations.
- */
- class Signature {
- constructor(r, s, recovery) {
- this.r = r;
- this.s = s;
- this.recovery = recovery;
- this.assertValidity();
- }
- // pair (bytes of r, bytes of s)
- static fromCompact(hex) {
- const l = CURVE.nByteLength;
- hex = ensureBytes('compactSignature', hex, l * 2);
- return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
- }
- // DER encoded ECDSA signature
- // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
- static fromDER(hex) {
- const { r, s } = DER.toSig(ensureBytes('DER', hex));
- return new Signature(r, s);
- }
- assertValidity() {
- // can use assertGE here
- if (!isWithinCurveOrder(this.r))
- throw new Error('r must be 0 < r < CURVE.n');
- if (!isWithinCurveOrder(this.s))
- throw new Error('s must be 0 < s < CURVE.n');
- }
- addRecoveryBit(recovery) {
- return new Signature(this.r, this.s, recovery);
- }
- recoverPublicKey(msgHash) {
- const { r, s, recovery: rec } = this;
- const h = bits2int_modN(ensureBytes('msgHash', msgHash)); // Truncate hash
- if (rec == null || ![0, 1, 2, 3].includes(rec))
- throw new Error('recovery id invalid');
- const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
- if (radj >= Fp.ORDER)
- throw new Error('recovery id 2 or 3 invalid');
- const prefix = (rec & 1) === 0 ? '02' : '03';
- const R = Point.fromHex(prefix + numToNByteStr(radj));
- const ir = invN(radj); // r^-1
- const u1 = modN(-h * ir); // -hr^-1
- const u2 = modN(s * ir); // sr^-1
- const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
- if (!Q)
- throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
- Q.assertValidity();
- return Q;
- }
- // Signatures should be low-s, to prevent malleability.
- hasHighS() {
- return isBiggerThanHalfOrder(this.s);
- }
- normalizeS() {
- return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
- }
- // DER-encoded
- toDERRawBytes() {
- return hexToBytes(this.toDERHex());
- }
- toDERHex() {
- return DER.hexFromSig({ r: this.r, s: this.s });
- }
- // padded bytes of r, then padded bytes of s
- toCompactRawBytes() {
- return hexToBytes(this.toCompactHex());
- }
- toCompactHex() {
- return numToNByteStr(this.r) + numToNByteStr(this.s);
- }
- }
- const utils = {
- isValidPrivateKey(privateKey) {
- try {
- normPrivateKeyToScalar(privateKey);
- return true;
- }
- catch (error) {
- return false;
- }
- },
- normPrivateKeyToScalar: normPrivateKeyToScalar,
- /**
- * Produces cryptographically secure private key from random of size
- * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
- */
- randomPrivateKey: () => {
- const length = getMinHashLength(CURVE.n);
- return mapHashToField(CURVE.randomBytes(length), CURVE.n);
- },
- /**
- * Creates precompute table for an arbitrary EC point. Makes point "cached".
- * Allows to massively speed-up `point.multiply(scalar)`.
- * @returns cached point
- * @example
- * const fast = utils.precompute(8, ProjectivePoint.fromHex(someonesPubKey));
- * fast.multiply(privKey); // much faster ECDH now
- */
- precompute(windowSize = 8, point = Point.BASE) {
- point._setWindowSize(windowSize);
- point.multiply(BigInt(3)); // 3 is arbitrary, just need any number here
- return point;
- },
- };
- /**
- * Computes public key for a private key. Checks for validity of the private key.
- * @param privateKey private key
- * @param isCompressed whether to return compact (default), or full key
- * @returns Public key, full when isCompressed=false; short when isCompressed=true
- */
- function getPublicKey(privateKey, isCompressed = true) {
- return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
- }
- /**
- * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
- */
- function isProbPub(item) {
- const arr = item instanceof Uint8Array;
- const str = typeof item === 'string';
- const len = (arr || str) && item.length;
- if (arr)
- return len === compressedLen || len === uncompressedLen;
- if (str)
- return len === 2 * compressedLen || len === 2 * uncompressedLen;
- if (item instanceof Point)
- return true;
- return false;
- }
- /**
- * ECDH (Elliptic Curve Diffie Hellman).
- * Computes shared public key from private key and public key.
- * Checks: 1) private key validity 2) shared key is on-curve.
- * Does NOT hash the result.
- * @param privateA private key
- * @param publicB different public key
- * @param isCompressed whether to return compact (default), or full key
- * @returns shared public key
- */
- function getSharedSecret(privateA, publicB, isCompressed = true) {
- if (isProbPub(privateA))
- throw new Error('first arg must be private key');
- if (!isProbPub(publicB))
- throw new Error('second arg must be public key');
- const b = Point.fromHex(publicB); // check for being on-curve
- return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);
- }
- // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
- // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
- // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
- // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
- const bits2int = CURVE.bits2int ||
- function (bytes) {
- // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
- // for some cases, since bytes.length * 8 is not actual bitLength.
- const num = bytesToNumberBE(bytes); // check for == u8 done here
- const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
- return delta > 0 ? num >> BigInt(delta) : num;
- };
- const bits2int_modN = CURVE.bits2int_modN ||
- function (bytes) {
- return modN(bits2int(bytes)); // can't use bytesToNumberBE here
- };
- // NOTE: pads output with zero as per spec
- const ORDER_MASK = bitMask(CURVE.nBitLength);
- /**
- * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
- */
- function int2octets(num) {
- if (typeof num !== 'bigint')
- throw new Error('bigint expected');
- if (!(_0n <= num && num < ORDER_MASK))
- throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
- // works with order, can have different size than numToField!
- return numberToBytesBE(num, CURVE.nByteLength);
- }
- // Steps A, D of RFC6979 3.2
- // Creates RFC6979 seed; converts msg/privKey to numbers.
- // Used only in sign, not in verify.
- // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
- // Also it can be bigger for P224 + SHA256
- function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
- if (['recovered', 'canonical'].some((k) => k in opts))
- throw new Error('sign() legacy options not supported');
- const { hash, randomBytes } = CURVE;
- let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
- if (lowS == null)
- lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
- msgHash = ensureBytes('msgHash', msgHash);
- if (prehash)
- msgHash = ensureBytes('prehashed msgHash', hash(msgHash));
- // We can't later call bits2octets, since nested bits2int is broken for curves
- // with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
- // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
- const h1int = bits2int_modN(msgHash);
- const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint
- const seedArgs = [int2octets(d), int2octets(h1int)];
- // extraEntropy. RFC6979 3.6: additional k' (optional).
- if (ent != null) {
- // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
- const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
- seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
- }
- const seed = concatBytes(...seedArgs); // Step D of RFC6979 3.2
- const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
- // Converts signature params into point w r/s, checks result for validity.
- function k2sig(kBytes) {
- // RFC 6979 Section 3.2, step 3: k = bits2int(T)
- const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
- if (!isWithinCurveOrder(k))
- return; // Important: all mod() calls here must be done over N
- const ik = invN(k); // k^-1 mod n
- const q = Point.BASE.multiply(k).toAffine(); // q = Gk
- const r = modN(q.x); // r = q.x mod n
- if (r === _0n)
- return;
- // Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
- // https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
- // a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
- const s = modN(ik * modN(m + r * d)); // Not using blinding here
- if (s === _0n)
- return;
- let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n$1); // recovery bit (2 or 3, when q.x > n)
- let normS = s;
- if (lowS && isBiggerThanHalfOrder(s)) {
- normS = normalizeS(s); // if lowS was passed, ensure s is always
- recovery ^= 1; // // in the bottom half of N
- }
- return new Signature(r, normS, recovery); // use normS, not s
- }
- return { seed, k2sig };
- }
- const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
- const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
- /**
- * Signs message hash with a private key.
- * ```
- * sign(m, d, k) where
- * (x, y) = G × k
- * r = x mod n
- * s = (m + dr)/k mod n
- * ```
- * @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
- * @param privKey private key
- * @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
- * @returns signature with recovery param
- */
- function sign(msgHash, privKey, opts = defaultSigOpts) {
- const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
- const C = CURVE;
- const drbg = createHmacDrbg(C.hash.outputLen, C.nByteLength, C.hmac);
- return drbg(seed, k2sig); // Steps B, C, D, E, F, G
- }
- // Enable precomputes. Slows down first publicKey computation by 20ms.
- Point.BASE._setWindowSize(8);
- // utils.precompute(8, ProjectivePoint.BASE)
- /**
- * Verifies a signature against message hash and public key.
- * Rejects lowS signatures by default: to override,
- * specify option `{lowS: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
- *
- * ```
- * verify(r, s, h, P) where
- * U1 = hs^-1 mod n
- * U2 = rs^-1 mod n
- * R = U1⋅G - U2⋅P
- * mod(R.x, n) == r
- * ```
- */
- function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
- const sg = signature;
- msgHash = ensureBytes('msgHash', msgHash);
- publicKey = ensureBytes('publicKey', publicKey);
- if ('strict' in opts)
- throw new Error('options.strict was renamed to lowS');
- const { lowS, prehash } = opts;
- let _sig = undefined;
- let P;
- try {
- if (typeof sg === 'string' || sg instanceof Uint8Array) {
- // Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
- // Since DER can also be 2*nByteLength bytes, we check for it first.
- try {
- _sig = Signature.fromDER(sg);
- }
- catch (derError) {
- if (!(derError instanceof DER.Err))
- throw derError;
- _sig = Signature.fromCompact(sg);
- }
- }
- else if (typeof sg === 'object' && typeof sg.r === 'bigint' && typeof sg.s === 'bigint') {
- const { r, s } = sg;
- _sig = new Signature(r, s);
- }
- else {
- throw new Error('PARSE');
- }
- P = Point.fromHex(publicKey);
- }
- catch (error) {
- if (error.message === 'PARSE')
- throw new Error(`signature must be Signature instance, Uint8Array or hex string`);
- return false;
- }
- if (lowS && _sig.hasHighS())
- return false;
- if (prehash)
- msgHash = CURVE.hash(msgHash);
- const { r, s } = _sig;
- const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
- const is = invN(s); // s^-1
- const u1 = modN(h * is); // u1 = hs^-1 mod n
- const u2 = modN(r * is); // u2 = rs^-1 mod n
- const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
- if (!R)
- return false;
- const v = modN(R.x);
- return v === r;
- }
- return {
- CURVE,
- getPublicKey,
- getSharedSecret,
- sign,
- verify,
- ProjectivePoint: Point,
- Signature,
- utils,
- };
- }
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- // connects noble-curves to noble-hashes
- function getHash(hash) {
- return {
- hash,
- hmac: (key, ...msgs) => hmac(hash, key, concatBytes$1(...msgs)),
- randomBytes: randomBytes$2,
- };
- }
- function createCurve(curveDef, defHash) {
- const create = (hash) => weierstrass({ ...curveDef, ...getHash(hash) });
- return Object.freeze({ ...create(defHash), create });
- }
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
- const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
- const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
- const _1n = BigInt(1);
- const _2n = BigInt(2);
- const divNearest = (a, b) => (a + b / _2n) / b;
- /**
- * √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
- * (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
- */
- function sqrtMod(y) {
- const P = secp256k1P;
- // prettier-ignore
- const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
- // prettier-ignore
- const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
- const b2 = (y * y * y) % P; // x^3, 11
- const b3 = (b2 * b2 * y) % P; // x^7
- const b6 = (pow2(b3, _3n, P) * b3) % P;
- const b9 = (pow2(b6, _3n, P) * b3) % P;
- const b11 = (pow2(b9, _2n, P) * b2) % P;
- const b22 = (pow2(b11, _11n, P) * b11) % P;
- const b44 = (pow2(b22, _22n, P) * b22) % P;
- const b88 = (pow2(b44, _44n, P) * b44) % P;
- const b176 = (pow2(b88, _88n, P) * b88) % P;
- const b220 = (pow2(b176, _44n, P) * b44) % P;
- const b223 = (pow2(b220, _3n, P) * b3) % P;
- const t1 = (pow2(b223, _23n, P) * b22) % P;
- const t2 = (pow2(t1, _6n, P) * b2) % P;
- const root = pow2(t2, _2n, P);
- if (!Fp.eql(Fp.sqr(root), y))
- throw new Error('Cannot find square root');
- return root;
- }
- const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
- const secp256k1 = createCurve({
- a: BigInt(0),
- b: BigInt(7),
- Fp,
- n: secp256k1N,
- // Base point (x, y) aka generator point
- Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
- Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
- h: BigInt(1),
- lowS: true,
- /**
- * secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.
- * Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
- * For precomputed wNAF it trades off 1/2 init time & 1/3 ram for 20% perf hit.
- * Explanation: https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
- */
- endo: {
- beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
- splitScalar: (k) => {
- const n = secp256k1N;
- const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
- const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
- const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
- const b2 = a1;
- const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
- const c1 = divNearest(b2 * k, n);
- const c2 = divNearest(-b1 * k, n);
- let k1 = mod(k - c1 * a1 - c2 * a2, n);
- let k2 = mod(-c1 * b1 - c2 * b2, n);
- const k1neg = k1 > POW_2_128;
- const k2neg = k2 > POW_2_128;
- if (k1neg)
- k1 = n - k1;
- if (k2neg)
- k2 = n - k2;
- if (k1 > POW_2_128 || k2 > POW_2_128) {
- throw new Error('splitScalar: Endomorphism failed, k=' + k);
- }
- return { k1neg, k1, k2neg, k2 };
- },
- },
- }, sha256$1);
- // Schnorr signatures are superior to ECDSA from above. Below is Schnorr-specific BIP0340 code.
- // https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
- BigInt(0);
- secp256k1.ProjectivePoint;
- /**
- * A constant for the zero address.
- *
- * (**i.e.** ``"0x0000000000000000000000000000000000000000"``)
- */
- const ZeroAddress = "0x0000000000000000000000000000000000000000";
- /**
- * A constant for the zero hash.
- *
- * (**i.e.** ``"0x0000000000000000000000000000000000000000000000000000000000000000"``)
- */
- const ZeroHash = "0x0000000000000000000000000000000000000000000000000000000000000000";
- /**
- * A constant for the order N for the secp256k1 curve.
- *
- * (**i.e.** ``0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n``)
- */
- const N$1 = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
- /**
- * A constant for the number of wei in a single ether.
- *
- * (**i.e.** ``1000000000000000000n``)
- */
- const WeiPerEther = BigInt("1000000000000000000");
- /**
- * A constant for the maximum value for a ``uint256``.
- *
- * (**i.e.** ``0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
- */
- const MaxUint256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- /**
- * A constant for the minimum value for an ``int256``.
- *
- * (**i.e.** ``-8000000000000000000000000000000000000000000000000000000000000000n``)
- */
- const MinInt256 = BigInt("0x8000000000000000000000000000000000000000000000000000000000000000") * BigInt(-1);
- /**
- * A constant for the maximum value for an ``int256``.
- *
- * (**i.e.** ``0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
- */
- const MaxInt256 = BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- // NFKC (composed) // (decomposed)
- /**
- * A constant for the ether symbol (normalized using NFKC).
- *
- * (**i.e.** ``"\\u039e"``)
- */
- const EtherSymbol = "\u039e"; // "\uD835\uDF63";
- /**
- * A constant for the [[link-eip-191]] personal message prefix.
- *
- * (**i.e.** ``"\\x19Ethereum Signed Message:\\n"``)
- */
- const MessagePrefix = "\x19Ethereum Signed Message:\n";
- // Constants
- const BN_0$7 = BigInt(0);
- const BN_1$3 = BigInt(1);
- const BN_2$3 = BigInt(2);
- const BN_27$1 = BigInt(27);
- const BN_28$1 = BigInt(28);
- const BN_35$1 = BigInt(35);
- const _guard$3 = {};
- function toUint256(value) {
- return zeroPadValue(toBeArray(value), 32);
- }
- /**
- * A Signature @TODO
- *
- *
- * @_docloc: api/crypto:Signing
- */
- class Signature {
- #r;
- #s;
- #v;
- #networkV;
- /**
- * The ``r`` value for a signautre.
- *
- * This represents the ``x`` coordinate of a "reference" or
- * challenge point, from which the ``y`` can be computed.
- */
- get r() { return this.#r; }
- set r(value) {
- assertArgument(dataLength(value) === 32, "invalid r", "value", value);
- this.#r = hexlify(value);
- }
- /**
- * The ``s`` value for a signature.
- */
- get s() { return this.#s; }
- set s(_value) {
- assertArgument(dataLength(_value) === 32, "invalid s", "value", _value);
- const value = hexlify(_value);
- assertArgument(parseInt(value.substring(0, 3)) < 8, "non-canonical s", "value", value);
- this.#s = value;
- }
- /**
- * The ``v`` value for a signature.
- *
- * Since a given ``x`` value for ``r`` has two possible values for
- * its correspondin ``y``, the ``v`` indicates which of the two ``y``
- * values to use.
- *
- * It is normalized to the values ``27`` or ``28`` for legacy
- * purposes.
- */
- get v() { return this.#v; }
- set v(value) {
- const v = getNumber(value, "value");
- assertArgument(v === 27 || v === 28, "invalid v", "v", value);
- this.#v = v;
- }
- /**
- * The EIP-155 ``v`` for legacy transactions. For non-legacy
- * transactions, this value is ``null``.
- */
- get networkV() { return this.#networkV; }
- /**
- * The chain ID for EIP-155 legacy transactions. For non-legacy
- * transactions, this value is ``null``.
- */
- get legacyChainId() {
- const v = this.networkV;
- if (v == null) {
- return null;
- }
- return Signature.getChainId(v);
- }
- /**
- * The ``yParity`` for the signature.
- *
- * See ``v`` for more details on how this value is used.
- */
- get yParity() {
- return (this.v === 27) ? 0 : 1;
- }
- /**
- * The [[link-eip-2098]] compact representation of the ``yParity``
- * and ``s`` compacted into a single ``bytes32``.
- */
- get yParityAndS() {
- // The EIP-2098 compact representation
- const yParityAndS = getBytes(this.s);
- if (this.yParity) {
- yParityAndS[0] |= 0x80;
- }
- return hexlify(yParityAndS);
- }
- /**
- * The [[link-eip-2098]] compact representation.
- */
- get compactSerialized() {
- return concat([this.r, this.yParityAndS]);
- }
- /**
- * The serialized representation.
- */
- get serialized() {
- return concat([this.r, this.s, (this.yParity ? "0x1c" : "0x1b")]);
- }
- /**
- * @private
- */
- constructor(guard, r, s, v) {
- assertPrivate(guard, _guard$3, "Signature");
- this.#r = r;
- this.#s = s;
- this.#v = v;
- this.#networkV = null;
- }
- [Symbol.for('nodejs.util.inspect.custom')]() {
- return `Signature { r: "${this.r}", s: "${this.s}", yParity: ${this.yParity}, networkV: ${this.networkV} }`;
- }
- /**
- * Returns a new identical [[Signature]].
- */
- clone() {
- const clone = new Signature(_guard$3, this.r, this.s, this.v);
- if (this.networkV) {
- clone.#networkV = this.networkV;
- }
- return clone;
- }
- /**
- * Returns a representation that is compatible with ``JSON.stringify``.
- */
- toJSON() {
- const networkV = this.networkV;
- return {
- _type: "signature",
- networkV: ((networkV != null) ? networkV.toString() : null),
- r: this.r, s: this.s, v: this.v,
- };
- }
- /**
- * Compute the chain ID from the ``v`` in a legacy EIP-155 transactions.
- *
- * @example:
- * Signature.getChainId(45)
- * //_result:
- *
- * Signature.getChainId(46)
- * //_result:
- */
- static getChainId(v) {
- const bv = getBigInt(v, "v");
- // The v is not an EIP-155 v, so it is the unspecified chain ID
- if ((bv == BN_27$1) || (bv == BN_28$1)) {
- return BN_0$7;
- }
- // Bad value for an EIP-155 v
- assertArgument(bv >= BN_35$1, "invalid EIP-155 v", "v", v);
- return (bv - BN_35$1) / BN_2$3;
- }
- /**
- * Compute the ``v`` for a chain ID for a legacy EIP-155 transactions.
- *
- * Legacy transactions which use [[link-eip-155]] hijack the ``v``
- * property to include the chain ID.
- *
- * @example:
- * Signature.getChainIdV(5, 27)
- * //_result:
- *
- * Signature.getChainIdV(5, 28)
- * //_result:
- *
- */
- static getChainIdV(chainId, v) {
- return (getBigInt(chainId) * BN_2$3) + BigInt(35 + v - 27);
- }
- /**
- * Compute the normalized legacy transaction ``v`` from a ``yParirty``,
- * a legacy transaction ``v`` or a legacy [[link-eip-155]] transaction.
- *
- * @example:
- * // The values 0 and 1 imply v is actually yParity
- * Signature.getNormalizedV(0)
- * //_result:
- *
- * // Legacy non-EIP-1559 transaction (i.e. 27 or 28)
- * Signature.getNormalizedV(27)
- * //_result:
- *
- * // Legacy EIP-155 transaction (i.e. >= 35)
- * Signature.getNormalizedV(46)
- * //_result:
- *
- * // Invalid values throw
- * Signature.getNormalizedV(5)
- * //_error:
- */
- static getNormalizedV(v) {
- const bv = getBigInt(v);
- if (bv === BN_0$7 || bv === BN_27$1) {
- return 27;
- }
- if (bv === BN_1$3 || bv === BN_28$1) {
- return 28;
- }
- assertArgument(bv >= BN_35$1, "invalid v", "v", v);
- // Otherwise, EIP-155 v means odd is 27 and even is 28
- return (bv & BN_1$3) ? 27 : 28;
- }
- /**
- * Creates a new [[Signature]].
- *
- * If no %%sig%% is provided, a new [[Signature]] is created
- * with default values.
- *
- * If %%sig%% is a string, it is parsed.
- */
- static from(sig) {
- function assertError(check, message) {
- assertArgument(check, message, "signature", sig);
- }
- if (sig == null) {
- return new Signature(_guard$3, ZeroHash, ZeroHash, 27);
- }
- if (typeof (sig) === "string") {
- const bytes = getBytes(sig, "signature");
- if (bytes.length === 64) {
- const r = hexlify(bytes.slice(0, 32));
- const s = bytes.slice(32, 64);
- const v = (s[0] & 0x80) ? 28 : 27;
- s[0] &= 0x7f;
- return new Signature(_guard$3, r, hexlify(s), v);
- }
- if (bytes.length === 65) {
- const r = hexlify(bytes.slice(0, 32));
- const s = bytes.slice(32, 64);
- assertError((s[0] & 0x80) === 0, "non-canonical s");
- const v = Signature.getNormalizedV(bytes[64]);
- return new Signature(_guard$3, r, hexlify(s), v);
- }
- assertError(false, "invalid raw signature length");
- }
- if (sig instanceof Signature) {
- return sig.clone();
- }
- // Get r
- const _r = sig.r;
- assertError(_r != null, "missing r");
- const r = toUint256(_r);
- // Get s; by any means necessary (we check consistency below)
- const s = (function (s, yParityAndS) {
- if (s != null) {
- return toUint256(s);
- }
- if (yParityAndS != null) {
- assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
- const bytes = getBytes(yParityAndS);
- bytes[0] &= 0x7f;
- return hexlify(bytes);
- }
- assertError(false, "missing s");
- })(sig.s, sig.yParityAndS);
- assertError((getBytes(s)[0] & 0x80) == 0, "non-canonical s");
- // Get v; by any means necessary (we check consistency below)
- const { networkV, v } = (function (_v, yParityAndS, yParity) {
- if (_v != null) {
- const v = getBigInt(_v);
- return {
- networkV: ((v >= BN_35$1) ? v : undefined),
- v: Signature.getNormalizedV(v)
- };
- }
- if (yParityAndS != null) {
- assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
- return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28 : 27) };
- }
- if (yParity != null) {
- switch (getNumber(yParity, "sig.yParity")) {
- case 0: return { v: 27 };
- case 1: return { v: 28 };
- }
- assertError(false, "invalid yParity");
- }
- assertError(false, "missing v");
- })(sig.v, sig.yParityAndS, sig.yParity);
- const result = new Signature(_guard$3, r, s, v);
- if (networkV) {
- result.#networkV = networkV;
- }
- // If multiple of v, yParity, yParityAndS we given, check they match
- assertError(sig.yParity == null || getNumber(sig.yParity, "sig.yParity") === result.yParity, "yParity mismatch");
- assertError(sig.yParityAndS == null || sig.yParityAndS === result.yParityAndS, "yParityAndS mismatch");
- return result;
- }
- }
- /**
- * Add details about signing here.
- *
- * @_subsection: api/crypto:Signing [about-signing]
- */
- /**
- * A **SigningKey** provides high-level access to the elliptic curve
- * cryptography (ECC) operations and key management.
- */
- class SigningKey {
- #privateKey;
- /**
- * Creates a new **SigningKey** for %%privateKey%%.
- */
- constructor(privateKey) {
- assertArgument(dataLength(privateKey) === 32, "invalid private key", "privateKey", "[REDACTED]");
- this.#privateKey = hexlify(privateKey);
- }
- /**
- * The private key.
- */
- get privateKey() { return this.#privateKey; }
- /**
- * The uncompressed public key.
- *
- * This will always begin with the prefix ``0x04`` and be 132
- * characters long (the ``0x`` prefix and 130 hexadecimal nibbles).
- */
- get publicKey() { return SigningKey.computePublicKey(this.#privateKey); }
- /**
- * The compressed public key.
- *
- * This will always begin with either the prefix ``0x02`` or ``0x03``
- * and be 68 characters long (the ``0x`` prefix and 33 hexadecimal
- * nibbles)
- */
- get compressedPublicKey() { return SigningKey.computePublicKey(this.#privateKey, true); }
- /**
- * Return the signature of the signed %%digest%%.
- */
- sign(digest) {
- assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
- const sig = secp256k1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
- lowS: true
- });
- return Signature.from({
- r: toBeHex(sig.r, 32),
- s: toBeHex(sig.s, 32),
- v: (sig.recovery ? 0x1c : 0x1b)
- });
- }
- /**
- * Returns the [[link-wiki-ecdh]] shared secret between this
- * private key and the %%other%% key.
- *
- * The %%other%% key may be any type of key, a raw public key,
- * a compressed/uncompressed pubic key or aprivate key.
- *
- * Best practice is usually to use a cryptographic hash on the
- * returned value before using it as a symetric secret.
- *
- * @example:
- * sign1 = new SigningKey(id("some-secret-1"))
- * sign2 = new SigningKey(id("some-secret-2"))
- *
- * // Notice that privA.computeSharedSecret(pubB)...
- * sign1.computeSharedSecret(sign2.publicKey)
- * //_result:
- *
- * // ...is equal to privB.computeSharedSecret(pubA).
- * sign2.computeSharedSecret(sign1.publicKey)
- * //_result:
- */
- computeSharedSecret(other) {
- const pubKey = SigningKey.computePublicKey(other);
- return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), getBytes(pubKey), false));
- }
- /**
- * Compute the public key for %%key%%, optionally %%compressed%%.
- *
- * The %%key%% may be any type of key, a raw public key, a
- * compressed/uncompressed public key or private key.
- *
- * @example:
- * sign = new SigningKey(id("some-secret"));
- *
- * // Compute the uncompressed public key for a private key
- * SigningKey.computePublicKey(sign.privateKey)
- * //_result:
- *
- * // Compute the compressed public key for a private key
- * SigningKey.computePublicKey(sign.privateKey, true)
- * //_result:
- *
- * // Compute the uncompressed public key
- * SigningKey.computePublicKey(sign.publicKey, false);
- * //_result:
- *
- * // Compute the Compressed a public key
- * SigningKey.computePublicKey(sign.publicKey, true);
- * //_result:
- */
- static computePublicKey(key, compressed) {
- let bytes = getBytes(key, "key");
- // private key
- if (bytes.length === 32) {
- const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
- return hexlify(pubKey);
- }
- // raw public key; use uncompressed key with 0x04 prefix
- if (bytes.length === 64) {
- const pub = new Uint8Array(65);
- pub[0] = 0x04;
- pub.set(bytes, 1);
- bytes = pub;
- }
- const point = secp256k1.ProjectivePoint.fromHex(bytes);
- return hexlify(point.toRawBytes(compressed));
- }
- /**
- * Returns the public key for the private key which produced the
- * %%signature%% for the given %%digest%%.
- *
- * @example:
- * key = new SigningKey(id("some-secret"))
- * digest = id("hello world")
- * sig = key.sign(digest)
- *
- * // Notice the signer public key...
- * key.publicKey
- * //_result:
- *
- * // ...is equal to the recovered public key
- * SigningKey.recoverPublicKey(digest, sig)
- * //_result:
- *
- */
- static recoverPublicKey(digest, signature) {
- assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
- const sig = Signature.from(signature);
- let secpSig = secp256k1.Signature.fromCompact(getBytesCopy(concat([sig.r, sig.s])));
- secpSig = secpSig.addRecoveryBit(sig.yParity);
- const pubKey = secpSig.recoverPublicKey(getBytesCopy(digest));
- assertArgument(pubKey != null, "invalid signautre for digest", "signature", signature);
- return "0x" + pubKey.toHex(false);
- }
- /**
- * Returns the point resulting from adding the ellipic curve points
- * %%p0%% and %%p1%%.
- *
- * This is not a common function most developers should require, but
- * can be useful for certain privacy-specific techniques.
- *
- * For example, it is used by [[HDNodeWallet]] to compute child
- * addresses from parent public keys and chain codes.
- */
- static addPoints(p0, p1, compressed) {
- const pub0 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p0).substring(2));
- const pub1 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p1).substring(2));
- return "0x" + pub0.add(pub1).toHex(!!compressed);
- }
- }
- /**
- * A fundamental building block of Ethereum is the underlying
- * cryptographic primitives.
- *
- * @_section: api/crypto:Cryptographic Functions [about-crypto]
- */
- /**
- * Once called, prevents any future change to the underlying cryptographic
- * primitives using the ``.register`` feature for hooks.
- */
- function lock() {
- computeHmac.lock();
- keccak256.lock();
- pbkdf2.lock();
- randomBytes.lock();
- ripemd160.lock();
- scrypt.lock();
- scryptSync.lock();
- sha256.lock();
- sha512.lock();
- randomBytes.lock();
- }
- const BN_0$6 = BigInt(0);
- const BN_36 = BigInt(36);
- function getChecksumAddress(address) {
- // if (!isHexString(address, 20)) {
- // logger.throwArgumentError("invalid address", "address", address);
- // }
- address = address.toLowerCase();
- const chars = address.substring(2).split("");
- const expanded = new Uint8Array(40);
- for (let i = 0; i < 40; i++) {
- expanded[i] = chars[i].charCodeAt(0);
- }
- const hashed = getBytes(keccak256(expanded));
- for (let i = 0; i < 40; i += 2) {
- if ((hashed[i >> 1] >> 4) >= 8) {
- chars[i] = chars[i].toUpperCase();
- }
- if ((hashed[i >> 1] & 0x0f) >= 8) {
- chars[i + 1] = chars[i + 1].toUpperCase();
- }
- }
- return "0x" + chars.join("");
- }
- // See: https://en.wikipedia.org/wiki/International_Bank_Account_Number
- // Create lookup table
- const ibanLookup = {};
- for (let i = 0; i < 10; i++) {
- ibanLookup[String(i)] = String(i);
- }
- for (let i = 0; i < 26; i++) {
- ibanLookup[String.fromCharCode(65 + i)] = String(10 + i);
- }
- // How many decimal digits can we process? (for 64-bit float, this is 15)
- // i.e. Math.floor(Math.log10(Number.MAX_SAFE_INTEGER));
- const safeDigits = 15;
- function ibanChecksum(address) {
- address = address.toUpperCase();
- address = address.substring(4) + address.substring(0, 2) + "00";
- let expanded = address.split("").map((c) => { return ibanLookup[c]; }).join("");
- // Javascript can handle integers safely up to 15 (decimal) digits
- while (expanded.length >= safeDigits) {
- let block = expanded.substring(0, safeDigits);
- expanded = parseInt(block, 10) % 97 + expanded.substring(block.length);
- }
- let checksum = String(98 - (parseInt(expanded, 10) % 97));
- while (checksum.length < 2) {
- checksum = "0" + checksum;
- }
- return checksum;
- }
- const Base36 = (function () {
- const result = {};
- for (let i = 0; i < 36; i++) {
- const key = "0123456789abcdefghijklmnopqrstuvwxyz"[i];
- result[key] = BigInt(i);
- }
- return result;
- })();
- function fromBase36(value) {
- value = value.toLowerCase();
- let result = BN_0$6;
- for (let i = 0; i < value.length; i++) {
- result = result * BN_36 + Base36[value[i]];
- }
- return result;
- }
- /**
- * Returns a normalized and checksumed address for %%address%%.
- * This accepts non-checksum addresses, checksum addresses and
- * [[getIcapAddress]] formats.
- *
- * The checksum in Ethereum uses the capitalization (upper-case
- * vs lower-case) of the characters within an address to encode
- * its checksum, which offers, on average, a checksum of 15-bits.
- *
- * If %%address%% contains both upper-case and lower-case, it is
- * assumed to already be a checksum address and its checksum is
- * validated, and if the address fails its expected checksum an
- * error is thrown.
- *
- * If you wish the checksum of %%address%% to be ignore, it should
- * be converted to lower-case (i.e. ``.toLowercase()``) before
- * being passed in. This should be a very rare situation though,
- * that you wish to bypass the safegaurds in place to protect
- * against an address that has been incorrectly copied from another
- * source.
- *
- * @example:
- * // Adds the checksum (via upper-casing specific letters)
- * getAddress("0x8ba1f109551bd432803012645ac136ddd64dba72")
- * //_result:
- *
- * // Converts ICAP address and adds checksum
- * getAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
- * //_result:
- *
- * // Throws an error if an address contains mixed case,
- * // but the checksum fails
- * getAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
- * //_error:
- */
- function getAddress(address) {
- assertArgument(typeof (address) === "string", "invalid address", "address", address);
- if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
- // Missing the 0x prefix
- if (!address.startsWith("0x")) {
- address = "0x" + address;
- }
- const result = getChecksumAddress(address);
- // It is a checksummed address with a bad checksum
- assertArgument(!address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) || result === address, "bad address checksum", "address", address);
- return result;
- }
- // Maybe ICAP? (we only support direct mode)
- if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
- // It is an ICAP address with a bad checksum
- assertArgument(address.substring(2, 4) === ibanChecksum(address), "bad icap checksum", "address", address);
- let result = fromBase36(address.substring(4)).toString(16);
- while (result.length < 40) {
- result = "0" + result;
- }
- return getChecksumAddress("0x" + result);
- }
- assertArgument(false, "invalid address", "address", address);
- }
- /**
- * The [ICAP Address format](link-icap) format is an early checksum
- * format which attempts to be compatible with the banking
- * industry [IBAN format](link-wiki-iban) for bank accounts.
- *
- * It is no longer common or a recommended format.
- *
- * @example:
- * getIcapAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
- * //_result:
- *
- * getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
- * //_result:
- *
- * // Throws an error if the ICAP checksum is wrong
- * getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK37");
- * //_error:
- */
- function getIcapAddress(address) {
- //let base36 = _base16To36(getAddress(address).substring(2)).toUpperCase();
- let base36 = BigInt(getAddress(address)).toString(36).toUpperCase();
- while (base36.length < 30) {
- base36 = "0" + base36;
- }
- return "XE" + ibanChecksum("XE00" + base36) + base36;
- }
- // http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
- /**
- * Returns the address that would result from a ``CREATE`` for %%tx%%.
- *
- * This can be used to compute the address a contract will be
- * deployed to by an EOA when sending a deployment transaction (i.e.
- * when the ``to`` address is ``null``).
- *
- * This can also be used to compute the address a contract will be
- * deployed to by a contract, by using the contract's address as the
- * ``to`` and the contract's nonce.
- *
- * @example
- * from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
- * nonce = 5;
- *
- * getCreateAddress({ from, nonce });
- * //_result:
- */
- function getCreateAddress(tx) {
- const from = getAddress(tx.from);
- const nonce = getBigInt(tx.nonce, "tx.nonce");
- let nonceHex = nonce.toString(16);
- if (nonceHex === "0") {
- nonceHex = "0x";
- }
- else if (nonceHex.length % 2) {
- nonceHex = "0x0" + nonceHex;
- }
- else {
- nonceHex = "0x" + nonceHex;
- }
- return getAddress(dataSlice(keccak256(encodeRlp([from, nonceHex])), 12));
- }
- /**
- * Returns the address that would result from a ``CREATE2`` operation
- * with the given %%from%%, %%salt%% and %%initCodeHash%%.
- *
- * To compute the %%initCodeHash%% from a contract's init code, use
- * the [[keccak256]] function.
- *
- * For a quick overview and example of ``CREATE2``, see [[link-ricmoo-wisps]].
- *
- * @example
- * // The address of the contract
- * from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
- *
- * // The salt
- * salt = id("HelloWorld")
- *
- * // The hash of the initCode
- * initCode = "0x6394198df16000526103ff60206004601c335afa6040516060f3";
- * initCodeHash = keccak256(initCode)
- *
- * getCreate2Address(from, salt, initCodeHash)
- * //_result:
- */
- function getCreate2Address(_from, _salt, _initCodeHash) {
- const from = getAddress(_from);
- const salt = getBytes(_salt, "salt");
- const initCodeHash = getBytes(_initCodeHash, "initCodeHash");
- assertArgument(salt.length === 32, "salt must be 32 bytes", "salt", _salt);
- assertArgument(initCodeHash.length === 32, "initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
- return getAddress(dataSlice(keccak256(concat(["0xff", from, salt, initCodeHash])), 12));
- }
- /**
- * Returns true if %%value%% is an object which implements the
- * [[Addressable]] interface.
- *
- * @example:
- * // Wallets and AbstractSigner sub-classes
- * isAddressable(Wallet.createRandom())
- * //_result:
- *
- * // Contracts
- * contract = new Contract("dai.tokens.ethers.eth", [ ], provider)
- * isAddressable(contract)
- * //_result:
- */
- function isAddressable(value) {
- return (value && typeof (value.getAddress) === "function");
- }
- /**
- * Returns true if %%value%% is a valid address.
- *
- * @example:
- * // Valid address
- * isAddress("0x8ba1f109551bD432803012645Ac136ddd64DBA72")
- * //_result:
- *
- * // Valid ICAP address
- * isAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36")
- * //_result:
- *
- * // Invalid checksum
- * isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBa72")
- * //_result:
- *
- * // Invalid ICAP checksum
- * isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
- * //_result:
- *
- * // Not an address (an ENS name requires a provided and an
- * // asynchronous API to access)
- * isAddress("ricmoo.eth")
- * //_result:
- */
- function isAddress(value) {
- try {
- getAddress(value);
- return true;
- }
- catch (error) { }
- return false;
- }
- async function checkAddress(target, promise) {
- const result = await promise;
- if (result == null || result === "0x0000000000000000000000000000000000000000") {
- assert(typeof (target) !== "string", "unconfigured name", "UNCONFIGURED_NAME", { value: target });
- assertArgument(false, "invalid AddressLike value; did not resolve to a value address", "target", target);
- }
- return getAddress(result);
- }
- /**
- * Resolves to an address for the %%target%%, which may be any
- * supported address type, an [[Addressable]] or a Promise which
- * resolves to an address.
- *
- * If an ENS name is provided, but that name has not been correctly
- * configured a [[UnconfiguredNameError]] is thrown.
- *
- * @example:
- * addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F"
- *
- * // Addresses are return synchronously
- * resolveAddress(addr, provider)
- * //_result:
- *
- * // Address promises are resolved asynchronously
- * resolveAddress(Promise.resolve(addr))
- * //_result:
- *
- * // ENS names are resolved asynchronously
- * resolveAddress("dai.tokens.ethers.eth", provider)
- * //_result:
- *
- * // Addressable objects are resolved asynchronously
- * contract = new Contract(addr, [ ])
- * resolveAddress(contract, provider)
- * //_result:
- *
- * // Unconfigured ENS names reject
- * resolveAddress("nothing-here.ricmoo.eth", provider)
- * //_error:
- *
- * // ENS names require a NameResolver object passed in
- * // (notice the provider was omitted)
- * resolveAddress("nothing-here.ricmoo.eth")
- * //_error:
- */
- function resolveAddress(target, resolver) {
- if (typeof (target) === "string") {
- if (target.match(/^0x[0-9a-f]{40}$/i)) {
- return getAddress(target);
- }
- assert(resolver != null, "ENS resolution requires a provider", "UNSUPPORTED_OPERATION", { operation: "resolveName" });
- return checkAddress(target, resolver.resolveName(target));
- }
- else if (isAddressable(target)) {
- return checkAddress(target, target.getAddress());
- }
- else if (target && typeof (target.then) === "function") {
- return checkAddress(target, target);
- }
- assertArgument(false, "unsupported addressable value", "target", target);
- }
- /**
- * A Typed object allows a value to have its type explicitly
- * specified.
- *
- * For example, in Solidity, the value ``45`` could represent a
- * ``uint8`` or a ``uint256``. The value ``0x1234`` could represent
- * a ``bytes2`` or ``bytes``.
- *
- * Since JavaScript has no meaningful way to explicitly inform any
- * APIs which what the type is, this allows transparent interoperation
- * with Soldity.
- *
- * @_subsection: api/abi:Typed Values
- */
- const _gaurd = {};
- function n(value, width) {
- let signed = false;
- if (width < 0) {
- signed = true;
- width *= -1;
- }
- // @TODO: Check range is valid for value
- return new Typed(_gaurd, `${signed ? "" : "u"}int${width}`, value, { signed, width });
- }
- function b(value, size) {
- // @TODO: Check range is valid for value
- return new Typed(_gaurd, `bytes${(size) ? size : ""}`, value, { size });
- }
- const _typedSymbol = Symbol.for("_ethers_typed");
- /**
- * The **Typed** class to wrap values providing explicit type information.
- */
- class Typed {
- /**
- * The type, as a Solidity-compatible type.
- */
- type;
- /**
- * The actual value.
- */
- value;
- #options;
- /**
- * @_ignore:
- */
- _typedSymbol;
- /**
- * @_ignore:
- */
- constructor(gaurd, type, value, options) {
- if (options == null) {
- options = null;
- }
- assertPrivate(_gaurd, gaurd, "Typed");
- defineProperties(this, { _typedSymbol, type, value });
- this.#options = options;
- // Check the value is valid
- this.format();
- }
- /**
- * Format the type as a Human-Readable type.
- */
- format() {
- if (this.type === "array") {
- throw new Error("");
- }
- else if (this.type === "dynamicArray") {
- throw new Error("");
- }
- else if (this.type === "tuple") {
- return `tuple(${this.value.map((v) => v.format()).join(",")})`;
- }
- return this.type;
- }
- /**
- * The default value returned by this type.
- */
- defaultValue() {
- return 0;
- }
- /**
- * The minimum value for numeric types.
- */
- minValue() {
- return 0;
- }
- /**
- * The maximum value for numeric types.
- */
- maxValue() {
- return 0;
- }
- /**
- * Returns ``true`` and provides a type guard is this is a [[TypedBigInt]].
- */
- isBigInt() {
- return !!(this.type.match(/^u?int[0-9]+$/));
- }
- /**
- * Returns ``true`` and provides a type guard is this is a [[TypedData]].
- */
- isData() {
- return this.type.startsWith("bytes");
- }
- /**
- * Returns ``true`` and provides a type guard is this is a [[TypedString]].
- */
- isString() {
- return (this.type === "string");
- }
- /**
- * Returns the tuple name, if this is a tuple. Throws otherwise.
- */
- get tupleName() {
- if (this.type !== "tuple") {
- throw TypeError("not a tuple");
- }
- return this.#options;
- }
- // Returns the length of this type as an array
- // - `null` indicates the length is unforced, it could be dynamic
- // - `-1` indicates the length is dynamic
- // - any other value indicates it is a static array and is its length
- /**
- * Returns the length of the array type or ``-1`` if it is dynamic.
- *
- * Throws if the type is not an array.
- */
- get arrayLength() {
- if (this.type !== "array") {
- throw TypeError("not an array");
- }
- if (this.#options === true) {
- return -1;
- }
- if (this.#options === false) {
- return (this.value).length;
- }
- return null;
- }
- /**
- * Returns a new **Typed** of %%type%% with the %%value%%.
- */
- static from(type, value) {
- return new Typed(_gaurd, type, value);
- }
- /**
- * Return a new ``uint8`` type for %%v%%.
- */
- static uint8(v) { return n(v, 8); }
- /**
- * Return a new ``uint16`` type for %%v%%.
- */
- static uint16(v) { return n(v, 16); }
- /**
- * Return a new ``uint24`` type for %%v%%.
- */
- static uint24(v) { return n(v, 24); }
- /**
- * Return a new ``uint32`` type for %%v%%.
- */
- static uint32(v) { return n(v, 32); }
- /**
- * Return a new ``uint40`` type for %%v%%.
- */
- static uint40(v) { return n(v, 40); }
- /**
- * Return a new ``uint48`` type for %%v%%.
- */
- static uint48(v) { return n(v, 48); }
- /**
- * Return a new ``uint56`` type for %%v%%.
- */
- static uint56(v) { return n(v, 56); }
- /**
- * Return a new ``uint64`` type for %%v%%.
- */
- static uint64(v) { return n(v, 64); }
- /**
- * Return a new ``uint72`` type for %%v%%.
- */
- static uint72(v) { return n(v, 72); }
- /**
- * Return a new ``uint80`` type for %%v%%.
- */
- static uint80(v) { return n(v, 80); }
- /**
- * Return a new ``uint88`` type for %%v%%.
- */
- static uint88(v) { return n(v, 88); }
- /**
- * Return a new ``uint96`` type for %%v%%.
- */
- static uint96(v) { return n(v, 96); }
- /**
- * Return a new ``uint104`` type for %%v%%.
- */
- static uint104(v) { return n(v, 104); }
- /**
- * Return a new ``uint112`` type for %%v%%.
- */
- static uint112(v) { return n(v, 112); }
- /**
- * Return a new ``uint120`` type for %%v%%.
- */
- static uint120(v) { return n(v, 120); }
- /**
- * Return a new ``uint128`` type for %%v%%.
- */
- static uint128(v) { return n(v, 128); }
- /**
- * Return a new ``uint136`` type for %%v%%.
- */
- static uint136(v) { return n(v, 136); }
- /**
- * Return a new ``uint144`` type for %%v%%.
- */
- static uint144(v) { return n(v, 144); }
- /**
- * Return a new ``uint152`` type for %%v%%.
- */
- static uint152(v) { return n(v, 152); }
- /**
- * Return a new ``uint160`` type for %%v%%.
- */
- static uint160(v) { return n(v, 160); }
- /**
- * Return a new ``uint168`` type for %%v%%.
- */
- static uint168(v) { return n(v, 168); }
- /**
- * Return a new ``uint176`` type for %%v%%.
- */
- static uint176(v) { return n(v, 176); }
- /**
- * Return a new ``uint184`` type for %%v%%.
- */
- static uint184(v) { return n(v, 184); }
- /**
- * Return a new ``uint192`` type for %%v%%.
- */
- static uint192(v) { return n(v, 192); }
- /**
- * Return a new ``uint200`` type for %%v%%.
- */
- static uint200(v) { return n(v, 200); }
- /**
- * Return a new ``uint208`` type for %%v%%.
- */
- static uint208(v) { return n(v, 208); }
- /**
- * Return a new ``uint216`` type for %%v%%.
- */
- static uint216(v) { return n(v, 216); }
- /**
- * Return a new ``uint224`` type for %%v%%.
- */
- static uint224(v) { return n(v, 224); }
- /**
- * Return a new ``uint232`` type for %%v%%.
- */
- static uint232(v) { return n(v, 232); }
- /**
- * Return a new ``uint240`` type for %%v%%.
- */
- static uint240(v) { return n(v, 240); }
- /**
- * Return a new ``uint248`` type for %%v%%.
- */
- static uint248(v) { return n(v, 248); }
- /**
- * Return a new ``uint256`` type for %%v%%.
- */
- static uint256(v) { return n(v, 256); }
- /**
- * Return a new ``uint256`` type for %%v%%.
- */
- static uint(v) { return n(v, 256); }
- /**
- * Return a new ``int8`` type for %%v%%.
- */
- static int8(v) { return n(v, -8); }
- /**
- * Return a new ``int16`` type for %%v%%.
- */
- static int16(v) { return n(v, -16); }
- /**
- * Return a new ``int24`` type for %%v%%.
- */
- static int24(v) { return n(v, -24); }
- /**
- * Return a new ``int32`` type for %%v%%.
- */
- static int32(v) { return n(v, -32); }
- /**
- * Return a new ``int40`` type for %%v%%.
- */
- static int40(v) { return n(v, -40); }
- /**
- * Return a new ``int48`` type for %%v%%.
- */
- static int48(v) { return n(v, -48); }
- /**
- * Return a new ``int56`` type for %%v%%.
- */
- static int56(v) { return n(v, -56); }
- /**
- * Return a new ``int64`` type for %%v%%.
- */
- static int64(v) { return n(v, -64); }
- /**
- * Return a new ``int72`` type for %%v%%.
- */
- static int72(v) { return n(v, -72); }
- /**
- * Return a new ``int80`` type for %%v%%.
- */
- static int80(v) { return n(v, -80); }
- /**
- * Return a new ``int88`` type for %%v%%.
- */
- static int88(v) { return n(v, -88); }
- /**
- * Return a new ``int96`` type for %%v%%.
- */
- static int96(v) { return n(v, -96); }
- /**
- * Return a new ``int104`` type for %%v%%.
- */
- static int104(v) { return n(v, -104); }
- /**
- * Return a new ``int112`` type for %%v%%.
- */
- static int112(v) { return n(v, -112); }
- /**
- * Return a new ``int120`` type for %%v%%.
- */
- static int120(v) { return n(v, -120); }
- /**
- * Return a new ``int128`` type for %%v%%.
- */
- static int128(v) { return n(v, -128); }
- /**
- * Return a new ``int136`` type for %%v%%.
- */
- static int136(v) { return n(v, -136); }
- /**
- * Return a new ``int144`` type for %%v%%.
- */
- static int144(v) { return n(v, -144); }
- /**
- * Return a new ``int52`` type for %%v%%.
- */
- static int152(v) { return n(v, -152); }
- /**
- * Return a new ``int160`` type for %%v%%.
- */
- static int160(v) { return n(v, -160); }
- /**
- * Return a new ``int168`` type for %%v%%.
- */
- static int168(v) { return n(v, -168); }
- /**
- * Return a new ``int176`` type for %%v%%.
- */
- static int176(v) { return n(v, -176); }
- /**
- * Return a new ``int184`` type for %%v%%.
- */
- static int184(v) { return n(v, -184); }
- /**
- * Return a new ``int92`` type for %%v%%.
- */
- static int192(v) { return n(v, -192); }
- /**
- * Return a new ``int200`` type for %%v%%.
- */
- static int200(v) { return n(v, -200); }
- /**
- * Return a new ``int208`` type for %%v%%.
- */
- static int208(v) { return n(v, -208); }
- /**
- * Return a new ``int216`` type for %%v%%.
- */
- static int216(v) { return n(v, -216); }
- /**
- * Return a new ``int224`` type for %%v%%.
- */
- static int224(v) { return n(v, -224); }
- /**
- * Return a new ``int232`` type for %%v%%.
- */
- static int232(v) { return n(v, -232); }
- /**
- * Return a new ``int240`` type for %%v%%.
- */
- static int240(v) { return n(v, -240); }
- /**
- * Return a new ``int248`` type for %%v%%.
- */
- static int248(v) { return n(v, -248); }
- /**
- * Return a new ``int256`` type for %%v%%.
- */
- static int256(v) { return n(v, -256); }
- /**
- * Return a new ``int256`` type for %%v%%.
- */
- static int(v) { return n(v, -256); }
- /**
- * Return a new ``bytes1`` type for %%v%%.
- */
- static bytes1(v) { return b(v, 1); }
- /**
- * Return a new ``bytes2`` type for %%v%%.
- */
- static bytes2(v) { return b(v, 2); }
- /**
- * Return a new ``bytes3`` type for %%v%%.
- */
- static bytes3(v) { return b(v, 3); }
- /**
- * Return a new ``bytes4`` type for %%v%%.
- */
- static bytes4(v) { return b(v, 4); }
- /**
- * Return a new ``bytes5`` type for %%v%%.
- */
- static bytes5(v) { return b(v, 5); }
- /**
- * Return a new ``bytes6`` type for %%v%%.
- */
- static bytes6(v) { return b(v, 6); }
- /**
- * Return a new ``bytes7`` type for %%v%%.
- */
- static bytes7(v) { return b(v, 7); }
- /**
- * Return a new ``bytes8`` type for %%v%%.
- */
- static bytes8(v) { return b(v, 8); }
- /**
- * Return a new ``bytes9`` type for %%v%%.
- */
- static bytes9(v) { return b(v, 9); }
- /**
- * Return a new ``bytes10`` type for %%v%%.
- */
- static bytes10(v) { return b(v, 10); }
- /**
- * Return a new ``bytes11`` type for %%v%%.
- */
- static bytes11(v) { return b(v, 11); }
- /**
- * Return a new ``bytes12`` type for %%v%%.
- */
- static bytes12(v) { return b(v, 12); }
- /**
- * Return a new ``bytes13`` type for %%v%%.
- */
- static bytes13(v) { return b(v, 13); }
- /**
- * Return a new ``bytes14`` type for %%v%%.
- */
- static bytes14(v) { return b(v, 14); }
- /**
- * Return a new ``bytes15`` type for %%v%%.
- */
- static bytes15(v) { return b(v, 15); }
- /**
- * Return a new ``bytes16`` type for %%v%%.
- */
- static bytes16(v) { return b(v, 16); }
- /**
- * Return a new ``bytes17`` type for %%v%%.
- */
- static bytes17(v) { return b(v, 17); }
- /**
- * Return a new ``bytes18`` type for %%v%%.
- */
- static bytes18(v) { return b(v, 18); }
- /**
- * Return a new ``bytes19`` type for %%v%%.
- */
- static bytes19(v) { return b(v, 19); }
- /**
- * Return a new ``bytes20`` type for %%v%%.
- */
- static bytes20(v) { return b(v, 20); }
- /**
- * Return a new ``bytes21`` type for %%v%%.
- */
- static bytes21(v) { return b(v, 21); }
- /**
- * Return a new ``bytes22`` type for %%v%%.
- */
- static bytes22(v) { return b(v, 22); }
- /**
- * Return a new ``bytes23`` type for %%v%%.
- */
- static bytes23(v) { return b(v, 23); }
- /**
- * Return a new ``bytes24`` type for %%v%%.
- */
- static bytes24(v) { return b(v, 24); }
- /**
- * Return a new ``bytes25`` type for %%v%%.
- */
- static bytes25(v) { return b(v, 25); }
- /**
- * Return a new ``bytes26`` type for %%v%%.
- */
- static bytes26(v) { return b(v, 26); }
- /**
- * Return a new ``bytes27`` type for %%v%%.
- */
- static bytes27(v) { return b(v, 27); }
- /**
- * Return a new ``bytes28`` type for %%v%%.
- */
- static bytes28(v) { return b(v, 28); }
- /**
- * Return a new ``bytes29`` type for %%v%%.
- */
- static bytes29(v) { return b(v, 29); }
- /**
- * Return a new ``bytes30`` type for %%v%%.
- */
- static bytes30(v) { return b(v, 30); }
- /**
- * Return a new ``bytes31`` type for %%v%%.
- */
- static bytes31(v) { return b(v, 31); }
- /**
- * Return a new ``bytes32`` type for %%v%%.
- */
- static bytes32(v) { return b(v, 32); }
- /**
- * Return a new ``address`` type for %%v%%.
- */
- static address(v) { return new Typed(_gaurd, "address", v); }
- /**
- * Return a new ``bool`` type for %%v%%.
- */
- static bool(v) { return new Typed(_gaurd, "bool", !!v); }
- /**
- * Return a new ``bytes`` type for %%v%%.
- */
- static bytes(v) { return new Typed(_gaurd, "bytes", v); }
- /**
- * Return a new ``string`` type for %%v%%.
- */
- static string(v) { return new Typed(_gaurd, "string", v); }
- /**
- * Return a new ``array`` type for %%v%%, allowing %%dynamic%% length.
- */
- static array(v, dynamic) {
- throw new Error("not implemented yet");
- }
- /**
- * Return a new ``tuple`` type for %%v%%, with the optional %%name%%.
- */
- static tuple(v, name) {
- throw new Error("not implemented yet");
- }
- /**
- * Return a new ``uint8`` type for %%v%%.
- */
- static overrides(v) {
- return new Typed(_gaurd, "overrides", Object.assign({}, v));
- }
- /**
- * Returns true only if %%value%% is a [[Typed]] instance.
- */
- static isTyped(value) {
- return (value
- && typeof (value) === "object"
- && "_typedSymbol" in value
- && value._typedSymbol === _typedSymbol);
- }
- /**
- * If the value is a [[Typed]] instance, validates the underlying value
- * and returns it, otherwise returns value directly.
- *
- * This is useful for functions that with to accept either a [[Typed]]
- * object or values.
- */
- static dereference(value, type) {
- if (Typed.isTyped(value)) {
- if (value.type !== type) {
- throw new Error(`invalid type: expecetd ${type}, got ${value.type}`);
- }
- return value.value;
- }
- return value;
- }
- }
- /**
- * @_ignore
- */
- class AddressCoder extends Coder {
- constructor(localName) {
- super("address", "address", localName, false);
- }
- defaultValue() {
- return "0x0000000000000000000000000000000000000000";
- }
- encode(writer, _value) {
- let value = Typed.dereference(_value, "string");
- try {
- value = getAddress(value);
- }
- catch (error) {
- return this._throwError(error.message, _value);
- }
- return writer.writeValue(value);
- }
- decode(reader) {
- return getAddress(toBeHex(reader.readValue(), 20));
- }
- }
- /**
- * Clones the functionality of an existing Coder, but without a localName
- *
- * @_ignore
- */
- class AnonymousCoder extends Coder {
- coder;
- constructor(coder) {
- super(coder.name, coder.type, "_", coder.dynamic);
- this.coder = coder;
- }
- defaultValue() {
- return this.coder.defaultValue();
- }
- encode(writer, value) {
- return this.coder.encode(writer, value);
- }
- decode(reader) {
- return this.coder.decode(reader);
- }
- }
- /**
- * @_ignore
- */
- function pack(writer, coders, values) {
- let arrayValues = [];
- if (Array.isArray(values)) {
- arrayValues = values;
- }
- else if (values && typeof (values) === "object") {
- let unique = {};
- arrayValues = coders.map((coder) => {
- const name = coder.localName;
- assert(name, "cannot encode object for signature with missing names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
- assert(!unique[name], "cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
- unique[name] = true;
- return values[name];
- });
- }
- else {
- assertArgument(false, "invalid tuple value", "tuple", values);
- }
- assertArgument(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values);
- let staticWriter = new Writer();
- let dynamicWriter = new Writer();
- let updateFuncs = [];
- coders.forEach((coder, index) => {
- let value = arrayValues[index];
- if (coder.dynamic) {
- // Get current dynamic offset (for the future pointer)
- let dynamicOffset = dynamicWriter.length;
- // Encode the dynamic value into the dynamicWriter
- coder.encode(dynamicWriter, value);
- // Prepare to populate the correct offset once we are done
- let updateFunc = staticWriter.writeUpdatableValue();
- updateFuncs.push((baseOffset) => {
- updateFunc(baseOffset + dynamicOffset);
- });
- }
- else {
- coder.encode(staticWriter, value);
- }
- });
- // Backfill all the dynamic offsets, now that we know the static length
- updateFuncs.forEach((func) => { func(staticWriter.length); });
- let length = writer.appendWriter(staticWriter);
- length += writer.appendWriter(dynamicWriter);
- return length;
- }
- /**
- * @_ignore
- */
- function unpack(reader, coders) {
- let values = [];
- let keys = [];
- // A reader anchored to this base
- let baseReader = reader.subReader(0);
- coders.forEach((coder) => {
- let value = null;
- if (coder.dynamic) {
- let offset = reader.readIndex();
- let offsetReader = baseReader.subReader(offset);
- try {
- value = coder.decode(offsetReader);
- }
- catch (error) {
- // Cannot recover from this
- if (isError(error, "BUFFER_OVERRUN")) {
- throw error;
- }
- value = error;
- value.baseType = coder.name;
- value.name = coder.localName;
- value.type = coder.type;
- }
- }
- else {
- try {
- value = coder.decode(reader);
- }
- catch (error) {
- // Cannot recover from this
- if (isError(error, "BUFFER_OVERRUN")) {
- throw error;
- }
- value = error;
- value.baseType = coder.name;
- value.name = coder.localName;
- value.type = coder.type;
- }
- }
- if (value == undefined) {
- throw new Error("investigate");
- }
- values.push(value);
- keys.push(coder.localName || null);
- });
- return Result.fromItems(values, keys);
- }
- /**
- * @_ignore
- */
- class ArrayCoder extends Coder {
- coder;
- length;
- constructor(coder, length, localName) {
- const type = (coder.type + "[" + (length >= 0 ? length : "") + "]");
- const dynamic = (length === -1 || coder.dynamic);
- super("array", type, localName, dynamic);
- defineProperties(this, { coder, length });
- }
- defaultValue() {
- // Verifies the child coder is valid (even if the array is dynamic or 0-length)
- const defaultChild = this.coder.defaultValue();
- const result = [];
- for (let i = 0; i < this.length; i++) {
- result.push(defaultChild);
- }
- return result;
- }
- encode(writer, _value) {
- const value = Typed.dereference(_value, "array");
- if (!Array.isArray(value)) {
- this._throwError("expected array value", value);
- }
- let count = this.length;
- if (count === -1) {
- count = value.length;
- writer.writeValue(value.length);
- }
- assertArgumentCount(value.length, count, "coder array" + (this.localName ? (" " + this.localName) : ""));
- let coders = [];
- for (let i = 0; i < value.length; i++) {
- coders.push(this.coder);
- }
- return pack(writer, coders, value);
- }
- decode(reader) {
- let count = this.length;
- if (count === -1) {
- count = reader.readIndex();
- // Check that there is *roughly* enough data to ensure
- // stray random data is not being read as a length. Each
- // slot requires at least 32 bytes for their value (or 32
- // bytes as a link to the data). This could use a much
- // tighter bound, but we are erroring on the side of safety.
- assert(count * WordSize <= reader.dataLength, "insufficient data length", "BUFFER_OVERRUN", { buffer: reader.bytes, offset: count * WordSize, length: reader.dataLength });
- }
- let coders = [];
- for (let i = 0; i < count; i++) {
- coders.push(new AnonymousCoder(this.coder));
- }
- return unpack(reader, coders);
- }
- }
- /**
- * @_ignore
- */
- class BooleanCoder extends Coder {
- constructor(localName) {
- super("bool", "bool", localName, false);
- }
- defaultValue() {
- return false;
- }
- encode(writer, _value) {
- const value = Typed.dereference(_value, "bool");
- return writer.writeValue(value ? 1 : 0);
- }
- decode(reader) {
- return !!reader.readValue();
- }
- }
- /**
- * @_ignore
- */
- class DynamicBytesCoder extends Coder {
- constructor(type, localName) {
- super(type, type, localName, true);
- }
- defaultValue() {
- return "0x";
- }
- encode(writer, value) {
- value = getBytesCopy(value);
- let length = writer.writeValue(value.length);
- length += writer.writeBytes(value);
- return length;
- }
- decode(reader) {
- return reader.readBytes(reader.readIndex(), true);
- }
- }
- /**
- * @_ignore
- */
- class BytesCoder extends DynamicBytesCoder {
- constructor(localName) {
- super("bytes", localName);
- }
- decode(reader) {
- return hexlify(super.decode(reader));
- }
- }
- /**
- * @_ignore
- */
- class FixedBytesCoder extends Coder {
- size;
- constructor(size, localName) {
- let name = "bytes" + String(size);
- super(name, name, localName, false);
- defineProperties(this, { size }, { size: "number" });
- }
- defaultValue() {
- return ("0x0000000000000000000000000000000000000000000000000000000000000000").substring(0, 2 + this.size * 2);
- }
- encode(writer, _value) {
- let data = getBytesCopy(Typed.dereference(_value, this.type));
- if (data.length !== this.size) {
- this._throwError("incorrect data length", _value);
- }
- return writer.writeBytes(data);
- }
- decode(reader) {
- return hexlify(reader.readBytes(this.size));
- }
- }
- const Empty = new Uint8Array([]);
- /**
- * @_ignore
- */
- class NullCoder extends Coder {
- constructor(localName) {
- super("null", "", localName, false);
- }
- defaultValue() {
- return null;
- }
- encode(writer, value) {
- if (value != null) {
- this._throwError("not null", value);
- }
- return writer.writeBytes(Empty);
- }
- decode(reader) {
- reader.readBytes(0);
- return null;
- }
- }
- const BN_0$5 = BigInt(0);
- const BN_1$2 = BigInt(1);
- const BN_MAX_UINT256$1 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- /**
- * @_ignore
- */
- class NumberCoder extends Coder {
- size;
- signed;
- constructor(size, signed, localName) {
- const name = ((signed ? "int" : "uint") + (size * 8));
- super(name, name, localName, false);
- defineProperties(this, { size, signed }, { size: "number", signed: "boolean" });
- }
- defaultValue() {
- return 0;
- }
- encode(writer, _value) {
- let value = getBigInt(Typed.dereference(_value, this.type));
- // Check bounds are safe for encoding
- let maxUintValue = mask(BN_MAX_UINT256$1, WordSize * 8);
- if (this.signed) {
- let bounds = mask(maxUintValue, (this.size * 8) - 1);
- if (value > bounds || value < -(bounds + BN_1$2)) {
- this._throwError("value out-of-bounds", _value);
- }
- value = toTwos(value, 8 * WordSize);
- }
- else if (value < BN_0$5 || value > mask(maxUintValue, this.size * 8)) {
- this._throwError("value out-of-bounds", _value);
- }
- return writer.writeValue(value);
- }
- decode(reader) {
- let value = mask(reader.readValue(), this.size * 8);
- if (this.signed) {
- value = fromTwos(value, this.size * 8);
- }
- return value;
- }
- }
- /**
- * @_ignore
- */
- class StringCoder extends DynamicBytesCoder {
- constructor(localName) {
- super("string", localName);
- }
- defaultValue() {
- return "";
- }
- encode(writer, _value) {
- return super.encode(writer, toUtf8Bytes(Typed.dereference(_value, "string")));
- }
- decode(reader) {
- return toUtf8String(super.decode(reader));
- }
- }
- /**
- * @_ignore
- */
- class TupleCoder extends Coder {
- coders;
- constructor(coders, localName) {
- let dynamic = false;
- const types = [];
- coders.forEach((coder) => {
- if (coder.dynamic) {
- dynamic = true;
- }
- types.push(coder.type);
- });
- const type = ("tuple(" + types.join(",") + ")");
- super("tuple", type, localName, dynamic);
- defineProperties(this, { coders: Object.freeze(coders.slice()) });
- }
- defaultValue() {
- const values = [];
- this.coders.forEach((coder) => {
- values.push(coder.defaultValue());
- });
- // We only output named properties for uniquely named coders
- const uniqueNames = this.coders.reduce((accum, coder) => {
- const name = coder.localName;
- if (name) {
- if (!accum[name]) {
- accum[name] = 0;
- }
- accum[name]++;
- }
- return accum;
- }, {});
- // Add named values
- this.coders.forEach((coder, index) => {
- let name = coder.localName;
- if (!name || uniqueNames[name] !== 1) {
- return;
- }
- if (name === "length") {
- name = "_length";
- }
- if (values[name] != null) {
- return;
- }
- values[name] = values[index];
- });
- return Object.freeze(values);
- }
- encode(writer, _value) {
- const value = Typed.dereference(_value, "tuple");
- return pack(writer, this.coders, value);
- }
- decode(reader) {
- return unpack(reader, this.coders);
- }
- }
- /**
- * A simple hashing function which operates on UTF-8 strings to
- * compute an 32-byte identifier.
- *
- * This simply computes the [UTF-8 bytes](toUtf8Bytes) and computes
- * the [[keccak256]].
- *
- * @example:
- * id("hello world")
- * //_result:
- */
- function id(value) {
- return keccak256(toUtf8Bytes(value));
- }
- // created 2023-09-25T01:01:55.148Z
- // compressed base64-encoded blob for include-ens data
- // source: https://github.com/adraffy/ens-normalize.js/blob/main/src/make.js
- // see: https://github.com/adraffy/ens-normalize.js#security
- // SHA-256: 0565ed049b9cf1614bb9e11ba7d8ac6a6fb96c893253d890f7e2b2884b9ded32
- var COMPRESSED$1 = 'AEEUdwmgDS8BxQKKAP4BOgDjATAAngDUAIMAoABoAOAAagCOAEQAhABMAHIAOwA9ACsANgAmAGIAHgAuACgAJwAXAC0AGgAjAB8ALwAUACkAEgAeAAkAGwARABkAFgA5ACgALQArADcAFQApABAAHgAiABAAGgAeABMAGAUhBe8BFxREN8sF2wC5AK5HAW8ArQkDzQCuhzc3NzcBP68NEfMABQdHBuw5BV8FYAA9MzkI9r4ZBg7QyQAWA9CeOwLNCjcCjqkChuA/lm+RAsXTAoP6ASfnEQDytQFJAjWVCkeXAOsA6godAB/cwdAUE0WlBCN/AQUCQRjFD/MRBjHxDQSJbw0jBzUAswBxme+tnIcAYwabAysG8QAjAEMMmxcDqgPKQyDXCMMxA7kUQwD3NXOrAKmFIAAfBC0D3x4BJQDBGdUFAhEgVD8JnwmQJiNWYUzrg0oAGwAUAB0AFnNcACkAFgBP9h3gPfsDOWDKneY2ChglX1UDYD30ABsAFAAdABZzIGRAnwDD8wAjAEEMzRbDqgMB2sAFYwXqAtCnAsS4AwpUJKRtFHsadUz9AMMVbwLpABM1NJEX0ZkCgYMBEyMAxRVvAukAEzUBUFAtmUwSAy4DBTER33EftQHfSwB5MxJ/AjkWKQLzL8E/cwBB6QH9LQDPDtO9ASNriQC5DQANAwCK21EFI91zHwCoL9kBqQcHBwcHKzUDowBvAQohPvU3fAQgHwCyAc8CKQMA5zMSezr7ULgFmDp/LzVQBgEGAi8FYQVgt8AFcTtlQhpCWEmfe5tmZ6IAExsDzQ8t+X8rBKtTAltbAn0jsy8Bl6utPWMDTR8Ei2kRANkDBrNHNysDBzECQWUAcwFpJ3kAiyUhAJ0BUb8AL3EfAbfNAz81KUsFWwF3YQZtAm0A+VEfAzEJDQBRSQCzAQBlAHsAM70GD/v3IZWHBwARKQAxALsjTwHZAeMPEzmXgIHwABIAGQA8AEUAQDt3gdvIEGcQZAkGTRFMdEIVEwK0D64L7REdDNkq09PgADSxB/MDWwfzA1sDWwfzB/MDWwfzA1sDWwNbA1scEvAi28gQZw9QBHUFlgWTBN4IiyZREYkHMAjaVBV0JhxPA00BBCMtSSQ7mzMTJUpMFE0LCAQ2SmyvfUADTzGzVP2QqgPTMlc5dAkGHnkSqAAyD3skNb1OhnpPcagKU0+2tYdJak5vAsY6sEAACikJm2/Dd1YGRRAfJ6kQ+ww3AbkBPw3xS9wE9QY/BM0fgRkdD9GVoAipLeEM8SbnLqWAXiP5KocF8Uv4POELUVFsD10LaQnnOmeBUgMlAREijwrhDT0IcRD3Cs1vDekRSQc9A9lJngCpBwULFR05FbkmFGKwCw05ewb/GvoLkyazEy17AAXXGiUGUQEtGwMA0y7rhbRaNVwgT2MGBwspI8sUrFAkDSlAu3hMGh8HGSWtApVDdEqLUToelyH6PEENai4XUYAH+TwJGVMLhTyiRq9FEhHWPpE9TCJNTDAEOYMsMyePCdMPiQy9fHYBXQklCbUMdRM1ERs3yQg9Bx0xlygnGQglRplgngT7owP3E9UDDwVDCUUHFwO5HDETMhUtBRGBKNsC9zbZLrcCk1aEARsFzw8pH+MQVEfkDu0InwJpA4cl7wAxFSUAGyKfCEdnAGOP3FMJLs8Iy2pwI3gDaxTrZRF3B5UOWwerHDcVwxzlcMxeD4YMKKezCV8BeQmdAWME5wgNNV+MpCBFZ1eLXBifIGVBQ14AAjUMaRWjRMGHfAKPD28SHwE5AXcHPQ0FAnsR8RFvEJkI74YINbkz/DopBFMhhyAVCisDU2zSCysm/Qz8bQGnEmYDEDRBd/Jnr2C6KBgBBx0yyUFkIfULlk/RDKAaxRhGVDIZ6AfDA/ca9yfuQVsGAwOnBxc6UTPyBMELbQiPCUMATQ6nGwfbGG4KdYzUATWPAbudA1uVhwJzkwY7Bw8Aaw+LBX3pACECqwinAAkA0wNbAD0CsQehAB0AiUUBQQMrMwEl6QKTA5cINc8BmTMB9y0EH8cMGQD7O25OAsO1AoBuZqYF4VwCkgJNOQFRKQQJUktVA7N15QDfAE8GF+NLARmvTs8e50cB43MvAMsA/wAJOQcJRQHRAfdxALsBYws1Caa3uQFR7S0AhwAZbwHbAo0A4QA5AIP1AVcAUQVd/QXXAlNNARU1HC9bZQG/AyMBNwERAH0Gz5GpzQsjBHEH1wIQHxXlAu8yB7kFAyLjE9FCyQK94lkAMhoKPAqrCqpgX2Q3CjV2PVQAEh+sPss/UgVVO1c7XDtXO1w7VztcO1c7XDtXO1wDm8Pmw+YKcF9JYe8Mqg3YRMw6TRPfYFVgNhPMLbsUxRXSJVoZQRrAJwkl6FUNDwgt12Y0CDA0eRfAAEMpbINFY4oeNApPHOtTlVT8LR8AtUumM7MNsBsZREQFS3XxYi4WEgomAmSFAmJGX1GzAV83JAKh+wJonAJmDQKfiDgfDwJmPwJmKgRyBIMDfxcDfpY5Cjl7GzmGOicnAmwhAjI6OA4CbcsCbbLzjgM3a0kvAWsA4gDlAE4JB5wMkQECD8YAEbkCdzMCdqZDAnlPRwJ4viFg30WyRvcCfEMCeswCfQ0CfPRIBEiBZygALxlJXEpfGRtK0ALRBQLQ0EsrA4hTA4fqRMmRNgLypV0HAwOyS9JMMSkH001QTbMCi0MCitzFHwshR2sJuwKOOwKOYESbhQKO3QKOYHxRuFM5AQ5S2FSJApP/ApMQAO0AIFUiVbNV1AosHymZijLleGpFPz0Cl6MC77ZYJawAXSkClpMCloCgAK1ZsFoNhVEAPwKWuQKWUlxIXNUCmc8CmWhczl0LHQKcnznGOqECnBoCn58CnryOACETNS4TAp31Ap6WALlBYThh8wKe1wKgcgGtAp6jIwKeUqljzGQrKS8CJ7MCJoICoP8CoFDbAqYzAqXSAqgDAIECp/ZogGi1AAdNaiBq1QKs5wKssgKtawKtBgJXIQJV4AKx5dsDH1JsmwKywRECsuwbbORtZ21MYwMl0QK2YD9DbpQDKUkCuGICuUsZArkue3A6cOUCvR0DLbYDMhUCvoxyBgMzdQK+HnMmc1MCw88CwwhzhnRPOUl05AM8qwEDPJ4DPcMCxYACxksCxhSNAshtVQLISALJUwLJMgJkoQLd1nh9ZXiyeSlL1AMYp2cGAmH4GfeVKHsPXpZevxUCz28Cz3AzT1fW9xejAMqxAs93AS3uA04Wfk8JAtwrAtuOAtJTA1JgA1NjAQUDVZCAjUMEzxrxZEl5A4LSg5EC2ssC2eKEFIRNp0ADhqkAMwNkEoZ1Xf0AWQLfaQLevHd7AuIz7RgB8zQrAfSfAfLWiwLr9wLpdH0DAur9AuroAP1LAb0C7o0C66CWrpcHAu5DA4XkmH1w5HGlAvMHAG0DjhqZlwL3FwORcgOSiwL3nAL53QL4apogmq+/O5siA52HAv7+AR8APZ8gAZ+3AwWRA6ZuA6bdANXJAwZuoYyiCQ0DDE0BEwEjB3EGZb1rCQC/BG/DFY8etxEAG3k9ACcDNxJRA42DAWcrJQCM8wAlAOanC6OVCLsGI6fJBgCvBRnDBvElRUYFFoAFcD9GSDNCKUK8X3kZX8QAls0FOgCQVCGbwTsuYDoZutcONxjOGJHJ/gVfBWAFXwVgBWsFYAVfBWAFXwVgBV8FYAVfBWBOHQjfjW8KCgoKbF7xMwTRA7kGN8PDAMMEr8MA70gxFroFTj5xPnhCR0K+X30/X/AAWBkzswCNBsxzzASm70aCRS4rDDMeLz49fnXfcsH5GcoscQFz13Y4HwVnBXLJycnACNdRYwgICAqEXoWTxgA7P4kACxbZBu21Kw0AjMsTAwkVAOVtJUUsJ1JCuULESUArXy9gPi9AKwnJRQYKTD9LPoA+iT54PnkCkULEUUpDX9NWV3JVEjQAc1w3A3IBE3YnX+g7QiMJb6MKaiszRCUuQrNCxDPMCcwEX9EWJzYREBEEBwIHKn6l33JCNVIfybPJtAltydPUCmhBZw/tEKsZAJOVJU1CLRuxbUHOQAo7P0s+eEJHHA8SJVRPdGM0NVrpvBoKhfUlM0JHHGUQUhEWO1xLSj8MO0ucNAqJIzVCRxv9EFsqKyA4OQgNj2nwZgp5ZNFgE2A1K3YHS2AhQQojJmC7DgpzGG1WYFUZCQYHZO9gHWCdYIVgu2BTYJlwFh8GvRbcXbG8YgtDHrMBwzPVyQonHQgkCyYBgQJ0Ajc4nVqIAwGSCsBPIgDsK3SWEtIVBa5N8gGjAo+kVwVIZwD/AEUSCDweX4ITrRQsJ8K3TwBXFDwEAB0TvzVcAtoTS20RIwDgVgZ9BBImYgA5AL4Coi8LFnezOkCnIQFjAY4KBAPh9RcGsgZSBsEAJctdsWIRu2kTkQstRw7DAcMBKgpPBGIGMDAwKCYnKTQaLg4AKRSVAFwCdl+YUZ0JdicFD3lPAdt1F9ZZKCGxuE3yBxkFVGcA/wBFEgiCBwAOLHQSjxOtQDg1z7deFRMAZ8QTAGtKb1ApIiPHADkAvgKiLy1DFtYCmBiDAlDDWNB0eo7fpaMO/aEVRRv0ATEQZBIODyMEAc8JQhCbDRgzFD4TAEMAu9YBCgCsAOkAm5I3ABwAYxvONnR+MhXJAxgKQyxL2+kkJhMbhQKDBMkSsvF0AD9BNQ6uQC7WqSQHwxEAEEIu1hkhAH2z4iQPwyJPHNWpdyYBRSpnJALzoBAEVPPsH20MxA0CCEQKRgAFyAtFAlMNwwjEDUQJRArELtapMg7DDZgJIw+TGukEIwvDFkMAqAtDEMMMBhioe+QAO3MMRAACrgnEBSPY9Q0FDnbSBoMAB8MSYxkSxAEJAPIJAAB8FWMOFtMc/HcXwxhDAC7DAvOowwAewwJdKDKHAAHDAALrFUQVwwAbwyvzpWMWv8wA/ABpAy++bcYDUKPD0KhDCwKmJ1MAAmMA5+UZwxAagwipBRL/eADfw6fDGOMCGsOjk3l6BwOpo4sAEsMOGxMAA5sAbcMOAAvDp0MJGkMDwgipnNIPAwfIqUMGAOGDAAPzABXDAAcDAAnDAGmTABrDAA7DChjDjnEWAwABYwAOcwAuUyYABsMAF8MIKQANUgC6wy4AA8MADqMq8wCyYgAcIwAB8wqpAAXOCx0V4wAHowBCwwEKAGnDAAuDAB3DAAjDCakABdIAbqcZ3QCZCCkABdIAAAFDAAfjAB2jCCkABqIACYMAGzMAbSMA5sOIAAhjAAhDABTDBAkpAAbSAOOTAAlDC6kOzPtnAAdDAG6kQFAATwAKwwwAA0MACbUDPwAHIwAZgwACE6cDAAojAApDAAoDp/MGwwAJIwADEwAQQwgAFEMAEXMAD5MADfMADcMAGRMOFiMAFUMAbqMWuwHDAMIAE0MLAGkzEgDhUwACQwAEWgAXgwUjAAbYABjDBSYBgzBaAEFNALcQBxUMegAwMngBrA0IZgJ0KxQHBREPd1N0ZzKRJwaIHAZqNT4DqQq8BwngAB4DAwt2AX56T1ocKQNXAh1GATQGC3tOxYNagkgAMQA5CQADAQEAWxLjAIOYNAEzAH7tFRk6TglSAF8NAAlYAQ+S1ACAQwQorQBiAN4dAJ1wPyeTANVzuQDX3AIeEMp9eyMgXiUAEdkBkJizKltbVVAaRMqRAAEAhyQ/SDEz6BmfVwB6ATEsOClKIRcDOF0E/832AFNt5AByAnkCRxGCOs94NjXdAwINGBonDBwPALW2AwICAgAAAAAAAAYDBQMDARrUAwAtAAAAAgEGBgYGBgYFBQUFBQUEBQYHCAkEBQUFBQQAAAICAAAAIgCNAJAAlT0A6gC7ANwApEQAwgCyAK0AqADuAKYA2gCjAOcBCAEDAMcAgQBiANIA1AEDAN4A8gCQAKkBMQDqAN8A3AsBCQ8yO9ra2tq8xuLT1tRJOB0BUgFcNU0BWgFpAWgBWwFMUUlLbhMBUxsNEAs6PhMOACcUKy0vMj5AQENDQ0RFFEYGJFdXV1dZWVhZL1pbXVxcI2NnZ2ZoZypsbnZ1eHh4eHh4enp6enp6enp6enp8fH18e2IARPIASQCaAHgAMgBm+ACOAFcAVwA3AnbvAIsABfj4AGQAk/IAnwBPAGIAZP//sACFAIUAaQBWALEAJAC2AIMCQAJDAPwA5wD+AP4A6AD/AOkA6QDoAOYALwJ7AVEBQAE+AVQBPgE+AT4BOQE4ATgBOAEcAVgXADEQCAEAUx8SHgsdHhYAjgCWAKYAUQBqIAIxAHYAbwCXAxUDJzIDIUlGTzEAkQJPAMcCVwKkAMAClgKWApYClgKWApYCiwKWApYClgKWApYClgKVApUCmAKgApcClgKWApQClAKUApQCkgKVAnUB1AKXAp8ClgKWApUeAIETBQD+DQOfAmECOh8BVBg9AuIZEjMbAU4/G1WZAXusRAFpYQEFA0FPAQYAmTEeIJdyADFoAHEANgCRA5zMk/C2jGINwjMWygIZCaXdfDILBCs5dAE7YnQBugDlhoiHhoiGiYqKhouOjIaNkI6Ij4qQipGGkoaThpSSlYaWhpeKmIaZhpqGm4aci52QnoqfhuIC4XTpAt90AIp0LHSoAIsAdHQEQwRABEIERQRDBEkERgRBBEcESQRIBEQERgRJAJ5udACrA490ALxuAQ10ANFZdHQA13QCFHQA/mJ0AP4BIQD+APwA/AD9APwDhGZ03ASMK23HAP4A/AD8AP0A/CR0dACRYnQA/gCRASEA/gCRAvQA/gCRA4RmdNwEjCttxyR0AP9idAEhAP4A/gD8APwA/QD8AP8A/AD8AP0A/AOEZnTcBIwrbcckdHQAkWJ0ASEA/gCRAP4AkQL0AP4AkQOEZnTcBIwrbcckdAJLAT50AlIBQXQCU8l0dAJfdHQDpgL0A6YDpgOnA6cDpwOnA4RmdNwEjCttxyR0dACRYnQBIQOmAJEDpgCRAvQDpgCRA4RmdNwEjCttxyR0BDh0AJEEOQCRDpU5dSgCADR03gV2CwArdAEFAM5iCnR0AF1iAAYcOgp0dACRCnQAXAEIwWZ0CnRmdHQAkWZ0CnRmdEXgAFF03gp0dEY0tlT2u3SOAQTwscwhjZZKrhYcBSfFp9XNbKiVDOD2b+cpe4/Z17mQnbtzzhaeQtE2GGj0IDNTjRUSyTxxw/RPHW/+vS7d1NfRt9z9QPZg4X7QFfhCnkvgNPIItOsC2eV6hPannZNHlZ9xrwZXIMOlu3jSoQSq78WEjwLjw1ELSlF1aBvfzwk5ZX7AUvQzjPQKbDuQ+sm4wNOp4A6AdVuRS0t1y/DZpg4R6m7FNjM9HgvW7Bi88zaMjOo6lM8wtBBdj8LP4ylv3zCXPhebMKJc066o9sF71oFW/8JXu86HJbwDID5lzw5GWLR/LhT0Qqnp2JQxNZNfcbLIzPy+YypqRm/lBmGmex+82+PisxUumSeJkALIT6rJezxMH+CTJmQtt5uwTVbL3ptmjDUQzlSIvWi8Tl7ng1NpuRn1Ng4n14Qc+3Iil7OwkvNWogLSPkn3pihIFytyIGmMhOe3n1tWsuMy9BdKyqF4Z3v2SgggTL9KVvMXPnCbRe+oOuFFP3HejBG/w9gvmfNYvg6JuWia2lcSSN1uIjBktzoIazOHPJZ7kKHPz8mRWVdW3lA8WGF9dQF6Bm673boov3BUWDU2JNcahR23GtfHKLOz/viZ+rYnZFaIznXO67CYEJ1fXuTRpZhYZkKe54xeoagkNGLs+NTZHE0rX45/XvQ2RGADX6vcAvdxIUBV27wxGm2zjZo4X3ILgAlrOFheuZ6wtsvaIj4yLY7qqawlliaIcrz2G+c3vscAnCkCuMzMmZvMfu9lLwTvfX+3cVSyPdN9ZwgDZhfjRgNJcLiJ67b9xx8JHswprbiE3v9UphotAPIgnXVIN5KmMc0piXhc6cChPnN+MRhG9adtdttQTTwSIpl8I4/j//d3sz1326qTBTpPRM/Hgh3kzqEXs8ZAk4ErQhNO8hzrQ0DLkWMA/N+91tn2MdOJnWC2FCZehkQrwzwbKOjhvZsbM95QoeL9skYyMf4srVPVJSgg7pOLUtr/n9eT99oe9nLtFRpjA9okV2Kj8h9k5HaC0oivRD8VyXkJ81tcd4fHNXPCfloIQasxsuO18/46dR2jgul/UIet2G0kRvnyONMKhHs6J26FEoqSqd+rfYjeEGwHWVDpX1fh1jBBcKGMqRepju9Y00mDVHC+Xdij/j44rKfvfjGinNs1jO/0F3jB83XCDINN/HB84axlP+3E/klktRo+vl3U/aiyMJbIodE1XSsDn6UAzIoMtUObY2+k/4gY/l+AkZJ5Sj2vQrkyLm3FoxjhDX+31UXBFf9XrAH31fFqoBmDEZvhvvpnZ87N+oZEu7U9O/nnk+QWj3x8uyoRbEnf+O5UMr9i0nHP38IF5AvzrBW8YWBUR0mIAzIvndQq9N3v/Jto3aPjPXUPl8ASdPPyAp7jENf8bk7VMM9ol9XGmlBmeDMuGqt+WzuL6CXAxXjIhCPM5vACchgMJ/8XBGLO/D1isVvGhwwHHr1DLaI5mn2Jr/b1pUD90uciDaS8cXNDzCWvNmT/PhQe5e8nTnnnkt8Ds/SIjibcum/fqDhKopxAY8AkSrPn+IGDEKOO+U3XOP6djFs2H5N9+orhOahiQk5KnEUWa+CzkVzhp8bMHRbg81qhjjXuIKbHjSLSIBKWqockGtKinY+z4/RdBUF6pcc3JmnlxVcNgrI4SEzKUZSwcD2QCyxzKve+gAmg6ZuSRkpPFa6mfThu7LJNu3H5K42uCpNvPAsoedolKV/LHe/eJ+BbaG5MG0NaSGVPRUmNFMFFSSpXEcXwbVh7UETOZZtoVNRGOIbbkig3McEtR68cG0RZAoJevWYo7Dg/lZ1CQzblWeUvVHmr8fY4Nqd9JJiH/zEX24mJviH60fAyFr0A3c4bC1j3yZU60VgJxXn8JgJXLUIsiBnmKmMYz+7yBQFBvqb2eYnuW59joZBf56/wXvWIR4R8wTmV80i1mZy+S4+BUES+hzjk0uXpC///z/IlqHZ1monzlXp8aCfhGKMti73FI1KbL1q6IKO4fuBuZ59gagjn5xU79muMpHXg6S+e+gDM/U9BKLHbl9l6o8czQKl4RUkJJiqftQG2i3BMg/TQlUYFkJDYBOOvAugYuzYSDnZbDDd/aSd9x0Oe6F+bJcHfl9+gp6L5/TgA+BdFFovbfCrQ40s5vMPw8866pNX8zyFGeFWdxIpPVp9Rg1UPOVFbFZrvaFq/YAzHQgqMWpahMYfqHpmwXfHL1/kpYmGuHFwT55mQu0dylfNuq2Oq0hTMCPwqfxnuBIPLXfci4Y1ANy+1CUipQxld/izVh16WyG2Q0CQQ9NqtAnx1HCHwDj7sYxOSB0wopZSnOzxQOcExmxrVTF2BkOthVpGfuhaGECfCJpJKpjnihY+xOT2QJxN61+9K6QSqtv2Shr82I3jgJrqBg0wELFZPjvHpvzTtaJnLK6Vb97Yn933koO/saN7fsjwNKzp4l2lJVx2orjCGzC/4ZL4zCver6aQYtC5sdoychuFE6ufOiog+VWi5UDkbmvmtah/3aArEBIi39s5ILUnlFLgilcGuz9CQshEY7fw2ouoILAYPVT/gyAIq3TFAIwVsl+ktkRz/qGfnCDGrm5gsl/l9QdvCWGsjPz3dU7XuqKfdUrr/6XIgjp4rey6AJBmCmUJMjITHVdFb5m1p+dLMCL8t55zD42cmftmLEJC0Da04YiRCVUBLLa8D071/N5UBNBXDh0LFsmhV/5B5ExOB4j3WVG/S3lfK5o+V6ELHvy6RR9n4ac+VsK4VE4yphPvV+kG9FegTBH4ZRXL2HytUHCduJazB/KykjfetYxOXTLws267aGOd+I+JhKP//+VnXmS90OD/jvLcVu0asyqcuYN1mSb6XTlCkqv1vigZPIYwNF/zpWcT1GR/6aEIRjkh0yhg4LXJfaGobYJTY4JI58KiAKgmmgAKWdl5nYCeLqavRJGQNuYuZtZFGx+IkI4w4NS2xwbetNMunOjBu/hmKCI/w7tfiiyUd//4rbTeWt4izBY8YvGIN6vyKYmP/8X8wHKCeN+WRcKM70+tXKNGyevU9H2Dg5BsljnTf8YbsJ1TmMs74Ce2XlHisleguhyeg44rQOHZuw/6HTkhnnurK2d62q6yS7210SsAIaR+jXMQA+svkrLpsUY+F30Uw89uOdGAR6vo4FIME0EfVVeHTu6eKicfhSqOeXJhbftcd08sWEnNUL1C9fnprTgd83IMut8onVUF0hvqzZfHduPjbjwEXIcoYmy+P6tcJZHmeOv6VrvEdkHDJecjHuHeWANe79VG662qTjA/HCvumVv3qL+LrOcpqGps2ZGwQdFJ7PU4iuyRlBrwfO+xnPyr47s2cXVbWzAyznDiBGjCM3ksxjjqM62GE9C8f5U38kB3VjtabKp/nRdvMESPGDG90bWRLAt1Qk5DyLuazRR1YzdC1c+hZXvAWV8xA72S4A8B67vjVhbba3MMop293FeEXpe7zItMWrJG/LOH9ByOXmYnNJfjmfuX9KbrpgLOba4nZ+fl8Gbdv/ihv+6wFGKHCYrVwmhFC0J3V2bn2tIB1wCc1CST3d3X2OyxhguXcs4sm679UngzofuSeBewMFJboIQHbUh/m2JhW2hG9DIvG2t7yZIzKBTz9wBtnNC+2pCRYhSIuQ1j8xsz5VvqnyUIthvuoyyu7fNIrg/KQUVmGQaqkqZk/Vx5b33/gsEs8yX7SC1J+NV4icz6bvIE7C5G6McBaI8rVg56q5QBJWxn/87Q1sPK4+sQa8fLU5gXo4paaq4cOcQ4wR0VBHPGjKh+UlPCbA1nLXyEUX45qZ8J7/Ln4FPJE2TdzD0Z8MLSNQiykMMmSyOCiFfy84Rq60emYB2vD09KjYwsoIpeDcBDTElBbXxND72yhd9pC/1CMid/5HUMvAL27OtcIJDzNKpRPNqPOpyt2aPGz9QWIs9hQ9LiX5s8m9hjTUu/f7MyIatjjd+tSfQ3ufZxPpmJhTaBtZtKLUcfOCUqADuO+QoH8B9v6U+P0HV1GLQmtoNFTb3s74ivZgjES0qfK+8RdGgBbcCMSy8eBvh98+et1KIFqSe1KQPyXULBMTsIYnysIwiZBJYdI20vseV+wuJkcqGemehKjaAb9L57xZm3g2zX0bZ2xk/fU+bCo7TlnbW7JuF1YdURo/2Gw7VclDG1W7LOtas2LX4upifZ/23rzpsnY/ALfRgrcWP5hYmV9VxVOQA1fZvp9F2UNU+7d7xRyVm5wiLp3/0dlV7vdw1PMiZrbDAYzIVqEjRY2YU03sJhPnlwIPcZUG5ltL6S8XCxU1eYS5cjr34veBmXAvy7yN4ZjArIG0dfD/5UpBNlX1ZPoxJOwyqRi3wQWtOzd4oNKh0LkoTm8cwqgIfKhqqGOhwo71I+zXnMemTv2B2AUzABWyFztGgGULjDDzWYwJUVBTjKCn5K2QGMK1CQT7SzziOjo+BhAmqBjzuc3xYym2eedGeOIRJVyTwDw37iCMe4g5Vbnsb5ZBdxOAnMT7HU4DHpxWGuQ7GeiY30Cpbvzss55+5Km1YsbD5ea3NI9QNYIXol5apgSu9dZ8f8xS5dtHpido5BclDuLWY4lhik0tbJa07yJhH0BOyEut/GRbYTS6RfiTYWGMCkNpfSHi7HvdiTglEVHKZXaVhezH4kkXiIvKopYAlPusftpE4a5IZwvw1x/eLvoDIh/zpo9FiQInsTb2SAkKHV42XYBjpJDg4374XiVb3ws4qM0s9eSQ5HzsMU4OZJKuopFjBM+dAZEl8RUMx5uU2N486Kr141tVsGQfGjORYMCJAMsxELeNT4RmWjRcpdTGBwcx6XN9drWqPmJzcrGrH4+DRc7+n1w3kPZwu0BkNr6hQrqgo7JTB9A5kdJ/H7P4cWBMwsmuixAzJB3yrQpnGIq90lxAXLzDCdn1LPibsRt7rHNjgQBklRgPZ8vTbjXdgXrTWQsK5MdrXXQVPp0Rinq3frzZKJ0qD6Qhc40VzAraUXlob1gvkhK3vpmHgI6FRlQZNx6eRqkp0zy4AQlX813fAPtL3jMRaitGFFjo0zmErloC+h+YYdVQ6k4F/epxAoF0BmqEoKNTt6j4vQZNQ2BoqF9Vj53TOIoNmDiu9Xp15RkIgQIGcoLpfoIbenzpGUAtqFJp5W+LLnx38jHeECTJ/navKY1NWfN0sY1T8/pB8kIH3DU3DX+u6W3YwpypBMYOhbSxGjq84RZ84fWJow8pyHqn4S/9J15EcCMsXqrfwyd9mhiu3+rEo9pPpoJkdZqHjra4NvzFwuThNKy6hao/SlLw3ZADUcUp3w3SRVfW2rhl80zOgTYnKE0Hs2qp1J6H3xqPqIkvUDRMFDYyRbsFI3M9MEyovPk8rlw7/0a81cDVLmBsR2ze2pBuKb23fbeZC0uXoIvDppfTwIDxk1Oq2dGesGc+oJXWJLGkOha3CX+DUnzgAp9HGH9RsPZN63Hn4RMA5eSVhPHO+9RcRb/IOgtW31V1Q5IPGtoxPjC+MEJbVlIMYADd9aHYWUIQKopuPOHmoqSkubnAKnzgKHqgIOfW5RdAgotN6BN+O2ZYHkuemLnvQ8U9THVrS1RtLmKbcC7PeeDsYznvqzeg6VCNwmr0Yyx1wnLjyT84BZz3EJyCptD3yeueAyDWIs0L2qs/VQ3HUyqfrja0V1LdDzqAikeWuV4sc7RLIB69jEIBjCkyZedoUHqCrOvShVzyd73OdrJW0hPOuQv2qOoHDc9xVb6Yu6uq3Xqp2ZaH46A7lzevbxQEmfrzvAYSJuZ4WDk1Hz3QX1LVdiUK0EvlAGAYlG3Md30r7dcPN63yqBCIj25prpvZP0nI4+EgWoFG95V596CurXpKRBGRjQlHCvy5Ib/iW8nZJWwrET3mgd6mEhfP4KCuaLjopWs7h+MdXFdIv8dHQJgg1xi1eYqB0uDYjxwVmri0Sv5XKut/onqapC+FQiC2C1lvYJ9MVco6yDYsS3AANUfMtvtbYI2hfwZatiSsnoUeMZd34GVjkMMKA+XnjJpXgRW2SHTZplVowPmJsvXy6w3cfO1AK2dvtZEKTkC/TY9LFiKHCG0DnrMQdGm2lzlBHM9iEYynH2UcVMhUEjsc0oDBTgo2ZSQ1gzkAHeWeBXYFjYLuuf8yzTCy7/RFR81WDjXMbq2BOH5dURnxo6oivmxL3cKzKInlZkD31nvpHB9Kk7GfcfE1t+1V64b9LtgeJGlpRFxQCAqWJ5DoY77ski8gsOEOr2uywZaoO/NGa0X0y1pNQHBi3b2SUGNpcZxDT7rLbBf1FSnQ8guxGW3W+36BW0gBje4DOz6Ba6SVk0xiKgt+q2JOFyr4SYfnu+Ic1QZYIuwHBrgzr6UvOcSCzPTOo7D6IC4ISeS7zkl4h+2VoeHpnG/uWR3+ysNgPcOIXQbv0n4mr3BwQcdKJxgPSeyuP/z1Jjg4e9nUvoXegqQVIE30EHx5GHv+FAVUNTowYDJgyFhf5IvlYmEqRif6+WN1MkEJmDcQITx9FX23a4mxy1AQRsOHO/+eImX9l8EMJI3oPWzVXxSOeHU1dUWYr2uAA7AMb+vAEZSbU3qob9ibCyXeypEMpZ6863o6QPqlqGHZkuWABSTVNd4cOh9hv3qEpSx2Zy/DJMP6cItEmiBJ5PFqQnDEIt3NrA3COlOSgz43D7gpNFNJ5MBh4oFzhDPiglC2ypsNU4ISywY2erkyb1NC3Qh/IfWj0eDgZI4/ln8WPfBsT3meTjq1Uqt1E7Zl/qftqkx6aM9KueMCekSnMrcHj1CqTWWzEzPsZGcDe3Ue4Ws+XFYVxNbOFF8ezkvQGR6ZOtOLU2lQEnMBStx47vE6Pb7AYMBRj2OOfZXfisjJnpTfSNjo6sZ6qSvNxZNmDeS7Gk3yYyCk1HtKN2UnhMIjOXUzAqDv90lx9O/q/AT1ZMnit5XQe9wmQxnE/WSH0CqZ9/2Hy+Sfmpeg8RwsHI5Z8kC8H293m/LHVVM/BA7HaTJYg5Enk7M/xWpq0192ACfBai2LA/qrCjCr6Dh1BIMzMXINBmX96MJ5Hn2nxln/RXPFhwHxUmSV0EV2V0jm86/dxxuYSU1W7sVkEbN9EzkG0QFwPhyHKyb3t+Fj5WoUUTErcazE/N6EW6Lvp0d//SDPj7EV9UdJN+Amnf3Wwk3A0SlJ9Z00yvXZ7n3z70G47Hfsow8Wq1JXcfwnA+Yxa5mFsgV464KKP4T31wqIgzFPd3eCe3j5ory5fBF2hgCFyVFrLzI9eetNXvM7oQqyFgDo4CTp/hDV9NMX9JDHQ/nyHTLvZLNLF6ftn2OxjGm8+PqOwhxnPHWipkE/8wbtyri80Sr7pMNkQGMfo4ZYK9OcCC4ESVFFbLMIvlxSoRqWie0wxqnLfcLSXMSpMMQEJYDVObYsXIQNv4TGNwjq1kvT1UOkicTrG3IaBZ3XdScS3u8sgeZPVpOLkbiF940FjbCeNRINNvDbd01EPBrTCPpm12m43ze1bBB59Ia6Ovhnur/Nvx3IxwSWol+3H2qfCJR8df6aQf4v6WiONxkK+IqT4pKQrZK/LplgDI/PJZbOep8dtbV7oCr6CgfpWa8NczOkPx81iSHbsNhVSJBOtrLIMrL31LK9TqHqAbAHe0RLmmV806kRLDLNEhUEJfm9u0sxpkL93Zgd6rw+tqBfTMi59xqXHLXSHwSbSBl0EK0+loECOPtrl+/nsaFe197di4yUgoe4jKoAJDXc6DGDjrQOoFDWZJ9HXwt8xDrQP+7aRwWKWI1GF8s8O4KzxWBBcwnl3vnl1Oez3oh6Ea1vjR7/z7DDTrFtqU2W/KAEzAuXDNZ7MY73MF216dzdSbWmUp4lcm7keJfWaMHgut9x5C9mj66Z0lJ+yhsjVvyiWrfk1lzPOTdhG15Y7gQlXtacvI7qv/XNSscDwqkgwHT/gUsD5yB7LdRRvJxQGYINn9hTpodKFVSTPrtGvyQw+HlRFXIkodErAGu9Iy1YpfSPc3jkFh5CX3lPxv7aqjE/JAfTIpEjGb/H7MO0e2vsViSW1qa/Lmi4/n4DEI3g7lYrcanspDfEpKkdV1OjSLOy0BCUqVoECaB55vs06rXl4jqmLsPsFM/7vYJ0vrBhDCm/00A/H81l1uekJ/6Lml3Hb9+NKiLqATJmDpyzfYZFHumEjC662L0Bwkxi7E9U4cQA0XMVDuMYAIeLMPgQaMVOd8fmt5SflFIfuBoszeAw7ow5gXPE2Y/yBc/7jExARUf/BxIHQBF5Sn3i61w4z5xJdCyO1F1X3+3ax+JSvMeZ7S6QSKp1Fp/sjYz6Z+VgCZzibGeEoujryfMulH7Rai5kAft9ebcW50DyJr2uo2z97mTWIu45YsSnNSMrrNUuG1XsYBtD9TDYzQffKB87vWbkM4EbPAFgoBV4GQS+vtFDUqOFAoi1nTtmIOvg38N4hT2Sn8r8clmBCXspBlMBYTnrqFJGBT3wZOzAyJDre9dHH7+x7qaaKDOB4UQALD5ecS0DE4obubQEiuJZ0EpBVpLuYcce8Aa4PYd/V4DLDAJBYKQPCWTcrEaZ5HYbJi11Gd6hjGom1ii18VHYnG28NKpkz2UKVPxlhYSp8uZr367iOmoy7zsxehW9wzcy2zG0a80PBMCRQMb32hnaHeOR8fnNDzZhaNYhkOdDsBUZ3loDMa1YP0uS0cjUP3b/6DBlqmZOeNABDsLl5BI5QJups8uxAuWJdkUB/pO6Zax6tsg7fN5mjjDgMGngO+DPcKqiHIDbFIGudxtPTIyDi9SFMKBDcfdGQRv41q1AqmxgkVfJMnP8w/Bc7N9/TR6C7mGObFqFkIEom8sKi2xYqJLTCHK7cxzaZvqODo22c3wisBCP4HeAgcRbNPAsBkNRhSmD48dHupdBRw4mIvtS5oeF6zeT1KMCyhMnmhpkFAGWnGscoNkwvQ8ZM5lE/vgTHFYL99OuNxdFBxTEDd5v2qLR8y9WkXsWgG6kZNndFG+pO/UAkOCipqIhL3hq7cRSdrCq7YhUsTocEcnaFa6nVkhnSeRYUA1YO0z5itF9Sly3VlxYDw239TJJH6f3EUfYO5lb7bcFcz8Bp7Oo8QmnsUHOz/fagVUBtKEw1iT88j+aKkv8cscKNkMxjYr8344D1kFoZ7/td1W6LCNYN594301tUGRmFjAzeRg5vyoM1F6+bJZ/Q54jN/k8SFd3DxPTYaAUsivsBfgTn7Mx8H2SpPt4GOdYRnEJOH6jHM2p6SgB0gzIRq6fHxGMmSmqaPCmlfwxiuloaVIitLGN8wie2CDWhkzLoCJcODh7KIOAqbHEvXdUxaS4TTTs07Clzj/6GmVs9kiZDerMxEnhUB6QQPlcfqkG9882RqHoLiHGBoHfQuXIsAG8GTAtao2KVwRnvvam8jo1e312GQAKWEa4sUVEAMG4G6ckcONDwRcg1e2D3+ohXgY4UAWF8wHKQMrSnzCgfFpsxh+aHXMGtPQroQasRY4U6UdG0rz1Vjbka0MekOGRZQEvqQFlxseFor8zWFgHek3v29+WqN6gaK5gZOTOMZzpQIC1201LkMCXild3vWXSc5UX9xcFYfbRPzGFa1FDcPfPB/jUEq/FeGt419CI3YmBlVoHsa4KdcwQP5ZSwHHhFJ7/Ph/Rap/4vmG91eDwPP0lDfCDRCLszTqfzM71xpmiKi2HwS4WlqvGNwtvwF5Dqpn6KTq8ax00UMPkxDcZrEEEsIvHiUXXEphdb4GB4FymlPwBz4Gperqq5pW7TQ6/yNRhW8VT5NhuP0udlxo4gILq5ZxAZk8ZGh3g4CqxJlPKY7AQxupfUcVpWT5VItp1+30UqoyP4wWsRo3olRRgkWZZ2ZN6VC3OZFeXB8NbnUrSdikNptD1QiGuKkr8EmSR/AK9Rw+FF3s5uwuPbvHGiPeFOViltMK7AUaOsq9+x9cndk3iJEE5LKZRlWJbKOZweROzmPNVPkjE3K/TyA57Rs68TkZ3MR8akKpm7cFjnjPd/DdkWjgYoKHSr5Wu5ssoBYU4acRs5g2DHxUmdq8VXOXRbunD8QN0LhgkssgahcdoYsNvuXGUK/KXD/7oFb+VGdhqIn02veuM5bLudJOc2Ky0GMaG4W/xWBxIJcL7yliJOXOpx0AkBqUgzlDczmLT4iILXDxxtRR1oZa2JWFgiAb43obrJnG/TZC2KSK2wqOzRZTXavZZFMb1f3bXvVaNaK828w9TO610gk8JNf3gMfETzXXsbcvRGCG9JWQZ6+cDPqc4466Yo2RcKH+PILeKOqtnlbInR3MmBeGG3FH10yzkybuqEC2HSQwpA0An7d9+73BkDUTm30bZmoP/RGbgFN+GrCOfADgqr0WbI1a1okpFms8iHYw9hm0zUvlEMivBRxModrbJJ+9/p3jUdQQ9BCtQdxnOGrT5dzRUmw0593/mbRSdBg0nRvRZM5/E16m7ZHmDEtWhwvfdZCZ8J8M12W0yRMszXamWfQTwIZ4ayYktrnscQuWr8idp3PjT2eF/jmtdhIfcpMnb+IfZY2FebW6UY/AK3jP4u3Tu4zE4qlnQgLFbM19EBIsNf7KhjdbqQ/D6yiDb+NlEi2SKD+ivXVUK8ib0oBo366gXkR8ZxGjpJIDcEgZPa9TcYe0TIbiPl/rPUQDu3XBJ9X/GNq3FAUsKsll57DzaGMrjcT+gctp+9MLYXCq+sqP81eVQ0r9lt+gcQfZbACRbEjvlMskztZG8gbC8Qn9tt26Q7y7nDrbZq/LEz7kR6Jc6pg3N9rVX8Y5MJrGlML9p9lU4jbTkKqCveeZUJjHB03m2KRKR2TytoFkTXOLg7keU1s1lrPMQJpoOKLuAAC+y1HlJucU6ysB5hsXhvSPPLq5J7JtnqHKZ4vYjC4Vy8153QY+6780xDuGARsGbOs1WqzH0QS765rnSKEbbKlkO8oI/VDwUd0is13tKpqILu1mDJFNy/iJAWcvDgjxvusIT+PGz3ST/J9r9Mtfd0jpaGeiLYIqXc7DiHSS8TcjFVksi66PEkxW1z6ujbLLUGNNYnzOWpH8BZGK4bCK7iR+MbIv8ncDAz1u4StN3vTTzewr9IQjk9wxFxn+6N1ddKs0vffJiS08N3a4G1SVrlZ97Q/M+8G9fe5AP6d9/Qq4WRnORVhofPIKEdCr3llspUfE0oKIIYoByBRPh+bX1HLS3JWGJRhIvE1aW4NTd8ePi4Z+kXb+Z8snYfSNcqijhAgVsx4RCM54cXUiYkjeBmmC4ajOHrChoELscJJC7+9jjMjw5BagZKlgRMiSNYz7h7vvZIoQqbtQmspc0cUk1G/73iXtSpROl5wtLgQi0mW2Ex8i3WULhcggx6E1LMVHUsdc9GHI1PH3U2Ko0PyGdn9KdVOLm7FPBui0i9a0HpA60MsewVE4z8CAt5d401Gv6zXlIT5Ybit1VIA0FCs7wtvYreru1fUyW3oLAZ/+aTnZrOcYRNVA8spoRtlRoWflsRClFcgzkqiHOrf0/SVw+EpVaFlJ0g4Kxq1MMOmiQdpMNpte8lMMQqm6cIFXlnGbfJllysKDi+0JJMotkqgIxOSQgU9dn/lWkeVf8nUm3iwX2Nl3WDw9i6AUK3vBAbZZrcJpDQ/N64AVwjT07Jef30GSSmtNu2WlW7YoyW2FlWfZFQUwk867EdLYKk9VG6JgEnBiBxkY7LMo4YLQJJlAo9l/oTvJkSARDF/XtyAzM8O2t3eT/iXa6wDN3WewNmQHdPfsxChU/KtLG2Mn8i4ZqKdSlIaBZadxJmRzVS/o4yA65RTSViq60oa395Lqw0pzY4SipwE0SXXsKV+GZraGSkr/RW08wPRvqvSUkYBMA9lPx4m24az+IHmCbXA+0faxTRE9wuGeO06DIXa6QlKJ3puIyiuAVfPr736vzo2pBirS+Vxel3TMm3JKhz9o2ZoRvaFVpIkykb0Hcm4oHFBMcNSNj7/4GJt43ogonY2Vg4nsDQIWxAcorpXACzgBqQPjYsE/VUpXpwNManEru4NwMCFPkXvMoqvoeLN3qyu/N1eWEHttMD65v19l/0kH2mR35iv/FI+yjoHJ9gPMz67af3Mq/BoWXqu3rphiWMXVkmnPSEkpGpUI2h1MThideGFEOK6YZHPwYzMBvpNC7+ZHxPb7epfefGyIB4JzO9DTNEYnDLVVHdQyvOEVefrk6Uv5kTQYVYWWdqrdcIl7yljwwIWdfQ/y+2QB3eR/qxYObuYyB4gTbo2in4PzarU1sO9nETkmj9/AoxDA+JM3GMqQtJR4jtduHtnoCLxd1gQUscHRB/MoRYIEsP2pDZ9KvHgtlk1iTbWWbHhohwFEYX7y51fUV2nuUmnoUcqnWIQAAgl9LTVX+Bc0QGNEhChxHR4YjfE51PUdGfsSFE6ck7BL3/hTf9jLq4G1IafINxOLKeAtO7quulYvH5YOBc+zX7CrMgWnW47/jfRsWnJjYYoE7xMfWV2HN2iyIqLI';
- const FENCED = new Map([[8217,"apostrophe"],[8260,"fraction slash"],[12539,"middle dot"]]);
- const NSM_MAX = 4;
- function decode_arithmetic(bytes) {
- let pos = 0;
- function u16() { return (bytes[pos++] << 8) | bytes[pos++]; }
-
- // decode the frequency table
- let symbol_count = u16();
- let total = 1;
- let acc = [0, 1]; // first symbol has frequency 1
- for (let i = 1; i < symbol_count; i++) {
- acc.push(total += u16());
- }
- // skip the sized-payload that the last 3 symbols index into
- let skip = u16();
- let pos_payload = pos;
- pos += skip;
- let read_width = 0;
- let read_buffer = 0;
- function read_bit() {
- if (read_width == 0) {
- // this will read beyond end of buffer
- // but (undefined|0) => zero pad
- read_buffer = (read_buffer << 8) | bytes[pos++];
- read_width = 8;
- }
- return (read_buffer >> --read_width) & 1;
- }
- const N = 31;
- const FULL = 2**N;
- const HALF = FULL >>> 1;
- const QRTR = HALF >> 1;
- const MASK = FULL - 1;
- // fill register
- let register = 0;
- for (let i = 0; i < N; i++) register = (register << 1) | read_bit();
- let symbols = [];
- let low = 0;
- let range = FULL; // treat like a float
- while (true) {
- let value = Math.floor((((register - low + 1) * total) - 1) / range);
- let start = 0;
- let end = symbol_count;
- while (end - start > 1) { // binary search
- let mid = (start + end) >>> 1;
- if (value < acc[mid]) {
- end = mid;
- } else {
- start = mid;
- }
- }
- if (start == 0) break; // first symbol is end mark
- symbols.push(start);
- let a = low + Math.floor(range * acc[start] / total);
- let b = low + Math.floor(range * acc[start+1] / total) - 1;
- while (((a ^ b) & HALF) == 0) {
- register = (register << 1) & MASK | read_bit();
- a = (a << 1) & MASK;
- b = (b << 1) & MASK | 1;
- }
- while (a & ~b & QRTR) {
- register = (register & HALF) | ((register << 1) & (MASK >>> 1)) | read_bit();
- a = (a << 1) ^ HALF;
- b = ((b ^ HALF) << 1) | HALF | 1;
- }
- low = a;
- range = 1 + b - a;
- }
- let offset = symbol_count - 4;
- return symbols.map(x => { // index into payload
- switch (x - offset) {
- case 3: return offset + 0x10100 + ((bytes[pos_payload++] << 16) | (bytes[pos_payload++] << 8) | bytes[pos_payload++]);
- case 2: return offset + 0x100 + ((bytes[pos_payload++] << 8) | bytes[pos_payload++]);
- case 1: return offset + bytes[pos_payload++];
- default: return x - 1;
- }
- });
- }
- // returns an iterator which returns the next symbol
- function read_payload(v) {
- let pos = 0;
- return () => v[pos++];
- }
- function read_compressed_payload(s) {
- return read_payload(decode_arithmetic(unsafe_atob(s)));
- }
- // unsafe in the sense:
- // expected well-formed Base64 w/o padding
- // 20220922: added for https://github.com/adraffy/ens-normalize.js/issues/4
- function unsafe_atob(s) {
- let lookup = [];
- [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'].forEach((c, i) => lookup[c.charCodeAt(0)] = i);
- let n = s.length;
- let ret = new Uint8Array((6 * n) >> 3);
- for (let i = 0, pos = 0, width = 0, carry = 0; i < n; i++) {
- carry = (carry << 6) | lookup[s.charCodeAt(i)];
- width += 6;
- if (width >= 8) {
- ret[pos++] = (carry >> (width -= 8));
- }
- }
- return ret;
- }
- // eg. [0,1,2,3...] => [0,-1,1,-2,...]
- function signed(i) {
- return (i & 1) ? (~i >> 1) : (i >> 1);
- }
- function read_deltas(n, next) {
- let v = Array(n);
- for (let i = 0, x = 0; i < n; i++) v[i] = x += signed(next());
- return v;
- }
- // [123][5] => [0 3] [1 1] [0 0]
- function read_sorted(next, prev = 0) {
- let ret = [];
- while (true) {
- let x = next();
- let n = next();
- if (!n) break;
- prev += x;
- for (let i = 0; i < n; i++) {
- ret.push(prev + i);
- }
- prev += n + 1;
- }
- return ret;
- }
- function read_sorted_arrays(next) {
- return read_array_while(() => {
- let v = read_sorted(next);
- if (v.length) return v;
- });
- }
- // returns map of x => ys
- function read_mapped(next) {
- let ret = [];
- while (true) {
- let w = next();
- if (w == 0) break;
- ret.push(read_linear_table(w, next));
- }
- while (true) {
- let w = next() - 1;
- if (w < 0) break;
- ret.push(read_replacement_table(w, next));
- }
- return ret.flat();
- }
- // read until next is falsy
- // return array of read values
- function read_array_while(next) {
- let v = [];
- while (true) {
- let x = next(v.length);
- if (!x) break;
- v.push(x);
- }
- return v;
- }
- // read w columns of length n
- // return as n rows of length w
- function read_transposed(n, w, next) {
- let m = Array(n).fill().map(() => []);
- for (let i = 0; i < w; i++) {
- read_deltas(n, next).forEach((x, j) => m[j].push(x));
- }
- return m;
- }
-
- // returns [[x, ys], [x+dx, ys+dy], [x+2*dx, ys+2*dy], ...]
- // where dx/dy = steps, n = run size, w = length of y
- function read_linear_table(w, next) {
- let dx = 1 + next();
- let dy = next();
- let vN = read_array_while(next);
- let m = read_transposed(vN.length, 1+w, next);
- return m.flatMap((v, i) => {
- let [x, ...ys] = v;
- return Array(vN[i]).fill().map((_, j) => {
- let j_dy = j * dy;
- return [x + j * dx, ys.map(y => y + j_dy)];
- });
- });
- }
- // return [[x, ys...], ...]
- // where w = length of y
- function read_replacement_table(w, next) {
- let n = 1 + next();
- let m = read_transposed(n, 1+w, next);
- return m.map(v => [v[0], v.slice(1)]);
- }
- function read_trie(next) {
- let ret = [];
- let sorted = read_sorted(next);
- expand(decode([]), []);
- return ret; // not sorted
- function decode(Q) { // characters that lead into this node
- let S = next(); // state: valid, save, check
- let B = read_array_while(() => { // buckets leading to new nodes
- let cps = read_sorted(next).map(i => sorted[i]);
- if (cps.length) return decode(cps);
- });
- return {S, B, Q};
- }
- function expand({S, B}, cps, saved) {
- if (S & 4 && saved === cps[cps.length-1]) return;
- if (S & 2) saved = cps[cps.length-1];
- if (S & 1) ret.push(cps);
- for (let br of B) {
- for (let cp of br.Q) {
- expand(br, [...cps, cp], saved);
- }
- }
- }
- }
- function hex_cp(cp) {
- return cp.toString(16).toUpperCase().padStart(2, '0');
- }
- function quote_cp(cp) {
- return `{${hex_cp(cp)}}`; // raffy convention: like "\u{X}" w/o the "\u"
- }
- /*
- export function explode_cp(s) {
- return [...s].map(c => c.codePointAt(0));
- }
- */
- function explode_cp(s) { // this is about 2x faster
- let cps = [];
- for (let pos = 0, len = s.length; pos < len; ) {
- let cp = s.codePointAt(pos);
- pos += cp < 0x10000 ? 1 : 2;
- cps.push(cp);
- }
- return cps;
- }
- function str_from_cps(cps) {
- const chunk = 4096;
- let len = cps.length;
- if (len < chunk) return String.fromCodePoint(...cps);
- let buf = [];
- for (let i = 0; i < len; ) {
- buf.push(String.fromCodePoint(...cps.slice(i, i += chunk)));
- }
- return buf.join('');
- }
- function compare_arrays(a, b) {
- let n = a.length;
- let c = n - b.length;
- for (let i = 0; c == 0 && i < n; i++) c = a[i] - b[i];
- return c;
- }
- // created 2023-09-25T01:01:55.148Z
- // compressed base64-encoded blob for include-nf data
- // source: https://github.com/adraffy/ens-normalize.js/blob/main/src/make.js
- // see: https://github.com/adraffy/ens-normalize.js#security
- // SHA-256: a974b6f8541fc29d919bc85118af0a44015851fab5343f8679cb31be2bdb209e
- var COMPRESSED = 'AEUDTAHBCFQATQDRADAAcgAgADQAFAAsABQAHwAOACQADQARAAoAFwAHABIACAAPAAUACwAFAAwABAAQAAMABwAEAAoABQAIAAIACgABAAQAFAALAAIACwABAAIAAQAHAAMAAwAEAAsADAAMAAwACgANAA0AAwAKAAkABAAdAAYAZwDSAdsDJgC0CkMB8xhZAqfoC190UGcThgBurwf7PT09Pb09AjgJum8OjDllxHYUKXAPxzq6tABAxgK8ysUvWAgMPT09PT09PSs6LT2HcgWXWwFLoSMEEEl5RFVMKvO0XQ8ExDdJMnIgsj26PTQyy8FfEQ8AY8IPAGcEbwRwBHEEcgRzBHQEdQR2BHcEeAR6BHsEfAR+BIAEgfndBQoBYgULAWIFDAFiBNcE2ATZBRAFEQUvBdALFAsVDPcNBw13DYcOMA4xDjMB4BllHI0B2grbAMDpHLkQ7QHVAPRNQQFnGRUEg0yEB2uaJF8AJpIBpob5AERSMAKNoAXqaQLUBMCzEiACnwRZEkkVsS7tANAsBG0RuAQLEPABv9HICTUBXigPZwRBApMDOwAamhtaABqEAY8KvKx3LQ4ArAB8UhwEBAVSagD8AEFZADkBIadVj2UMUgx5Il4ANQC9AxIB1BlbEPMAs30CGxlXAhwZKQIECBc6EbsCoxngzv7UzRQA8M0BawL6ZwkN7wABAD33OQRcsgLJCjMCjqUChtw/km+NAsXPAoP2BT84PwURAK0RAvptb6cApQS/OMMey5HJS84UdxpxTPkCogVFITaTOwERAK5pAvkNBOVyA7q3BKlOJSALAgUIBRcEdASpBXqzABXFSWZOawLCOqw//AolCZdvv3dSBkEQGyelEPcMMwG1ATsN7UvYBPEGOwTJH30ZGQ/NlZwIpS3dDO0m4y6hgFoj9SqDBe1L9DzdC01RaA9ZC2UJ4zpjgU4DIQENIosK3Q05CG0Q8wrJaw3lEUUHOQPVSZoApQcBCxEdNRW1JhBirAsJOXcG+xr2C48mrxMpevwF0xohBk0BKRr/AM8u54WwWjFcHE9fBgMLJSPHFKhQIA0lQLd4SBobBxUlqQKRQ3BKh1E2HpMh9jw9DWYuE1F8B/U8BRlPC4E8nkarRQ4R0j6NPUgiSUwsBDV/LC8niwnPD4UMuXxyAVkJIQmxDHETMREXN8UIOQcZLZckJxUIIUaVYJoE958D8xPRAwsFPwlBBxMDtRwtEy4VKQUNgSTXAvM21S6zAo9WgAEXBcsPJR/fEFBH4A7pCJsCZQODJesALRUhABcimwhDYwBfj9hTBS7LCMdqbCN0A2cU52ERcweRDlcHpxwzFb8c4XDIXguGCCijrwlbAXUJmQFfBOMICTVbjKAgQWdTi1gYmyBhQT9d/AIxDGUVn0S9h3gCiw9rEhsBNQFzBzkNAQJ3Ee0RaxCVCOuGBDW1M/g6JQRPIYMgEQonA09szgsnJvkM+GkBoxJiAww0PXfuZ6tgtiQX/QcZMsVBYCHxC5JPzQycGsEYQlQuGeQHvwPzGvMn6kFXBf8DowMTOk0z7gS9C2kIiwk/AEkOoxcH1xhqCnGM0AExiwG3mQNXkYMCb48GNwcLAGcLhwV55QAdAqcIowAFAM8DVwA5Aq0HnQAZAIVBAT0DJy8BIeUCjwOTCDHLAZUvAfMpBBvDDBUA9zduSgLDsQKAamaiBd1YAo4CSTUBTSUEBU5HUQOvceEA2wBLBhPfRwEVq0rLGuNDAd9vKwDHAPsABTUHBUEBzQHzbQC3AV8LMQmis7UBTekpAIMAFWsB1wKJAN0ANQB/8QFTAE0FWfkF0wJPSQERMRgrV2EBuwMfATMBDQB5BsuNpckHHwRtB9MCEBsV4QLvLge1AQMi3xPNQsUCvd5VoWACZIECYkJbTa9bNyACofcCaJgCZgkCn4Q4GwsCZjsCZiYEbgR/A38TA36SOQY5dxc5gjojIwJsHQIyNjgKAm3HAm2u74ozZ0UrAWcA3gDhAEoFB5gMjQD+C8IADbUCdy8CdqI/AnlLQwJ4uh1c20WuRtcCfD8CesgCfQkCfPAFWQUgSABIfWMkAoFtAoAAAoAFAn+uSVhKWxUXSswC0QEC0MxLJwOITwOH5kTFkTIC8qFdAwMDrkvOTC0lA89NTE2vAos/AorYwRsHHUNnBbcCjjcCjlxAl4ECjtkCjlx4UbRTNQpS1FSFApP7ApMMAOkAHFUeVa9V0AYsGymVhjLheGZFOzkCl58C77JYIagAWSUClo8ClnycAKlZrFoJgU0AOwKWtQKWTlxEXNECmcsCmWRcyl0HGQKcmznCOp0CnBYCn5sCnriKAB0PMSoPAp3xAp6SALU9YTRh7wKe0wKgbgGpAp6fHwKeTqVjyGQnJSsCJ68CJn4CoPsCoEwCot0CocQCpi8Cpc4Cp/8AfQKn8mh8aLEAA0lqHGrRAqzjAqyuAq1nAq0CAlcdAlXcArHh1wMfTmyXArK9DQKy6Bds4G1jbUhfAyXNArZcOz9ukAMpRQK4XgK5RxUCuSp3cDZw4QK9GQK72nCWAzIRAr6IcgIDM3ECvhpzInNPAsPLAsMEc4J0SzVFdOADPKcDPJoDPb8CxXwCxkcCxhCJAshpUQLIRALJTwLJLgJknQLd0nh5YXiueSVL0AMYo2cCAmH0GfOVJHsLXpJeuxECz2sCz2wvS1PS8xOfAMatAs9zASnqA04SfksFAtwnAtuKAtJPA1JcA1NfAQEDVYyAiT8AyxbtYEWCHILTgs6DjQLaxwLZ3oQQhEmnPAOGpQAvA2QOhnFZ+QBVAt9lAt64c3cC4i/tFAHzMCcB9JsB8tKHAuvzAulweQLq+QLq5AD5RwG5Au6JAuuclqqXAwLuPwOF4Jh5cOBxoQLzAwBpA44WmZMC9xMDkW4DkocC95gC+dkC+GaaHJqruzebHgOdgwL++gEbADmfHJ+zAwWNA6ZqA6bZANHFAwZqoYiiBQkDDEkCwAA/AwDhQRdTARHzA2sHl2cFAJMtK7evvdsBiZkUfxEEOQH7KQUhDp0JnwCS/SlXxQL3AZ0AtwW5AG8LbUEuFCaNLgFDAYD8AbUmAHUDDgRtACwCFgyhAAAKAj0CagPdA34EkQEgRQUhfAoABQBEABMANhICdwEABdUDa+8KxQIA9wqfJ7+xt+UBkSFBQgHpFH8RNMCJAAQAGwBaAkUChIsABjpTOpSNbQC4Oo860ACNOME63AClAOgAywE6gTo7Ofw5+Tt2iTpbO56JOm85GAFWATMBbAUvNV01njWtNWY1dTW2NcU1gjWRNdI14TWeNa017jX9NbI1wTYCNhE1xjXVNhY2JzXeNe02LjY9Ni41LSE2OjY9Njw2yTcIBJA8VzY4Nt03IDcPNsogN4k3MAoEsDxnNiQ3GTdsOo03IULUQwdC4EMLHA8PCZsobShRVQYA6X8A6bABFCnXAukBowC9BbcAbwNzBL8MDAMMAQgDAAkKCwsLCQoGBAVVBI/DvwDz9b29kaUCb0QtsRTNLt4eGBcSHAMZFhYZEhYEARAEBUEcQRxBHEEcQRxBHEEaQRxBHEFCSTxBPElISUhBNkM2QTYbNklISVmBVIgBFLWZAu0BhQCjBcEAbykBvwGJAaQcEZ0ePCklMAAhMvAIMAL54gC7Bm8EescjzQMpARQpKgDUABavAj626xQAJP0A3etzuf4NNRA7efy2Z9NQrCnC0OSyANz5BBIbJ5IFDR6miIavYS6tprjjmuKebxm5C74Q225X1pkaYYPb6f1DK4k3xMEBb9S2WMjEibTNWhsRJIA+vwNVEiXTE5iXs/wezV66oFLfp9NZGYW+Gk19J2+bCT6Ye2w6LDYdgzKMUabk595eLBCXANz9HUpWbATq9vqXVx9XDg+Pc9Xp4+bsS005SVM/BJBM4687WUuf+Uj9dEi8aDNaPxtpbDxcG1THTImUMZq4UCaaNYpsVqraNyKLJXDYsFZ/5jl7bLRtO88t7P3xZaAxhb5OdPMXqsSkp1WCieG8jXm1U99+blvLlXzPCS+M93VnJCiK+09LfaSaBAVBomyDgJua8dfUzR7ga34IvR2Nvj+A9heJ6lsl1KG4NkI1032Cnff1m1wof2B9oHJK4bi6JkEdSqeNeiuo6QoZZincoc73/TH9SXF8sCE7XyuYyW8WSgbGFCjPV0ihLKhdPs08Tx82fYAkLLc4I2wdl4apY7GU5lHRFzRWJep7Ww3wbeA3qmd59/86P4xuNaqDpygXt6M85glSBHOCGgJDnt+pN9bK7HApMguX6+06RZNjzVmcZJ+wcUrJ9//bpRNxNuKpNl9uFds+S9tdx7LaM5ZkIrPj6nIU9mnbFtVbs9s/uLgl8MVczAwet+iOEzzBlYW7RCMgE6gyNLeq6+1tIx4dpgZnd0DksJS5f+JNDpwwcPNXaaVspq1fbQajOrJgK0ofKtJ1Ne90L6VO4MOl5S886p7u6xo7OLjG8TGL+HU1JXGJgppg4nNbNJ5nlzSpuPYy21JUEcUA94PoFiZfjZue+QnyQ80ekOuZVkxx4g+cvhJfHgNl4hy1/a6+RKcKlar/J29y//EztlbVPHVUeQ1zX86eQVAjR/M3dA9w4W8LfaXp4EgM85wOWasli837PzVMOnsLzR+k3o75/lRPAJSE1xAKQzEi5v10ke+VBvRt1cwQRMd+U5mLCTGVd6XiZtgBG5cDi0w22GKcVNvHiu5LQbZEDVtz0onn7k5+heuKXVsZtSzilkLRAUmjMXEMB3J9YC50XBxPiz53SC+EhnPl9WsKCv92SM/OFFIMJZYfl0WW8tIO3UxYcwdMAj7FSmgrsZ2aAZO03BOhP1bNNZItyXYQFTpC3SG1VuPDqH9GkiCDmE+JwxyIVSO5siDErAOpEXFgjy6PQtOVDj+s6e1r8heWVvmZnTciuf4EiNZzCAd7SOMhXERIOlsHIMG399i9aLTy3m2hRLZjJVDNLS53iGIK11dPqQt0zBDyg6qc7YqkDm2M5Ve6dCWCaCbTXX2rToaIgz6+zh4lYUi/+6nqcFMAkQJKHYLK0wYk5N9szV6xihDbDDFr45lN1K4aCXBq/FitPSud9gLt5ZVn+ZqGX7cwm2z5EGMgfFpIFyhGGuDPmso6TItTMwny+7uPnLCf4W6goFQFV0oQSsc9VfMmVLcLr6ZetDZbaSFTLqnSO/bIPjA3/zAUoqgGFAEQS4IhuMzEp2I3jJzbzkk/IEmyax+rhZTwd6f+CGtwPixu8IvzACquPWPREu9ZvGkUzpRwvRRuaNN6cr0W1wWits9ICdYJ7ltbgMiSL3sTPeufgNcVqMVWFkCPDH4jG2jA0XcVgQj62Cb29v9f/z/+2KbYvIv/zzjpQAPkliaVDzNrW57TZ/ZOyZD0nlfMmAIBIAGAI0D3k/mdN4xr9v85ZbZbbqfH2jGd5hUqNZWwl5SPfoGmfElmazUIeNL1j/mkF7VNAzTq4jNt8JoQ11NQOcmhprXoxSxfRGJ9LDEOAQ+dmxAQH90iti9e2u/MoeuaGcDTHoC+xsmEeWmxEKefQuIzHbpw5Tc5cEocboAD09oipWQhtTO1wivf/O+DRe2rpl/E9wlrzBorjJsOeG1B/XPW4EaJEFdNlECEZga5ZoGRHXgYouGRuVkm8tDESiEyFNo+3s5M5puSdTyUL2llnINVHEt91XUNW4ewdMgJ4boJfEyt/iY5WXqbA+A2Fkt5Z0lutiWhe9nZIyIUjyXDC3UsaG1t+eNx6z4W/OYoTB7A6x+dNSTOi9AInctbESqm5gvOLww7OWXPrmHwVZasrl4eD113pm+JtT7JVOvnCXqdzzdTRHgJ0PiGTFYW5Gvt9R9LD6Lzfs0v/TZZHSmyVNq7viIHE6DBK7Qp07Iz55EM8SYtQvZf/obBniTWi5C2/ovHfw4VndkE5XYdjOhCMRjDeOEfXeN/CwfGduiUIfsoFeUxXeQXba7c7972XNv8w+dTjjUM0QeNAReW+J014dKAD/McQYXT7c0GQPIkn3Ll6R7gGjuiQoZD0TEeEqQpKoZ15g/0OPQI17QiSv9AUROa/V/TQN3dvLArec3RrsYlvBm1b8LWzltdugsC50lNKYLEp2a+ZZYqPejULRlOJh5zj/LVMyTDvwKhMxxwuDkxJ1QpoNI0OTWLom4Z71SNzI9TV1iXJrIu9Wcnd+MCaAw8o1jSXd94YU/1gnkrC9BUEOtQvEIQ7g0i6h+KL2JKk8Ydl7HruvgWMSAmNe+LshGhV4qnWHhO9/RIPQzY1tHRj2VqOyNsDpK0cww+56AdDC4gsWwY0XxoucIWIqs/GcwnWqlaT0KPr8mbK5U94/301i1WLt4YINTVvCFBrFZbIbY8eycOdeJ2teD5IfPLCRg7jjcFTwlMFNl9zdh/o3E/hHPwj7BWg0MU09pPrBLbrCgm54A6H+I6v27+jL5gkjWg/iYdks9jbfVP5y/n0dlgWEMlKasl7JvFZd56LfybW1eeaVO0gxTfXZwD8G4SI116yx7UKVRgui6Ya1YpixqXeNLc8IxtAwCU5IhwQgn+NqHnRaDv61CxKhOq4pOX7M6pkA+Pmpd4j1vn6ACUALoLLc4vpXci8VidLxzm7qFBe7s+quuJs6ETYmnpgS3LwSZxPIltgBDXz8M1k/W2ySNv2f9/NPhxLGK2D21dkHeSGmenRT3Yqcdl0m/h3OYr8V+lXNYGf8aCCpd4bWjE4QIPj7vUKN4Nrfs7ML6Y2OyS830JCnofg/k7lpFpt4SqZc5HGg1HCOrHvOdC8bP6FGDbE/VV0mX4IakzbdS/op+Kt3G24/8QbBV7y86sGSQ/vZzU8FXs7u6jIvwchsEP2BpIhW3G8uWNwa3HmjfH/ZjhhCWvluAcF+nMf14ClKg5hGgtPLJ98ueNAkc5Hs2WZlk2QHvfreCK1CCGO6nMZVSb99VM/ajr8WHTte9JSmkXq/i/U943HEbdzW6Re/S88dKgg8pGOLlAeNiqrcLkUR3/aClFpMXcOUP3rmETcWSfMXZE3TUOi8i+fqRnTYLflVx/Vb/6GJ7eIRZUA6k3RYR3iFSK9c4iDdNwJuZL2FKz/IK5VimcNWEqdXjSoxSgmF0UPlDoUlNrPcM7ftmA8Y9gKiqKEHuWN+AZRIwtVSxye2Kf8rM3lhJ5XcBXU9n4v0Oy1RU2M+4qM8AQPVwse8ErNSob5oFPWxuqZnVzo1qB/IBxkM3EVUKFUUlO3e51259GgNcJbCmlvrdjtoTW7rChm1wyCKzpCTwozUUEOIcWLneRLgMXh+SjGSFkAllzbGS5HK7LlfCMRNRDSvbQPjcXaenNYxCvu2Qyznz6StuxVj66SgI0T8B6/sfHAJYZaZ78thjOSIFumNWLQbeZixDCCC+v0YBtkxiBB3jefHqZ/dFHU+crbj6OvS1x/JDD7vlm7zOVPwpUC01nhxZuY/63E7g';
- // https://unicode.org/reports/tr15/
- // for reference implementation
- // see: /derive/nf.js
- // algorithmic hangul
- // https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf (page 144)
- const S0 = 0xAC00;
- const L0 = 0x1100;
- const V0 = 0x1161;
- const T0 = 0x11A7;
- const L_COUNT = 19;
- const V_COUNT = 21;
- const T_COUNT = 28;
- const N_COUNT = V_COUNT * T_COUNT;
- const S_COUNT = L_COUNT * N_COUNT;
- const S1 = S0 + S_COUNT;
- const L1 = L0 + L_COUNT;
- const V1 = V0 + V_COUNT;
- const T1$1 = T0 + T_COUNT;
- function unpack_cc(packed) {
- return (packed >> 24) & 0xFF;
- }
- function unpack_cp(packed) {
- return packed & 0xFFFFFF;
- }
- let SHIFTED_RANK, EXCLUSIONS, DECOMP, RECOMP;
- function init$1() {
- //console.time('nf');
- let r = read_compressed_payload(COMPRESSED);
- SHIFTED_RANK = new Map(read_sorted_arrays(r).flatMap((v, i) => v.map(x => [x, (i+1) << 24]))); // pre-shifted
- EXCLUSIONS = new Set(read_sorted(r));
- DECOMP = new Map();
- RECOMP = new Map();
- for (let [cp, cps] of read_mapped(r)) {
- if (!EXCLUSIONS.has(cp) && cps.length == 2) {
- let [a, b] = cps;
- let bucket = RECOMP.get(a);
- if (!bucket) {
- bucket = new Map();
- RECOMP.set(a, bucket);
- }
- bucket.set(b, cp);
- }
- DECOMP.set(cp, cps.reverse()); // stored reversed
- }
- //console.timeEnd('nf');
- // 20230905: 11ms
- }
- function is_hangul(cp) {
- return cp >= S0 && cp < S1;
- }
- function compose_pair(a, b) {
- if (a >= L0 && a < L1 && b >= V0 && b < V1) {
- return S0 + (a - L0) * N_COUNT + (b - V0) * T_COUNT;
- } else if (is_hangul(a) && b > T0 && b < T1$1 && (a - S0) % T_COUNT == 0) {
- return a + (b - T0);
- } else {
- let recomp = RECOMP.get(a);
- if (recomp) {
- recomp = recomp.get(b);
- if (recomp) {
- return recomp;
- }
- }
- return -1;
- }
- }
- function decomposed(cps) {
- if (!SHIFTED_RANK) init$1();
- let ret = [];
- let buf = [];
- let check_order = false;
- function add(cp) {
- let cc = SHIFTED_RANK.get(cp);
- if (cc) {
- check_order = true;
- cp |= cc;
- }
- ret.push(cp);
- }
- for (let cp of cps) {
- while (true) {
- if (cp < 0x80) {
- ret.push(cp);
- } else if (is_hangul(cp)) {
- let s_index = cp - S0;
- let l_index = s_index / N_COUNT | 0;
- let v_index = (s_index % N_COUNT) / T_COUNT | 0;
- let t_index = s_index % T_COUNT;
- add(L0 + l_index);
- add(V0 + v_index);
- if (t_index > 0) add(T0 + t_index);
- } else {
- let mapped = DECOMP.get(cp);
- if (mapped) {
- buf.push(...mapped);
- } else {
- add(cp);
- }
- }
- if (!buf.length) break;
- cp = buf.pop();
- }
- }
- if (check_order && ret.length > 1) {
- let prev_cc = unpack_cc(ret[0]);
- for (let i = 1; i < ret.length; i++) {
- let cc = unpack_cc(ret[i]);
- if (cc == 0 || prev_cc <= cc) {
- prev_cc = cc;
- continue;
- }
- let j = i-1;
- while (true) {
- let tmp = ret[j+1];
- ret[j+1] = ret[j];
- ret[j] = tmp;
- if (!j) break;
- prev_cc = unpack_cc(ret[--j]);
- if (prev_cc <= cc) break;
- }
- prev_cc = unpack_cc(ret[i]);
- }
- }
- return ret;
- }
- function composed_from_decomposed(v) {
- let ret = [];
- let stack = [];
- let prev_cp = -1;
- let prev_cc = 0;
- for (let packed of v) {
- let cc = unpack_cc(packed);
- let cp = unpack_cp(packed);
- if (prev_cp == -1) {
- if (cc == 0) {
- prev_cp = cp;
- } else {
- ret.push(cp);
- }
- } else if (prev_cc > 0 && prev_cc >= cc) {
- if (cc == 0) {
- ret.push(prev_cp, ...stack);
- stack.length = 0;
- prev_cp = cp;
- } else {
- stack.push(cp);
- }
- prev_cc = cc;
- } else {
- let composed = compose_pair(prev_cp, cp);
- if (composed >= 0) {
- prev_cp = composed;
- } else if (prev_cc == 0 && cc == 0) {
- ret.push(prev_cp);
- prev_cp = cp;
- } else {
- stack.push(cp);
- prev_cc = cc;
- }
- }
- }
- if (prev_cp >= 0) {
- ret.push(prev_cp, ...stack);
- }
- return ret;
- }
- // note: cps can be iterable
- function nfd(cps) {
- return decomposed(cps).map(unpack_cp);
- }
- function nfc(cps) {
- return composed_from_decomposed(decomposed(cps));
- }
- const HYPHEN = 0x2D;
- const STOP_CH = '.';
- const FE0F = 0xFE0F;
- const UNIQUE_PH = 1;
- // 20230913: replace [...v] with Array_from(v) to avoid large spreads
- const Array_from = x => Array.from(x); // Array.from.bind(Array);
- function group_has_cp(g, cp) {
- // 20230913: keep primary and secondary distinct instead of creating valid union
- return g.P.has(cp) || g.Q.has(cp);
- }
- class Emoji extends Array {
- get is_emoji() { return true; } // free tagging system
- }
- let MAPPED, IGNORED, CM, NSM, ESCAPE, GROUPS, WHOLE_VALID, WHOLE_MAP, VALID, EMOJI_LIST, EMOJI_ROOT;
- function init() {
- if (MAPPED) return;
-
- let r = read_compressed_payload(COMPRESSED$1);
- const read_sorted_array = () => read_sorted(r);
- const read_sorted_set = () => new Set(read_sorted_array());
- const set_add_many = (set, v) => v.forEach(x => set.add(x));
- MAPPED = new Map(read_mapped(r));
- IGNORED = read_sorted_set(); // ignored characters are not valid, so just read raw codepoints
- /*
- // direct include from payload is smaller than the decompression code
- const FENCED = new Map(read_array_while(() => {
- let cp = r();
- if (cp) return [cp, read_str(r())];
- }));
- */
- // 20230217: we still need all CM for proper error formatting
- // but norm only needs NSM subset that are potentially-valid
- CM = read_sorted_array();
- NSM = new Set(read_sorted_array().map(i => CM[i]));
- CM = new Set(CM);
-
- ESCAPE = read_sorted_set(); // characters that should not be printed
- read_sorted_set(); // only needed to illustrate ens_tokenize() transformations
- let chunks = read_sorted_arrays(r);
- let unrestricted = r();
- //const read_chunked = () => new Set(read_sorted_array().flatMap(i => chunks[i]).concat(read_sorted_array()));
- const read_chunked = () => {
- // 20230921: build set in parts, 2x faster
- let set = new Set();
- read_sorted_array().forEach(i => set_add_many(set, chunks[i]));
- set_add_many(set, read_sorted_array());
- return set;
- };
- GROUPS = read_array_while(i => {
- // minifier property mangling seems unsafe
- // so these are manually renamed to single chars
- let N = read_array_while(r).map(x => x+0x60);
- if (N.length) {
- let R = i >= unrestricted; // unrestricted then restricted
- N[0] -= 32; // capitalize
- N = str_from_cps(N);
- if (R) N=`Restricted[${N}]`;
- let P = read_chunked(); // primary
- let Q = read_chunked(); // secondary
- let M = !r(); // not-whitelisted, check for NSM
- // *** this code currently isn't needed ***
- /*
- let V = [...P, ...Q].sort((a, b) => a-b); // derive: sorted valid
- let M = r()-1; // number of combining mark
- if (M < 0) { // whitelisted
- M = new Map(read_array_while(() => {
- let i = r();
- if (i) return [V[i-1], read_array_while(() => {
- let v = read_array_while(r);
- if (v.length) return v.map(x => x-1);
- })];
- }));
- }*/
- return {N, P, Q, M, R};
- }
- });
- // decode compressed wholes
- WHOLE_VALID = read_sorted_set();
- WHOLE_MAP = new Map();
- let wholes = read_sorted_array().concat(Array_from(WHOLE_VALID)).sort((a, b) => a-b); // must be sorted
- wholes.forEach((cp, i) => {
- let d = r();
- let w = wholes[i] = d ? wholes[i-d] : {V: [], M: new Map()};
- w.V.push(cp); // add to member set
- if (!WHOLE_VALID.has(cp)) {
- WHOLE_MAP.set(cp, w); // register with whole map
- }
- });
- // compute confusable-extent complements
- // usage: WHOLE_MAP.get(cp).M.get(cp) = complement set
- for (let {V, M} of new Set(WHOLE_MAP.values())) {
- // connect all groups that have each whole character
- let recs = [];
- for (let cp of V) {
- let gs = GROUPS.filter(g => group_has_cp(g, cp));
- let rec = recs.find(({G}) => gs.some(g => G.has(g)));
- if (!rec) {
- rec = {G: new Set(), V: []};
- recs.push(rec);
- }
- rec.V.push(cp);
- set_add_many(rec.G, gs);
- }
- // per character cache groups which are not a member of the extent
- let union = recs.flatMap(x => Array_from(x.G)); // all of the groups used by this whole
- for (let {G, V} of recs) {
- let complement = new Set(union.filter(g => !G.has(g))); // groups not covered by the extent
- for (let cp of V) {
- M.set(cp, complement); // this is the same reference
- }
- }
- }
- // compute valid set
- // 20230924: VALID was union but can be re-used
- VALID = new Set(); // exists in 1+ groups
- let multi = new Set(); // exists in 2+ groups
- const add_to_union = cp => VALID.has(cp) ? multi.add(cp) : VALID.add(cp);
- for (let g of GROUPS) {
- for (let cp of g.P) add_to_union(cp);
- for (let cp of g.Q) add_to_union(cp);
- }
- // dual purpose WHOLE_MAP: return placeholder if unique non-confusable
- for (let cp of VALID) {
- if (!WHOLE_MAP.has(cp) && !multi.has(cp)) {
- WHOLE_MAP.set(cp, UNIQUE_PH);
- }
- }
- // add all decomposed parts
- // see derive: "Valid is Closed (via Brute-force)"
- set_add_many(VALID, nfd(VALID));
-
- // decode emoji
- // 20230719: emoji are now fully-expanded to avoid quirk logic
- EMOJI_LIST = read_trie(r).map(v => Emoji.from(v)).sort(compare_arrays);
- EMOJI_ROOT = new Map(); // this has approx 7K nodes (2+ per emoji)
- for (let cps of EMOJI_LIST) {
- // 20230719: change to *slightly* stricter algorithm which disallows
- // insertion of misplaced FE0F in emoji sequences (matching ENSIP-15)
- // example: beautified [A B] (eg. flag emoji)
- // before: allow: [A FE0F B], error: [A FE0F FE0F B]
- // after: error: both
- // note: this code now matches ENSNormalize.{cs,java} logic
- let prev = [EMOJI_ROOT];
- for (let cp of cps) {
- let next = prev.map(node => {
- let child = node.get(cp);
- if (!child) {
- // should this be object?
- // (most have 1-2 items, few have many)
- // 20230719: no, v8 default map is 4?
- child = new Map();
- node.set(cp, child);
- }
- return child;
- });
- if (cp === FE0F) {
- prev.push(...next); // less than 20 elements
- } else {
- prev = next;
- }
- }
- for (let x of prev) {
- x.V = cps;
- }
- }
- }
- // if escaped: {HEX}
- // else: "x" {HEX}
- function quoted_cp(cp) {
- return (should_escape(cp) ? '' : `${bidi_qq(safe_str_from_cps([cp]))} `) + quote_cp(cp);
- }
- // 20230211: some messages can be mixed-directional and result in spillover
- // use 200E after a quoted string to force the remainder of a string from
- // acquring the direction of the quote
- // https://www.w3.org/International/questions/qa-bidi-unicode-controls#exceptions
- function bidi_qq(s) {
- return `"${s}"\u200E`; // strong LTR
- }
- function check_label_extension(cps) {
- if (cps.length >= 4 && cps[2] == HYPHEN && cps[3] == HYPHEN) {
- throw new Error(`invalid label extension: "${str_from_cps(cps.slice(0, 4))}"`); // this can only be ascii so cant be bidi
- }
- }
- function check_leading_underscore(cps) {
- const UNDERSCORE = 0x5F;
- for (let i = cps.lastIndexOf(UNDERSCORE); i > 0; ) {
- if (cps[--i] !== UNDERSCORE) {
- throw new Error('underscore allowed only at start');
- }
- }
- }
- // check that a fenced cp is not leading, trailing, or touching another fenced cp
- function check_fenced(cps) {
- let cp = cps[0];
- let prev = FENCED.get(cp);
- if (prev) throw error_placement(`leading ${prev}`);
- let n = cps.length;
- let last = -1; // prevents trailing from throwing
- for (let i = 1; i < n; i++) {
- cp = cps[i];
- let match = FENCED.get(cp);
- if (match) {
- // since cps[0] isn't fenced, cps[1] cannot throw
- if (last == i) throw error_placement(`${prev} + ${match}`);
- last = i + 1;
- prev = match;
- }
- }
- if (last == n) throw error_placement(`trailing ${prev}`);
- }
- // create a safe to print string
- // invisibles are escaped
- // leading cm uses placeholder
- // if cps exceed max, middle truncate with ellipsis
- // quoter(cp) => string, eg. 3000 => "{3000}"
- // note: in html, you'd call this function then replace [<>&] with entities
- function safe_str_from_cps(cps, max = Infinity, quoter = quote_cp) {
- //if (Number.isInteger(cps)) cps = [cps];
- //if (!Array.isArray(cps)) throw new TypeError(`expected codepoints`);
- let buf = [];
- if (is_combining_mark(cps[0])) buf.push('◌');
- if (cps.length > max) {
- max >>= 1;
- cps = [...cps.slice(0, max), 0x2026, ...cps.slice(-max)];
- }
- let prev = 0;
- let n = cps.length;
- for (let i = 0; i < n; i++) {
- let cp = cps[i];
- if (should_escape(cp)) {
- buf.push(str_from_cps(cps.slice(prev, i)));
- buf.push(quoter(cp));
- prev = i + 1;
- }
- }
- buf.push(str_from_cps(cps.slice(prev, n)));
- return buf.join('');
- }
- // note: set(s) cannot be exposed because they can be modified
- // note: Object.freeze() doesn't work
- function is_combining_mark(cp) {
- init();
- return CM.has(cp);
- }
- function should_escape(cp) {
- init();
- return ESCAPE.has(cp);
- }
- function ens_normalize(name) {
- return flatten(split(name, nfc, filter_fe0f));
- }
- function split(name, nf, ef) {
- if (!name) return []; // 20230719: empty name allowance
- init();
- let offset = 0;
- // https://unicode.org/reports/tr46/#Validity_Criteria
- // 4.) "The label must not contain a U+002E ( . ) FULL STOP."
- return name.split(STOP_CH).map(label => {
- let input = explode_cp(label);
- let info = {
- input,
- offset, // codepoint, not substring!
- };
- offset += input.length + 1; // + stop
- try {
- // 1.) "The label must be in Unicode Normalization Form NFC"
- let tokens = info.tokens = tokens_from_str(input, nf, ef);
- let token_count = tokens.length;
- let type;
- if (!token_count) { // the label was effectively empty (could of had ignored characters)
- //norm = [];
- //type = 'None'; // use this instead of next match, "ASCII"
- // 20230120: change to strict
- // https://discuss.ens.domains/t/ens-name-normalization-2nd/14564/59
- throw new Error(`empty label`);
- }
- let norm = info.output = tokens.flat();
- check_leading_underscore(norm);
- let emoji = info.emoji = token_count > 1 || tokens[0].is_emoji; // same as: tokens.some(x => x.is_emoji);
- if (!emoji && norm.every(cp => cp < 0x80)) { // special case for ascii
- // 20230123: matches matches WHATWG, see note 3.3
- check_label_extension(norm); // only needed for ascii
- // cant have fenced
- // cant have cm
- // cant have wholes
- // see derive: "Fastpath ASCII"
- type = 'ASCII';
- } else {
- let chars = tokens.flatMap(x => x.is_emoji ? [] : x); // all of the nfc tokens concat together
- if (!chars.length) { // theres no text, just emoji
- type = 'Emoji';
- } else {
- // 5.) "The label must not begin with a combining mark, that is: General_Category=Mark."
- if (CM.has(norm[0])) throw error_placement('leading combining mark');
- for (let i = 1; i < token_count; i++) { // we've already checked the first token
- let cps = tokens[i];
- if (!cps.is_emoji && CM.has(cps[0])) { // every text token has emoji neighbors, eg. EtEEEtEt...
- // bidi_qq() not needed since emoji is LTR and cps is a CM
- throw error_placement(`emoji + combining mark: "${str_from_cps(tokens[i-1])} + ${safe_str_from_cps([cps[0]])}"`);
- }
- }
- check_fenced(norm);
- let unique = Array_from(new Set(chars));
- let [g] = determine_group(unique); // take the first match
- // see derive: "Matching Groups have Same CM Style"
- // alternative: could form a hybrid type: Latin/Japanese/...
- check_group(g, chars); // need text in order
- check_whole(g, unique); // only need unique text (order would be required for multiple-char confusables)
- type = g.N;
- // 20230121: consider exposing restricted flag
- // it's simpler to just check for 'Restricted'
- // or even better: type.endsWith(']')
- //if (g.R) info.restricted = true;
- }
- }
- info.type = type;
- } catch (err) {
- info.error = err; // use full error object
- }
- return info;
- });
- }
- function check_whole(group, unique) {
- let maker;
- let shared = [];
- for (let cp of unique) {
- let whole = WHOLE_MAP.get(cp);
- if (whole === UNIQUE_PH) return; // unique, non-confusable
- if (whole) {
- let set = whole.M.get(cp); // groups which have a character that look-like this character
- maker = maker ? maker.filter(g => set.has(g)) : Array_from(set);
- if (!maker.length) return; // confusable intersection is empty
- } else {
- shared.push(cp);
- }
- }
- if (maker) {
- // we have 1+ confusable
- // check if any of the remaining groups
- // contain the shared characters too
- for (let g of maker) {
- if (shared.every(cp => group_has_cp(g, cp))) {
- throw new Error(`whole-script confusable: ${group.N}/${g.N}`);
- }
- }
- }
- }
- // assumption: unique.size > 0
- // returns list of matching groups
- function determine_group(unique) {
- let groups = GROUPS;
- for (let cp of unique) {
- // note: we need to dodge CM that are whitelisted
- // but that code isn't currently necessary
- let gs = groups.filter(g => group_has_cp(g, cp));
- if (!gs.length) {
- if (!GROUPS.some(g => group_has_cp(g, cp))) {
- // the character was composed of valid parts
- // but it's NFC form is invalid
- // 20230716: change to more exact statement, see: ENSNormalize.{cs,java}
- // note: this doesn't have to be a composition
- // 20230720: change to full check
- throw error_disallowed(cp); // this should be rare
- } else {
- // there is no group that contains all these characters
- // throw using the highest priority group that matched
- // https://www.unicode.org/reports/tr39/#mixed_script_confusables
- throw error_group_member(groups[0], cp);
- }
- }
- groups = gs;
- if (gs.length == 1) break; // there is only one group left
- }
- // there are at least 1 group(s) with all of these characters
- return groups;
- }
- // throw on first error
- function flatten(split) {
- return split.map(({input, error, output}) => {
- if (error) {
- // don't print label again if just a single label
- let msg = error.message;
- // bidi_qq() only necessary if msg is digits
- throw new Error(split.length == 1 ? msg : `Invalid label ${bidi_qq(safe_str_from_cps(input, 63))}: ${msg}`);
- }
- return str_from_cps(output);
- }).join(STOP_CH);
- }
- function error_disallowed(cp) {
- // TODO: add cp to error?
- return new Error(`disallowed character: ${quoted_cp(cp)}`);
- }
- function error_group_member(g, cp) {
- let quoted = quoted_cp(cp);
- let gg = GROUPS.find(g => g.P.has(cp)); // only check primary
- if (gg) {
- quoted = `${gg.N} ${quoted}`;
- }
- return new Error(`illegal mixture: ${g.N} + ${quoted}`);
- }
- function error_placement(where) {
- return new Error(`illegal placement: ${where}`);
- }
- // assumption: cps.length > 0
- // assumption: cps[0] isn't a CM
- // assumption: the previous character isn't an emoji
- function check_group(g, cps) {
- for (let cp of cps) {
- if (!group_has_cp(g, cp)) {
- // for whitelisted scripts, this will throw illegal mixture on invalid cm, eg. "e{300}{300}"
- // at the moment, it's unnecessary to introduce an extra error type
- // until there exists a whitelisted multi-character
- // eg. if (M < 0 && is_combining_mark(cp)) { ... }
- // there are 3 cases:
- // 1. illegal cm for wrong group => mixture error
- // 2. illegal cm for same group => cm error
- // requires set of whitelist cm per group:
- // eg. new Set([...g.P, ...g.Q].flatMap(nfc).filter(cp => CM.has(cp)))
- // 3. wrong group => mixture error
- throw error_group_member(g, cp);
- }
- }
- //if (M >= 0) { // we have a known fixed cm count
- if (g.M) { // we need to check for NSM
- let decomposed = nfd(cps);
- for (let i = 1, e = decomposed.length; i < e; i++) { // see: assumption
- // 20230210: bugfix: using cps instead of decomposed h/t Carbon225
- /*
- if (CM.has(decomposed[i])) {
- let j = i + 1;
- while (j < e && CM.has(decomposed[j])) j++;
- if (j - i > M) {
- throw new Error(`too many combining marks: ${g.N} ${bidi_qq(str_from_cps(decomposed.slice(i-1, j)))} (${j-i}/${M})`);
- }
- i = j;
- }
- */
- // 20230217: switch to NSM counting
- // https://www.unicode.org/reports/tr39/#Optional_Detection
- if (NSM.has(decomposed[i])) {
- let j = i + 1;
- for (let cp; j < e && NSM.has(cp = decomposed[j]); j++) {
- // a. Forbid sequences of the same nonspacing mark.
- for (let k = i; k < j; k++) { // O(n^2) but n < 100
- if (decomposed[k] == cp) {
- throw new Error(`duplicate non-spacing marks: ${quoted_cp(cp)}`);
- }
- }
- }
- // parse to end so we have full nsm count
- // b. Forbid sequences of more than 4 nonspacing marks (gc=Mn or gc=Me).
- if (j - i > NSM_MAX) {
- // note: this slice starts with a base char or spacing-mark cm
- throw new Error(`excessive non-spacing marks: ${bidi_qq(safe_str_from_cps(decomposed.slice(i-1, j)))} (${j-i}/${NSM_MAX})`);
- }
- i = j;
- }
- }
- }
- // *** this code currently isn't needed ***
- /*
- let cm_whitelist = M instanceof Map;
- for (let i = 0, e = cps.length; i < e; ) {
- let cp = cps[i++];
- let seqs = cm_whitelist && M.get(cp);
- if (seqs) {
- // list of codepoints that can follow
- // if this exists, this will always be 1+
- let j = i;
- while (j < e && CM.has(cps[j])) j++;
- let cms = cps.slice(i, j);
- let match = seqs.find(seq => !compare_arrays(seq, cms));
- if (!match) throw new Error(`disallowed combining mark sequence: "${safe_str_from_cps([cp, ...cms])}"`);
- i = j;
- } else if (!V.has(cp)) {
- // https://www.unicode.org/reports/tr39/#mixed_script_confusables
- let quoted = quoted_cp(cp);
- for (let cp of cps) {
- let u = UNIQUE.get(cp);
- if (u && u !== g) {
- // if both scripts are restricted this error is confusing
- // because we don't differentiate RestrictedA from RestrictedB
- if (!u.R) quoted = `${quoted} is ${u.N}`;
- break;
- }
- }
- throw new Error(`disallowed ${g.N} character: ${quoted}`);
- //throw new Error(`disallowed character: ${quoted} (expected ${g.N})`);
- //throw new Error(`${g.N} does not allow: ${quoted}`);
- }
- }
- if (!cm_whitelist) {
- let decomposed = nfd(cps);
- for (let i = 1, e = decomposed.length; i < e; i++) { // we know it can't be cm leading
- if (CM.has(decomposed[i])) {
- let j = i + 1;
- while (j < e && CM.has(decomposed[j])) j++;
- if (j - i > M) {
- throw new Error(`too many combining marks: "${str_from_cps(decomposed.slice(i-1, j))}" (${j-i}/${M})`);
- }
- i = j;
- }
- }
- }
- */
- }
- // given a list of codepoints
- // returns a list of lists, where emoji are a fully-qualified (as Array subclass)
- // eg. explode_cp("abc💩d") => [[61, 62, 63], Emoji[1F4A9, FE0F], [64]]
- // 20230818: rename for 'process' name collision h/t Javarome
- // https://github.com/adraffy/ens-normalize.js/issues/23
- function tokens_from_str(input, nf, ef) {
- let ret = [];
- let chars = [];
- input = input.slice().reverse(); // flip so we can pop
- while (input.length) {
- let emoji = consume_emoji_reversed(input);
- if (emoji) {
- if (chars.length) {
- ret.push(nf(chars));
- chars = [];
- }
- ret.push(ef(emoji));
- } else {
- let cp = input.pop();
- if (VALID.has(cp)) {
- chars.push(cp);
- } else {
- let cps = MAPPED.get(cp);
- if (cps) {
- chars.push(...cps); // less than 10 elements
- } else if (!IGNORED.has(cp)) {
- // 20230912: unicode 15.1 changed the order of processing such that
- // disallowed parts are only rejected after NFC
- // https://unicode.org/reports/tr46/#Validity_Criteria
- // this doesn't impact normalization as of today
- // technically, this error can be removed as the group logic will apply similar logic
- // however the error type might be less clear
- throw error_disallowed(cp);
- }
- }
- }
- }
- if (chars.length) {
- ret.push(nf(chars));
- }
- return ret;
- }
- function filter_fe0f(cps) {
- return cps.filter(cp => cp != FE0F);
- }
- // given array of codepoints
- // returns the longest valid emoji sequence (or undefined if no match)
- // *MUTATES* the supplied array
- // disallows interleaved ignored characters
- // fills (optional) eaten array with matched codepoints
- function consume_emoji_reversed(cps, eaten) {
- let node = EMOJI_ROOT;
- let emoji;
- let pos = cps.length;
- while (pos) {
- node = node.get(cps[--pos]);
- if (!node) break;
- let {V} = node;
- if (V) { // this is a valid emoji (so far)
- emoji = V;
- cps.length = pos; // truncate
- }
- }
- return emoji;
- }
- const Zeros = new Uint8Array(32);
- Zeros.fill(0);
- function checkComponent(comp) {
- assertArgument(comp.length !== 0, "invalid ENS name; empty component", "comp", comp);
- return comp;
- }
- function ensNameSplit(name) {
- const bytes = toUtf8Bytes(ensNormalize(name));
- const comps = [];
- if (name.length === 0) {
- return comps;
- }
- let last = 0;
- for (let i = 0; i < bytes.length; i++) {
- const d = bytes[i];
- // A separator (i.e. "."); copy this component
- if (d === 0x2e) {
- comps.push(checkComponent(bytes.slice(last, i)));
- last = i + 1;
- }
- }
- // There was a stray separator at the end of the name
- assertArgument(last < bytes.length, "invalid ENS name; empty component", "name", name);
- comps.push(checkComponent(bytes.slice(last)));
- return comps;
- }
- /**
- * Returns the ENS %%name%% normalized.
- */
- function ensNormalize(name) {
- try {
- if (name.length === 0) {
- throw new Error("empty label");
- }
- return ens_normalize(name);
- }
- catch (error) {
- assertArgument(false, `invalid ENS name (${error.message})`, "name", name);
- }
- }
- /**
- * Returns ``true`` if %%name%% is a valid ENS name.
- */
- function isValidName(name) {
- try {
- return (ensNameSplit(name).length !== 0);
- }
- catch (error) { }
- return false;
- }
- /**
- * Returns the [[link-namehash]] for %%name%%.
- */
- function namehash(name) {
- assertArgument(typeof (name) === "string", "invalid ENS name; not a string", "name", name);
- assertArgument(name.length, `invalid ENS name (empty label)`, "name", name);
- let result = Zeros;
- const comps = ensNameSplit(name);
- while (comps.length) {
- result = keccak256(concat([result, keccak256((comps.pop()))]));
- }
- return hexlify(result);
- }
- /**
- * Returns the DNS encoded %%name%%.
- *
- * This is used for various parts of ENS name resolution, such
- * as the wildcard resolution.
- */
- function dnsEncode(name, _maxLength) {
- const length = (_maxLength != null) ? _maxLength : 63;
- assertArgument(length <= 255, "DNS encoded label cannot exceed 255", "length", length);
- return hexlify(concat(ensNameSplit(name).map((comp) => {
- assertArgument(comp.length <= length, `label ${JSON.stringify(name)} exceeds ${length} bytes`, "name", name);
- const bytes = new Uint8Array(comp.length + 1);
- bytes.set(comp, 1);
- bytes[0] = bytes.length - 1;
- return bytes;
- }))) + "00";
- }
- function accessSetify(addr, storageKeys) {
- return {
- address: getAddress(addr),
- storageKeys: storageKeys.map((storageKey, index) => {
- assertArgument(isHexString(storageKey, 32), "invalid slot", `storageKeys[${index}]`, storageKey);
- return storageKey.toLowerCase();
- })
- };
- }
- /**
- * Returns a [[AccessList]] from any ethers-supported access-list structure.
- */
- function accessListify(value) {
- if (Array.isArray(value)) {
- return value.map((set, index) => {
- if (Array.isArray(set)) {
- assertArgument(set.length === 2, "invalid slot set", `value[${index}]`, set);
- return accessSetify(set[0], set[1]);
- }
- assertArgument(set != null && typeof (set) === "object", "invalid address-slot set", "value", value);
- return accessSetify(set.address, set.storageKeys);
- });
- }
- assertArgument(value != null && typeof (value) === "object", "invalid access list", "value", value);
- const result = Object.keys(value).map((addr) => {
- const storageKeys = value[addr].reduce((accum, storageKey) => {
- accum[storageKey] = true;
- return accum;
- }, {});
- return accessSetify(addr, Object.keys(storageKeys).sort());
- });
- result.sort((a, b) => (a.address.localeCompare(b.address)));
- return result;
- }
- /**
- * Returns the address for the %%key%%.
- *
- * The key may be any standard form of public key or a private key.
- */
- function computeAddress(key) {
- let pubkey;
- if (typeof (key) === "string") {
- pubkey = SigningKey.computePublicKey(key, false);
- }
- else {
- pubkey = key.publicKey;
- }
- return getAddress(keccak256("0x" + pubkey.substring(4)).substring(26));
- }
- /**
- * Returns the recovered address for the private key that was
- * used to sign %%digest%% that resulted in %%signature%%.
- */
- function recoverAddress(digest, signature) {
- return computeAddress(SigningKey.recoverPublicKey(digest, signature));
- }
- const BN_0$4 = BigInt(0);
- const BN_2$2 = BigInt(2);
- const BN_27 = BigInt(27);
- const BN_28 = BigInt(28);
- const BN_35 = BigInt(35);
- const BN_MAX_UINT = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- const BLOB_SIZE = 4096 * 32;
- function getVersionedHash(version, hash) {
- let versioned = version.toString(16);
- while (versioned.length < 2) {
- versioned = "0" + versioned;
- }
- versioned += sha256(hash).substring(4);
- return "0x" + versioned;
- }
- function handleAddress(value) {
- if (value === "0x") {
- return null;
- }
- return getAddress(value);
- }
- function handleAccessList(value, param) {
- try {
- return accessListify(value);
- }
- catch (error) {
- assertArgument(false, error.message, param, value);
- }
- }
- function handleNumber(_value, param) {
- if (_value === "0x") {
- return 0;
- }
- return getNumber(_value, param);
- }
- function handleUint(_value, param) {
- if (_value === "0x") {
- return BN_0$4;
- }
- const value = getBigInt(_value, param);
- assertArgument(value <= BN_MAX_UINT, "value exceeds uint size", param, value);
- return value;
- }
- function formatNumber(_value, name) {
- const value = getBigInt(_value, "value");
- const result = toBeArray(value);
- assertArgument(result.length <= 32, `value too large`, `tx.${name}`, value);
- return result;
- }
- function formatAccessList(value) {
- return accessListify(value).map((set) => [set.address, set.storageKeys]);
- }
- function formatHashes(value, param) {
- assertArgument(Array.isArray(value), `invalid ${param}`, "value", value);
- for (let i = 0; i < value.length; i++) {
- assertArgument(isHexString(value[i], 32), "invalid ${ param } hash", `value[${i}]`, value[i]);
- }
- return value;
- }
- function _parseLegacy(data) {
- const fields = decodeRlp(data);
- assertArgument(Array.isArray(fields) && (fields.length === 9 || fields.length === 6), "invalid field count for legacy transaction", "data", data);
- const tx = {
- type: 0,
- nonce: handleNumber(fields[0], "nonce"),
- gasPrice: handleUint(fields[1], "gasPrice"),
- gasLimit: handleUint(fields[2], "gasLimit"),
- to: handleAddress(fields[3]),
- value: handleUint(fields[4], "value"),
- data: hexlify(fields[5]),
- chainId: BN_0$4
- };
- // Legacy unsigned transaction
- if (fields.length === 6) {
- return tx;
- }
- const v = handleUint(fields[6], "v");
- const r = handleUint(fields[7], "r");
- const s = handleUint(fields[8], "s");
- if (r === BN_0$4 && s === BN_0$4) {
- // EIP-155 unsigned transaction
- tx.chainId = v;
- }
- else {
- // Compute the EIP-155 chain ID (or 0 for legacy)
- let chainId = (v - BN_35) / BN_2$2;
- if (chainId < BN_0$4) {
- chainId = BN_0$4;
- }
- tx.chainId = chainId;
- // Signed Legacy Transaction
- assertArgument(chainId !== BN_0$4 || (v === BN_27 || v === BN_28), "non-canonical legacy v", "v", fields[6]);
- tx.signature = Signature.from({
- r: zeroPadValue(fields[7], 32),
- s: zeroPadValue(fields[8], 32),
- v
- });
- //tx.hash = keccak256(data);
- }
- return tx;
- }
- function _serializeLegacy(tx, sig) {
- const fields = [
- formatNumber(tx.nonce, "nonce"),
- formatNumber(tx.gasPrice || 0, "gasPrice"),
- formatNumber(tx.gasLimit, "gasLimit"),
- (tx.to || "0x"),
- formatNumber(tx.value, "value"),
- tx.data,
- ];
- let chainId = BN_0$4;
- if (tx.chainId != BN_0$4) {
- // A chainId was provided; if non-zero we'll use EIP-155
- chainId = getBigInt(tx.chainId, "tx.chainId");
- // We have a chainId in the tx and an EIP-155 v in the signature,
- // make sure they agree with each other
- assertArgument(!sig || sig.networkV == null || sig.legacyChainId === chainId, "tx.chainId/sig.v mismatch", "sig", sig);
- }
- else if (tx.signature) {
- // No explicit chainId, but EIP-155 have a derived implicit chainId
- const legacy = tx.signature.legacyChainId;
- if (legacy != null) {
- chainId = legacy;
- }
- }
- // Requesting an unsigned transaction
- if (!sig) {
- // We have an EIP-155 transaction (chainId was specified and non-zero)
- if (chainId !== BN_0$4) {
- fields.push(toBeArray(chainId));
- fields.push("0x");
- fields.push("0x");
- }
- return encodeRlp(fields);
- }
- // @TODO: We should probably check that tx.signature, chainId, and sig
- // match but that logic could break existing code, so schedule
- // this for the next major bump.
- // Compute the EIP-155 v
- let v = BigInt(27 + sig.yParity);
- if (chainId !== BN_0$4) {
- v = Signature.getChainIdV(chainId, sig.v);
- }
- else if (BigInt(sig.v) !== v) {
- assertArgument(false, "tx.chainId/sig.v mismatch", "sig", sig);
- }
- // Add the signature
- fields.push(toBeArray(v));
- fields.push(toBeArray(sig.r));
- fields.push(toBeArray(sig.s));
- return encodeRlp(fields);
- }
- function _parseEipSignature(tx, fields) {
- let yParity;
- try {
- yParity = handleNumber(fields[0], "yParity");
- if (yParity !== 0 && yParity !== 1) {
- throw new Error("bad yParity");
- }
- }
- catch (error) {
- assertArgument(false, "invalid yParity", "yParity", fields[0]);
- }
- const r = zeroPadValue(fields[1], 32);
- const s = zeroPadValue(fields[2], 32);
- const signature = Signature.from({ r, s, yParity });
- tx.signature = signature;
- }
- function _parseEip1559(data) {
- const fields = decodeRlp(getBytes(data).slice(1));
- assertArgument(Array.isArray(fields) && (fields.length === 9 || fields.length === 12), "invalid field count for transaction type: 2", "data", hexlify(data));
- const tx = {
- type: 2,
- chainId: handleUint(fields[0], "chainId"),
- nonce: handleNumber(fields[1], "nonce"),
- maxPriorityFeePerGas: handleUint(fields[2], "maxPriorityFeePerGas"),
- maxFeePerGas: handleUint(fields[3], "maxFeePerGas"),
- gasPrice: null,
- gasLimit: handleUint(fields[4], "gasLimit"),
- to: handleAddress(fields[5]),
- value: handleUint(fields[6], "value"),
- data: hexlify(fields[7]),
- accessList: handleAccessList(fields[8], "accessList"),
- };
- // Unsigned EIP-1559 Transaction
- if (fields.length === 9) {
- return tx;
- }
- //tx.hash = keccak256(data);
- _parseEipSignature(tx, fields.slice(9));
- return tx;
- }
- function _serializeEip1559(tx, sig) {
- const fields = [
- formatNumber(tx.chainId, "chainId"),
- formatNumber(tx.nonce, "nonce"),
- formatNumber(tx.maxPriorityFeePerGas || 0, "maxPriorityFeePerGas"),
- formatNumber(tx.maxFeePerGas || 0, "maxFeePerGas"),
- formatNumber(tx.gasLimit, "gasLimit"),
- (tx.to || "0x"),
- formatNumber(tx.value, "value"),
- tx.data,
- formatAccessList(tx.accessList || [])
- ];
- if (sig) {
- fields.push(formatNumber(sig.yParity, "yParity"));
- fields.push(toBeArray(sig.r));
- fields.push(toBeArray(sig.s));
- }
- return concat(["0x02", encodeRlp(fields)]);
- }
- function _parseEip2930(data) {
- const fields = decodeRlp(getBytes(data).slice(1));
- assertArgument(Array.isArray(fields) && (fields.length === 8 || fields.length === 11), "invalid field count for transaction type: 1", "data", hexlify(data));
- const tx = {
- type: 1,
- chainId: handleUint(fields[0], "chainId"),
- nonce: handleNumber(fields[1], "nonce"),
- gasPrice: handleUint(fields[2], "gasPrice"),
- gasLimit: handleUint(fields[3], "gasLimit"),
- to: handleAddress(fields[4]),
- value: handleUint(fields[5], "value"),
- data: hexlify(fields[6]),
- accessList: handleAccessList(fields[7], "accessList")
- };
- // Unsigned EIP-2930 Transaction
- if (fields.length === 8) {
- return tx;
- }
- //tx.hash = keccak256(data);
- _parseEipSignature(tx, fields.slice(8));
- return tx;
- }
- function _serializeEip2930(tx, sig) {
- const fields = [
- formatNumber(tx.chainId, "chainId"),
- formatNumber(tx.nonce, "nonce"),
- formatNumber(tx.gasPrice || 0, "gasPrice"),
- formatNumber(tx.gasLimit, "gasLimit"),
- (tx.to || "0x"),
- formatNumber(tx.value, "value"),
- tx.data,
- formatAccessList(tx.accessList || [])
- ];
- if (sig) {
- fields.push(formatNumber(sig.yParity, "recoveryParam"));
- fields.push(toBeArray(sig.r));
- fields.push(toBeArray(sig.s));
- }
- return concat(["0x01", encodeRlp(fields)]);
- }
- function _parseEip4844(data) {
- let fields = decodeRlp(getBytes(data).slice(1));
- let typeName = "3";
- let blobs = null;
- // Parse the network format
- if (fields.length === 4 && Array.isArray(fields[0])) {
- typeName = "3 (network format)";
- const fBlobs = fields[1], fCommits = fields[2], fProofs = fields[3];
- assertArgument(Array.isArray(fBlobs), "invalid network format: blobs not an array", "fields[1]", fBlobs);
- assertArgument(Array.isArray(fCommits), "invalid network format: commitments not an array", "fields[2]", fCommits);
- assertArgument(Array.isArray(fProofs), "invalid network format: proofs not an array", "fields[3]", fProofs);
- assertArgument(fBlobs.length === fCommits.length, "invalid network format: blobs/commitments length mismatch", "fields", fields);
- assertArgument(fBlobs.length === fProofs.length, "invalid network format: blobs/proofs length mismatch", "fields", fields);
- blobs = [];
- for (let i = 0; i < fields[1].length; i++) {
- blobs.push({
- data: fBlobs[i],
- commitment: fCommits[i],
- proof: fProofs[i],
- });
- }
- fields = fields[0];
- }
- assertArgument(Array.isArray(fields) && (fields.length === 11 || fields.length === 14), `invalid field count for transaction type: ${typeName}`, "data", hexlify(data));
- const tx = {
- type: 3,
- chainId: handleUint(fields[0], "chainId"),
- nonce: handleNumber(fields[1], "nonce"),
- maxPriorityFeePerGas: handleUint(fields[2], "maxPriorityFeePerGas"),
- maxFeePerGas: handleUint(fields[3], "maxFeePerGas"),
- gasPrice: null,
- gasLimit: handleUint(fields[4], "gasLimit"),
- to: handleAddress(fields[5]),
- value: handleUint(fields[6], "value"),
- data: hexlify(fields[7]),
- accessList: handleAccessList(fields[8], "accessList"),
- maxFeePerBlobGas: handleUint(fields[9], "maxFeePerBlobGas"),
- blobVersionedHashes: fields[10]
- };
- if (blobs) {
- tx.blobs = blobs;
- }
- assertArgument(tx.to != null, `invalid address for transaction type: ${typeName}`, "data", data);
- assertArgument(Array.isArray(tx.blobVersionedHashes), "invalid blobVersionedHashes: must be an array", "data", data);
- for (let i = 0; i < tx.blobVersionedHashes.length; i++) {
- assertArgument(isHexString(tx.blobVersionedHashes[i], 32), `invalid blobVersionedHash at index ${i}: must be length 32`, "data", data);
- }
- // Unsigned EIP-4844 Transaction
- if (fields.length === 11) {
- return tx;
- }
- // @TODO: Do we need to do this? This is only called internally
- // and used to verify hashes; it might save time to not do this
- //tx.hash = keccak256(concat([ "0x03", encodeRlp(fields) ]));
- _parseEipSignature(tx, fields.slice(11));
- return tx;
- }
- function _serializeEip4844(tx, sig, blobs) {
- const fields = [
- formatNumber(tx.chainId, "chainId"),
- formatNumber(tx.nonce, "nonce"),
- formatNumber(tx.maxPriorityFeePerGas || 0, "maxPriorityFeePerGas"),
- formatNumber(tx.maxFeePerGas || 0, "maxFeePerGas"),
- formatNumber(tx.gasLimit, "gasLimit"),
- (tx.to || ZeroAddress),
- formatNumber(tx.value, "value"),
- tx.data,
- formatAccessList(tx.accessList || []),
- formatNumber(tx.maxFeePerBlobGas || 0, "maxFeePerBlobGas"),
- formatHashes(tx.blobVersionedHashes || [], "blobVersionedHashes")
- ];
- if (sig) {
- fields.push(formatNumber(sig.yParity, "yParity"));
- fields.push(toBeArray(sig.r));
- fields.push(toBeArray(sig.s));
- // We have blobs; return the network wrapped format
- if (blobs) {
- return concat([
- "0x03",
- encodeRlp([
- fields,
- blobs.map((b) => b.data),
- blobs.map((b) => b.commitment),
- blobs.map((b) => b.proof),
- ])
- ]);
- }
- }
- return concat(["0x03", encodeRlp(fields)]);
- }
- /**
- * A **Transaction** describes an operation to be executed on
- * Ethereum by an Externally Owned Account (EOA). It includes
- * who (the [[to]] address), what (the [[data]]) and how much (the
- * [[value]] in ether) the operation should entail.
- *
- * @example:
- * tx = new Transaction()
- * //_result:
- *
- * tx.data = "0x1234";
- * //_result:
- */
- class Transaction {
- #type;
- #to;
- #data;
- #nonce;
- #gasLimit;
- #gasPrice;
- #maxPriorityFeePerGas;
- #maxFeePerGas;
- #value;
- #chainId;
- #sig;
- #accessList;
- #maxFeePerBlobGas;
- #blobVersionedHashes;
- #kzg;
- #blobs;
- /**
- * The transaction type.
- *
- * If null, the type will be automatically inferred based on
- * explicit properties.
- */
- get type() { return this.#type; }
- set type(value) {
- switch (value) {
- case null:
- this.#type = null;
- break;
- case 0:
- case "legacy":
- this.#type = 0;
- break;
- case 1:
- case "berlin":
- case "eip-2930":
- this.#type = 1;
- break;
- case 2:
- case "london":
- case "eip-1559":
- this.#type = 2;
- break;
- case 3:
- case "cancun":
- case "eip-4844":
- this.#type = 3;
- break;
- default:
- assertArgument(false, "unsupported transaction type", "type", value);
- }
- }
- /**
- * The name of the transaction type.
- */
- get typeName() {
- switch (this.type) {
- case 0: return "legacy";
- case 1: return "eip-2930";
- case 2: return "eip-1559";
- case 3: return "eip-4844";
- }
- return null;
- }
- /**
- * The ``to`` address for the transaction or ``null`` if the
- * transaction is an ``init`` transaction.
- */
- get to() {
- const value = this.#to;
- if (value == null && this.type === 3) {
- return ZeroAddress;
- }
- return value;
- }
- set to(value) {
- this.#to = (value == null) ? null : getAddress(value);
- }
- /**
- * The transaction nonce.
- */
- get nonce() { return this.#nonce; }
- set nonce(value) { this.#nonce = getNumber(value, "value"); }
- /**
- * The gas limit.
- */
- get gasLimit() { return this.#gasLimit; }
- set gasLimit(value) { this.#gasLimit = getBigInt(value); }
- /**
- * The gas price.
- *
- * On legacy networks this defines the fee that will be paid. On
- * EIP-1559 networks, this should be ``null``.
- */
- get gasPrice() {
- const value = this.#gasPrice;
- if (value == null && (this.type === 0 || this.type === 1)) {
- return BN_0$4;
- }
- return value;
- }
- set gasPrice(value) {
- this.#gasPrice = (value == null) ? null : getBigInt(value, "gasPrice");
- }
- /**
- * The maximum priority fee per unit of gas to pay. On legacy
- * networks this should be ``null``.
- */
- get maxPriorityFeePerGas() {
- const value = this.#maxPriorityFeePerGas;
- if (value == null) {
- if (this.type === 2 || this.type === 3) {
- return BN_0$4;
- }
- return null;
- }
- return value;
- }
- set maxPriorityFeePerGas(value) {
- this.#maxPriorityFeePerGas = (value == null) ? null : getBigInt(value, "maxPriorityFeePerGas");
- }
- /**
- * The maximum total fee per unit of gas to pay. On legacy
- * networks this should be ``null``.
- */
- get maxFeePerGas() {
- const value = this.#maxFeePerGas;
- if (value == null) {
- if (this.type === 2 || this.type === 3) {
- return BN_0$4;
- }
- return null;
- }
- return value;
- }
- set maxFeePerGas(value) {
- this.#maxFeePerGas = (value == null) ? null : getBigInt(value, "maxFeePerGas");
- }
- /**
- * The transaction data. For ``init`` transactions this is the
- * deployment code.
- */
- get data() { return this.#data; }
- set data(value) { this.#data = hexlify(value); }
- /**
- * The amount of ether (in wei) to send in this transactions.
- */
- get value() { return this.#value; }
- set value(value) {
- this.#value = getBigInt(value, "value");
- }
- /**
- * The chain ID this transaction is valid on.
- */
- get chainId() { return this.#chainId; }
- set chainId(value) { this.#chainId = getBigInt(value); }
- /**
- * If signed, the signature for this transaction.
- */
- get signature() { return this.#sig || null; }
- set signature(value) {
- this.#sig = (value == null) ? null : Signature.from(value);
- }
- /**
- * The access list.
- *
- * An access list permits discounted (but pre-paid) access to
- * bytecode and state variable access within contract execution.
- */
- get accessList() {
- const value = this.#accessList || null;
- if (value == null) {
- if (this.type === 1 || this.type === 2 || this.type === 3) {
- // @TODO: in v7, this should assign the value or become
- // a live object itself, otherwise mutation is inconsistent
- return [];
- }
- return null;
- }
- return value;
- }
- set accessList(value) {
- this.#accessList = (value == null) ? null : accessListify(value);
- }
- /**
- * The max fee per blob gas for Cancun transactions.
- */
- get maxFeePerBlobGas() {
- const value = this.#maxFeePerBlobGas;
- if (value == null && this.type === 3) {
- return BN_0$4;
- }
- return value;
- }
- set maxFeePerBlobGas(value) {
- this.#maxFeePerBlobGas = (value == null) ? null : getBigInt(value, "maxFeePerBlobGas");
- }
- /**
- * The BLOb versioned hashes for Cancun transactions.
- */
- get blobVersionedHashes() {
- // @TODO: Mutation is inconsistent; if unset, the returned value
- // cannot mutate the object, if set it can
- let value = this.#blobVersionedHashes;
- if (value == null && this.type === 3) {
- return [];
- }
- return value;
- }
- set blobVersionedHashes(value) {
- if (value != null) {
- assertArgument(Array.isArray(value), "blobVersionedHashes must be an Array", "value", value);
- value = value.slice();
- for (let i = 0; i < value.length; i++) {
- assertArgument(isHexString(value[i], 32), "invalid blobVersionedHash", `value[${i}]`, value[i]);
- }
- }
- this.#blobVersionedHashes = value;
- }
- /**
- * The BLObs for the Transaction, if any.
- *
- * If ``blobs`` is non-``null``, then the [[seriailized]]
- * will return the network formatted sidecar, otherwise it
- * will return the standard [[link-eip-2718]] payload. The
- * [[unsignedSerialized]] is unaffected regardless.
- *
- * When setting ``blobs``, either fully valid [[Blob]] objects
- * may be specified (i.e. correctly padded, with correct
- * committments and proofs) or a raw [[BytesLike]] may
- * be provided.
- *
- * If raw [[BytesLike]] are provided, the [[kzg]] property **must**
- * be already set. The blob will be correctly padded and the
- * [[KzgLibrary]] will be used to compute the committment and
- * proof for the blob.
- *
- * A BLOb is a sequence of field elements, each of which must
- * be within the BLS field modulo, so some additional processing
- * may be required to encode arbitrary data to ensure each 32 byte
- * field is within the valid range.
- *
- * Setting this automatically populates [[blobVersionedHashes]],
- * overwriting any existing values. Setting this to ``null``
- * does **not** remove the [[blobVersionedHashes]], leaving them
- * present.
- */
- get blobs() {
- if (this.#blobs == null) {
- return null;
- }
- return this.#blobs.map((b) => Object.assign({}, b));
- }
- set blobs(_blobs) {
- if (_blobs == null) {
- this.#blobs = null;
- return;
- }
- const blobs = [];
- const versionedHashes = [];
- for (let i = 0; i < _blobs.length; i++) {
- const blob = _blobs[i];
- if (isBytesLike(blob)) {
- assert(this.#kzg, "adding a raw blob requires a KZG library", "UNSUPPORTED_OPERATION", {
- operation: "set blobs()"
- });
- let data = getBytes(blob);
- assertArgument(data.length <= BLOB_SIZE, "blob is too large", `blobs[${i}]`, blob);
- // Pad blob if necessary
- if (data.length !== BLOB_SIZE) {
- const padded = new Uint8Array(BLOB_SIZE);
- padded.set(data);
- data = padded;
- }
- const commit = this.#kzg.blobToKzgCommitment(data);
- const proof = hexlify(this.#kzg.computeBlobKzgProof(data, commit));
- blobs.push({
- data: hexlify(data),
- commitment: hexlify(commit),
- proof
- });
- versionedHashes.push(getVersionedHash(1, commit));
- }
- else {
- const commit = hexlify(blob.commitment);
- blobs.push({
- data: hexlify(blob.data),
- commitment: commit,
- proof: hexlify(blob.proof)
- });
- versionedHashes.push(getVersionedHash(1, commit));
- }
- }
- this.#blobs = blobs;
- this.#blobVersionedHashes = versionedHashes;
- }
- get kzg() { return this.#kzg; }
- set kzg(kzg) {
- this.#kzg = kzg;
- }
- /**
- * Creates a new Transaction with default values.
- */
- constructor() {
- this.#type = null;
- this.#to = null;
- this.#nonce = 0;
- this.#gasLimit = BN_0$4;
- this.#gasPrice = null;
- this.#maxPriorityFeePerGas = null;
- this.#maxFeePerGas = null;
- this.#data = "0x";
- this.#value = BN_0$4;
- this.#chainId = BN_0$4;
- this.#sig = null;
- this.#accessList = null;
- this.#maxFeePerBlobGas = null;
- this.#blobVersionedHashes = null;
- this.#blobs = null;
- this.#kzg = null;
- }
- /**
- * The transaction hash, if signed. Otherwise, ``null``.
- */
- get hash() {
- if (this.signature == null) {
- return null;
- }
- return keccak256(this.#getSerialized(true, false));
- }
- /**
- * The pre-image hash of this transaction.
- *
- * This is the digest that a [[Signer]] must sign to authorize
- * this transaction.
- */
- get unsignedHash() {
- return keccak256(this.unsignedSerialized);
- }
- /**
- * The sending address, if signed. Otherwise, ``null``.
- */
- get from() {
- if (this.signature == null) {
- return null;
- }
- return recoverAddress(this.unsignedHash, this.signature);
- }
- /**
- * The public key of the sender, if signed. Otherwise, ``null``.
- */
- get fromPublicKey() {
- if (this.signature == null) {
- return null;
- }
- return SigningKey.recoverPublicKey(this.unsignedHash, this.signature);
- }
- /**
- * Returns true if signed.
- *
- * This provides a Type Guard that properties requiring a signed
- * transaction are non-null.
- */
- isSigned() {
- return this.signature != null;
- }
- #getSerialized(signed, sidecar) {
- assert(!signed || this.signature != null, "cannot serialize unsigned transaction; maybe you meant .unsignedSerialized", "UNSUPPORTED_OPERATION", { operation: ".serialized" });
- const sig = signed ? this.signature : null;
- switch (this.inferType()) {
- case 0:
- return _serializeLegacy(this, sig);
- case 1:
- return _serializeEip2930(this, sig);
- case 2:
- return _serializeEip1559(this, sig);
- case 3:
- return _serializeEip4844(this, sig, sidecar ? this.blobs : null);
- }
- assert(false, "unsupported transaction type", "UNSUPPORTED_OPERATION", { operation: ".serialized" });
- }
- /**
- * The serialized transaction.
- *
- * This throws if the transaction is unsigned. For the pre-image,
- * use [[unsignedSerialized]].
- */
- get serialized() {
- return this.#getSerialized(true, true);
- }
- /**
- * The transaction pre-image.
- *
- * The hash of this is the digest which needs to be signed to
- * authorize this transaction.
- */
- get unsignedSerialized() {
- return this.#getSerialized(false, false);
- }
- /**
- * Return the most "likely" type; currently the highest
- * supported transaction type.
- */
- inferType() {
- const types = this.inferTypes();
- // Prefer London (EIP-1559) over Cancun (BLOb)
- if (types.indexOf(2) >= 0) {
- return 2;
- }
- // Return the highest inferred type
- return (types.pop());
- }
- /**
- * Validates the explicit properties and returns a list of compatible
- * transaction types.
- */
- inferTypes() {
- // Checks that there are no conflicting properties set
- const hasGasPrice = this.gasPrice != null;
- const hasFee = (this.maxFeePerGas != null || this.maxPriorityFeePerGas != null);
- const hasAccessList = (this.accessList != null);
- const hasBlob = (this.#maxFeePerBlobGas != null || this.#blobVersionedHashes);
- //if (hasGasPrice && hasFee) {
- // throw new Error("transaction cannot have gasPrice and maxFeePerGas");
- //}
- if (this.maxFeePerGas != null && this.maxPriorityFeePerGas != null) {
- assert(this.maxFeePerGas >= this.maxPriorityFeePerGas, "priorityFee cannot be more than maxFee", "BAD_DATA", { value: this });
- }
- //if (this.type === 2 && hasGasPrice) {
- // throw new Error("eip-1559 transaction cannot have gasPrice");
- //}
- assert(!hasFee || (this.type !== 0 && this.type !== 1), "transaction type cannot have maxFeePerGas or maxPriorityFeePerGas", "BAD_DATA", { value: this });
- assert(this.type !== 0 || !hasAccessList, "legacy transaction cannot have accessList", "BAD_DATA", { value: this });
- const types = [];
- // Explicit type
- if (this.type != null) {
- types.push(this.type);
- }
- else {
- if (hasFee) {
- types.push(2);
- }
- else if (hasGasPrice) {
- types.push(1);
- if (!hasAccessList) {
- types.push(0);
- }
- }
- else if (hasAccessList) {
- types.push(1);
- types.push(2);
- }
- else if (hasBlob && this.to) {
- types.push(3);
- }
- else {
- types.push(0);
- types.push(1);
- types.push(2);
- types.push(3);
- }
- }
- types.sort();
- return types;
- }
- /**
- * Returns true if this transaction is a legacy transaction (i.e.
- * ``type === 0``).
- *
- * This provides a Type Guard that the related properties are
- * non-null.
- */
- isLegacy() {
- return (this.type === 0);
- }
- /**
- * Returns true if this transaction is berlin hardform transaction (i.e.
- * ``type === 1``).
- *
- * This provides a Type Guard that the related properties are
- * non-null.
- */
- isBerlin() {
- return (this.type === 1);
- }
- /**
- * Returns true if this transaction is london hardform transaction (i.e.
- * ``type === 2``).
- *
- * This provides a Type Guard that the related properties are
- * non-null.
- */
- isLondon() {
- return (this.type === 2);
- }
- /**
- * Returns true if this transaction is an [[link-eip-4844]] BLOB
- * transaction.
- *
- * This provides a Type Guard that the related properties are
- * non-null.
- */
- isCancun() {
- return (this.type === 3);
- }
- /**
- * Create a copy of this transaciton.
- */
- clone() {
- return Transaction.from(this);
- }
- /**
- * Return a JSON-friendly object.
- */
- toJSON() {
- const s = (v) => {
- if (v == null) {
- return null;
- }
- return v.toString();
- };
- return {
- type: this.type,
- to: this.to,
- // from: this.from,
- data: this.data,
- nonce: this.nonce,
- gasLimit: s(this.gasLimit),
- gasPrice: s(this.gasPrice),
- maxPriorityFeePerGas: s(this.maxPriorityFeePerGas),
- maxFeePerGas: s(this.maxFeePerGas),
- value: s(this.value),
- chainId: s(this.chainId),
- sig: this.signature ? this.signature.toJSON() : null,
- accessList: this.accessList
- };
- }
- /**
- * Create a **Transaction** from a serialized transaction or a
- * Transaction-like object.
- */
- static from(tx) {
- if (tx == null) {
- return new Transaction();
- }
- if (typeof (tx) === "string") {
- const payload = getBytes(tx);
- if (payload[0] >= 0x7f) { // @TODO: > vs >= ??
- return Transaction.from(_parseLegacy(payload));
- }
- switch (payload[0]) {
- case 1: return Transaction.from(_parseEip2930(payload));
- case 2: return Transaction.from(_parseEip1559(payload));
- case 3: return Transaction.from(_parseEip4844(payload));
- }
- assert(false, "unsupported transaction type", "UNSUPPORTED_OPERATION", { operation: "from" });
- }
- const result = new Transaction();
- if (tx.type != null) {
- result.type = tx.type;
- }
- if (tx.to != null) {
- result.to = tx.to;
- }
- if (tx.nonce != null) {
- result.nonce = tx.nonce;
- }
- if (tx.gasLimit != null) {
- result.gasLimit = tx.gasLimit;
- }
- if (tx.gasPrice != null) {
- result.gasPrice = tx.gasPrice;
- }
- if (tx.maxPriorityFeePerGas != null) {
- result.maxPriorityFeePerGas = tx.maxPriorityFeePerGas;
- }
- if (tx.maxFeePerGas != null) {
- result.maxFeePerGas = tx.maxFeePerGas;
- }
- if (tx.maxFeePerBlobGas != null) {
- result.maxFeePerBlobGas = tx.maxFeePerBlobGas;
- }
- if (tx.data != null) {
- result.data = tx.data;
- }
- if (tx.value != null) {
- result.value = tx.value;
- }
- if (tx.chainId != null) {
- result.chainId = tx.chainId;
- }
- if (tx.signature != null) {
- result.signature = Signature.from(tx.signature);
- }
- if (tx.accessList != null) {
- result.accessList = tx.accessList;
- }
- // This will get overwritten by blobs, if present
- if (tx.blobVersionedHashes != null) {
- result.blobVersionedHashes = tx.blobVersionedHashes;
- }
- // Make sure we assign the kzg before assigning blobs, which
- // require the library in the event raw blob data is provided.
- if (tx.kzg != null) {
- result.kzg = tx.kzg;
- }
- if (tx.blobs != null) {
- result.blobs = tx.blobs;
- }
- if (tx.hash != null) {
- assertArgument(result.isSigned(), "unsigned transaction cannot define '.hash'", "tx", tx);
- assertArgument(result.hash === tx.hash, "hash mismatch", "tx", tx);
- }
- if (tx.from != null) {
- assertArgument(result.isSigned(), "unsigned transaction cannot define '.from'", "tx", tx);
- assertArgument(result.from.toLowerCase() === (tx.from || "").toLowerCase(), "from mismatch", "tx", tx);
- }
- return result;
- }
- }
- /**
- * Computes the [[link-eip-191]] personal-sign message digest to sign.
- *
- * This prefixes the message with [[MessagePrefix]] and the decimal length
- * of %%message%% and computes the [[keccak256]] digest.
- *
- * If %%message%% is a string, it is converted to its UTF-8 bytes
- * first. To compute the digest of a [[DataHexString]], it must be converted
- * to [bytes](getBytes).
- *
- * @example:
- * hashMessage("Hello World")
- * //_result:
- *
- * // Hashes the SIX (6) string characters, i.e.
- * // [ "0", "x", "4", "2", "4", "3" ]
- * hashMessage("0x4243")
- * //_result:
- *
- * // Hashes the TWO (2) bytes [ 0x42, 0x43 ]...
- * hashMessage(getBytes("0x4243"))
- * //_result:
- *
- * // ...which is equal to using data
- * hashMessage(new Uint8Array([ 0x42, 0x43 ]))
- * //_result:
- *
- */
- function hashMessage(message) {
- if (typeof (message) === "string") {
- message = toUtf8Bytes(message);
- }
- return keccak256(concat([
- toUtf8Bytes(MessagePrefix),
- toUtf8Bytes(String(message.length)),
- message
- ]));
- }
- /**
- * Return the address of the private key that produced
- * the signature %%sig%% during signing for %%message%%.
- */
- function verifyMessage(message, sig) {
- const digest = hashMessage(message);
- return recoverAddress(digest, sig);
- }
- const regexBytes = new RegExp("^bytes([0-9]+)$");
- const regexNumber = new RegExp("^(u?int)([0-9]*)$");
- const regexArray = new RegExp("^(.*)\\[([0-9]*)\\]$");
- function _pack(type, value, isArray) {
- switch (type) {
- case "address":
- if (isArray) {
- return getBytes(zeroPadValue(value, 32));
- }
- return getBytes(getAddress(value));
- case "string":
- return toUtf8Bytes(value);
- case "bytes":
- return getBytes(value);
- case "bool":
- value = (!!value ? "0x01" : "0x00");
- if (isArray) {
- return getBytes(zeroPadValue(value, 32));
- }
- return getBytes(value);
- }
- let match = type.match(regexNumber);
- if (match) {
- let signed = (match[1] === "int");
- let size = parseInt(match[2] || "256");
- assertArgument((!match[2] || match[2] === String(size)) && (size % 8 === 0) && size !== 0 && size <= 256, "invalid number type", "type", type);
- if (isArray) {
- size = 256;
- }
- if (signed) {
- value = toTwos(value, size);
- }
- return getBytes(zeroPadValue(toBeArray(value), size / 8));
- }
- match = type.match(regexBytes);
- if (match) {
- const size = parseInt(match[1]);
- assertArgument(String(size) === match[1] && size !== 0 && size <= 32, "invalid bytes type", "type", type);
- assertArgument(dataLength(value) === size, `invalid value for ${type}`, "value", value);
- if (isArray) {
- return getBytes(zeroPadBytes(value, 32));
- }
- return value;
- }
- match = type.match(regexArray);
- if (match && Array.isArray(value)) {
- const baseType = match[1];
- const count = parseInt(match[2] || String(value.length));
- assertArgument(count === value.length, `invalid array length for ${type}`, "value", value);
- const result = [];
- value.forEach(function (value) {
- result.push(_pack(baseType, value, true));
- });
- return getBytes(concat(result));
- }
- assertArgument(false, "invalid type", "type", type);
- }
- // @TODO: Array Enum
- /**
- * Computes the [[link-solc-packed]] representation of %%values%%
- * respectively to their %%types%%.
- *
- * @example:
- * addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
- * solidityPacked([ "address", "uint" ], [ addr, 45 ]);
- * //_result:
- */
- function solidityPacked(types, values) {
- assertArgument(types.length === values.length, "wrong number of values; expected ${ types.length }", "values", values);
- const tight = [];
- types.forEach(function (type, index) {
- tight.push(_pack(type, values[index]));
- });
- return hexlify(concat(tight));
- }
- /**
- * Computes the [[link-solc-packed]] [[keccak256]] hash of %%values%%
- * respectively to their %%types%%.
- *
- * @example:
- * addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
- * solidityPackedKeccak256([ "address", "uint" ], [ addr, 45 ]);
- * //_result:
- */
- function solidityPackedKeccak256(types, values) {
- return keccak256(solidityPacked(types, values));
- }
- /**
- * Computes the [[link-solc-packed]] [[sha256]] hash of %%values%%
- * respectively to their %%types%%.
- *
- * @example:
- * addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
- * solidityPackedSha256([ "address", "uint" ], [ addr, 45 ]);
- * //_result:
- */
- function solidityPackedSha256(types, values) {
- return sha256(solidityPacked(types, values));
- }
- //import { TypedDataDomain, TypedDataField } from "@ethersproject/providerabstract-signer";
- const padding = new Uint8Array(32);
- padding.fill(0);
- const BN__1 = BigInt(-1);
- const BN_0$3 = BigInt(0);
- const BN_1$1 = BigInt(1);
- const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- function hexPadRight(value) {
- const bytes = getBytes(value);
- const padOffset = bytes.length % 32;
- if (padOffset) {
- return concat([bytes, padding.slice(padOffset)]);
- }
- return hexlify(bytes);
- }
- const hexTrue = toBeHex(BN_1$1, 32);
- const hexFalse = toBeHex(BN_0$3, 32);
- const domainFieldTypes = {
- name: "string",
- version: "string",
- chainId: "uint256",
- verifyingContract: "address",
- salt: "bytes32"
- };
- const domainFieldNames = [
- "name", "version", "chainId", "verifyingContract", "salt"
- ];
- function checkString(key) {
- return function (value) {
- assertArgument(typeof (value) === "string", `invalid domain value for ${JSON.stringify(key)}`, `domain.${key}`, value);
- return value;
- };
- }
- const domainChecks = {
- name: checkString("name"),
- version: checkString("version"),
- chainId: function (_value) {
- const value = getBigInt(_value, "domain.chainId");
- assertArgument(value >= 0, "invalid chain ID", "domain.chainId", _value);
- if (Number.isSafeInteger(value)) {
- return Number(value);
- }
- return toQuantity(value);
- },
- verifyingContract: function (value) {
- try {
- return getAddress(value).toLowerCase();
- }
- catch (error) { }
- assertArgument(false, `invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
- },
- salt: function (value) {
- const bytes = getBytes(value, "domain.salt");
- assertArgument(bytes.length === 32, `invalid domain value "salt"`, "domain.salt", value);
- return hexlify(bytes);
- }
- };
- function getBaseEncoder(type) {
- // intXX and uintXX
- {
- const match = type.match(/^(u?)int(\d+)$/);
- if (match) {
- const signed = (match[1] === "");
- const width = parseInt(match[2]);
- assertArgument(width % 8 === 0 && width !== 0 && width <= 256 && match[2] === String(width), "invalid numeric width", "type", type);
- const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1) : width);
- const boundsLower = signed ? ((boundsUpper + BN_1$1) * BN__1) : BN_0$3;
- return function (_value) {
- const value = getBigInt(_value, "value");
- assertArgument(value >= boundsLower && value <= boundsUpper, `value out-of-bounds for ${type}`, "value", value);
- return toBeHex(signed ? toTwos(value, 256) : value, 32);
- };
- }
- }
- // bytesXX
- {
- const match = type.match(/^bytes(\d+)$/);
- if (match) {
- const width = parseInt(match[1]);
- assertArgument(width !== 0 && width <= 32 && match[1] === String(width), "invalid bytes width", "type", type);
- return function (value) {
- const bytes = getBytes(value);
- assertArgument(bytes.length === width, `invalid length for ${type}`, "value", value);
- return hexPadRight(value);
- };
- }
- }
- switch (type) {
- case "address": return function (value) {
- return zeroPadValue(getAddress(value), 32);
- };
- case "bool": return function (value) {
- return ((!value) ? hexFalse : hexTrue);
- };
- case "bytes": return function (value) {
- return keccak256(value);
- };
- case "string": return function (value) {
- return id(value);
- };
- }
- return null;
- }
- function encodeType(name, fields) {
- return `${name}(${fields.map(({ name, type }) => (type + " " + name)).join(",")})`;
- }
- // foo[][3] => { base: "foo", index: "[][3]", array: {
- // base: "foo", prefix: "foo[]", count: 3 } }
- function splitArray(type) {
- const match = type.match(/^([^\x5b]*)((\x5b\d*\x5d)*)(\x5b(\d*)\x5d)$/);
- if (match) {
- return {
- base: match[1],
- index: (match[2] + match[4]),
- array: {
- base: match[1],
- prefix: (match[1] + match[2]),
- count: (match[5] ? parseInt(match[5]) : -1),
- }
- };
- }
- return { base: type };
- }
- /**
- * A **TypedDataEncode** prepares and encodes [[link-eip-712]] payloads
- * for signed typed data.
- *
- * This is useful for those that wish to compute various components of a
- * typed data hash, primary types, or sub-components, but generally the
- * higher level [[Signer-signTypedData]] is more useful.
- */
- class TypedDataEncoder {
- /**
- * The primary type for the structured [[types]].
- *
- * This is derived automatically from the [[types]], since no
- * recursion is possible, once the DAG for the types is consturcted
- * internally, the primary type must be the only remaining type with
- * no parent nodes.
- */
- primaryType;
- #types;
- /**
- * The types.
- */
- get types() {
- return JSON.parse(this.#types);
- }
- #fullTypes;
- #encoderCache;
- /**
- * Create a new **TypedDataEncoder** for %%types%%.
- *
- * This performs all necessary checking that types are valid and
- * do not violate the [[link-eip-712]] structural constraints as
- * well as computes the [[primaryType]].
- */
- constructor(_types) {
- this.#fullTypes = new Map();
- this.#encoderCache = new Map();
- // Link struct types to their direct child structs
- const links = new Map();
- // Link structs to structs which contain them as a child
- const parents = new Map();
- // Link all subtypes within a given struct
- const subtypes = new Map();
- const types = {};
- Object.keys(_types).forEach((type) => {
- types[type] = _types[type].map(({ name, type }) => {
- // Normalize the base type (unless name conflict)
- let { base, index } = splitArray(type);
- if (base === "int" && !_types["int"]) {
- base = "int256";
- }
- if (base === "uint" && !_types["uint"]) {
- base = "uint256";
- }
- return { name, type: (base + (index || "")) };
- });
- links.set(type, new Set());
- parents.set(type, []);
- subtypes.set(type, new Set());
- });
- this.#types = JSON.stringify(types);
- for (const name in types) {
- const uniqueNames = new Set();
- for (const field of types[name]) {
- // Check each field has a unique name
- assertArgument(!uniqueNames.has(field.name), `duplicate variable name ${JSON.stringify(field.name)} in ${JSON.stringify(name)}`, "types", _types);
- uniqueNames.add(field.name);
- // Get the base type (drop any array specifiers)
- const baseType = splitArray(field.type).base;
- assertArgument(baseType !== name, `circular type reference to ${JSON.stringify(baseType)}`, "types", _types);
- // Is this a base encoding type?
- const encoder = getBaseEncoder(baseType);
- if (encoder) {
- continue;
- }
- assertArgument(parents.has(baseType), `unknown type ${JSON.stringify(baseType)}`, "types", _types);
- // Add linkage
- parents.get(baseType).push(name);
- links.get(name).add(baseType);
- }
- }
- // Deduce the primary type
- const primaryTypes = Array.from(parents.keys()).filter((n) => (parents.get(n).length === 0));
- assertArgument(primaryTypes.length !== 0, "missing primary type", "types", _types);
- assertArgument(primaryTypes.length === 1, `ambiguous primary types or unused types: ${primaryTypes.map((t) => (JSON.stringify(t))).join(", ")}`, "types", _types);
- defineProperties(this, { primaryType: primaryTypes[0] });
- // Check for circular type references
- function checkCircular(type, found) {
- assertArgument(!found.has(type), `circular type reference to ${JSON.stringify(type)}`, "types", _types);
- found.add(type);
- for (const child of links.get(type)) {
- if (!parents.has(child)) {
- continue;
- }
- // Recursively check children
- checkCircular(child, found);
- // Mark all ancestors as having this decendant
- for (const subtype of found) {
- subtypes.get(subtype).add(child);
- }
- }
- found.delete(type);
- }
- checkCircular(this.primaryType, new Set());
- // Compute each fully describe type
- for (const [name, set] of subtypes) {
- const st = Array.from(set);
- st.sort();
- this.#fullTypes.set(name, encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join(""));
- }
- }
- /**
- * Returnthe encoder for the specific %%type%%.
- */
- getEncoder(type) {
- let encoder = this.#encoderCache.get(type);
- if (!encoder) {
- encoder = this.#getEncoder(type);
- this.#encoderCache.set(type, encoder);
- }
- return encoder;
- }
- #getEncoder(type) {
- // Basic encoder type (address, bool, uint256, etc)
- {
- const encoder = getBaseEncoder(type);
- if (encoder) {
- return encoder;
- }
- }
- // Array
- const array = splitArray(type).array;
- if (array) {
- const subtype = array.prefix;
- const subEncoder = this.getEncoder(subtype);
- return (value) => {
- assertArgument(array.count === -1 || array.count === value.length, `array length mismatch; expected length ${array.count}`, "value", value);
- let result = value.map(subEncoder);
- if (this.#fullTypes.has(subtype)) {
- result = result.map(keccak256);
- }
- return keccak256(concat(result));
- };
- }
- // Struct
- const fields = this.types[type];
- if (fields) {
- const encodedType = id(this.#fullTypes.get(type));
- return (value) => {
- const values = fields.map(({ name, type }) => {
- const result = this.getEncoder(type)(value[name]);
- if (this.#fullTypes.has(type)) {
- return keccak256(result);
- }
- return result;
- });
- values.unshift(encodedType);
- return concat(values);
- };
- }
- assertArgument(false, `unknown type: ${type}`, "type", type);
- }
- /**
- * Return the full type for %%name%%.
- */
- encodeType(name) {
- const result = this.#fullTypes.get(name);
- assertArgument(result, `unknown type: ${JSON.stringify(name)}`, "name", name);
- return result;
- }
- /**
- * Return the encoded %%value%% for the %%type%%.
- */
- encodeData(type, value) {
- return this.getEncoder(type)(value);
- }
- /**
- * Returns the hash of %%value%% for the type of %%name%%.
- */
- hashStruct(name, value) {
- return keccak256(this.encodeData(name, value));
- }
- /**
- * Return the fulled encoded %%value%% for the [[types]].
- */
- encode(value) {
- return this.encodeData(this.primaryType, value);
- }
- /**
- * Return the hash of the fully encoded %%value%% for the [[types]].
- */
- hash(value) {
- return this.hashStruct(this.primaryType, value);
- }
- /**
- * @_ignore:
- */
- _visit(type, value, callback) {
- // Basic encoder type (address, bool, uint256, etc)
- {
- const encoder = getBaseEncoder(type);
- if (encoder) {
- return callback(type, value);
- }
- }
- // Array
- const array = splitArray(type).array;
- if (array) {
- assertArgument(array.count === -1 || array.count === value.length, `array length mismatch; expected length ${array.count}`, "value", value);
- return value.map((v) => this._visit(array.prefix, v, callback));
- }
- // Struct
- const fields = this.types[type];
- if (fields) {
- return fields.reduce((accum, { name, type }) => {
- accum[name] = this._visit(type, value[name], callback);
- return accum;
- }, {});
- }
- assertArgument(false, `unknown type: ${type}`, "type", type);
- }
- /**
- * Call %%calback%% for each value in %%value%%, passing the type and
- * component within %%value%%.
- *
- * This is useful for replacing addresses or other transformation that
- * may be desired on each component, based on its type.
- */
- visit(value, callback) {
- return this._visit(this.primaryType, value, callback);
- }
- /**
- * Create a new **TypedDataEncoder** for %%types%%.
- */
- static from(types) {
- return new TypedDataEncoder(types);
- }
- /**
- * Return the primary type for %%types%%.
- */
- static getPrimaryType(types) {
- return TypedDataEncoder.from(types).primaryType;
- }
- /**
- * Return the hashed struct for %%value%% using %%types%% and %%name%%.
- */
- static hashStruct(name, types, value) {
- return TypedDataEncoder.from(types).hashStruct(name, value);
- }
- /**
- * Return the domain hash for %%domain%%.
- */
- static hashDomain(domain) {
- const domainFields = [];
- for (const name in domain) {
- if (domain[name] == null) {
- continue;
- }
- const type = domainFieldTypes[name];
- assertArgument(type, `invalid typed-data domain key: ${JSON.stringify(name)}`, "domain", domain);
- domainFields.push({ name, type });
- }
- domainFields.sort((a, b) => {
- return domainFieldNames.indexOf(a.name) - domainFieldNames.indexOf(b.name);
- });
- return TypedDataEncoder.hashStruct("EIP712Domain", { EIP712Domain: domainFields }, domain);
- }
- /**
- * Return the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
- */
- static encode(domain, types, value) {
- return concat([
- "0x1901",
- TypedDataEncoder.hashDomain(domain),
- TypedDataEncoder.from(types).hash(value)
- ]);
- }
- /**
- * Return the hash of the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
- */
- static hash(domain, types, value) {
- return keccak256(TypedDataEncoder.encode(domain, types, value));
- }
- // Replaces all address types with ENS names with their looked up address
- /**
- * Resolves to the value from resolving all addresses in %%value%% for
- * %%types%% and the %%domain%%.
- */
- static async resolveNames(domain, types, value, resolveName) {
- // Make a copy to isolate it from the object passed in
- domain = Object.assign({}, domain);
- // Allow passing null to ignore value
- for (const key in domain) {
- if (domain[key] == null) {
- delete domain[key];
- }
- }
- // Look up all ENS names
- const ensCache = {};
- // Do we need to look up the domain's verifyingContract?
- if (domain.verifyingContract && !isHexString(domain.verifyingContract, 20)) {
- ensCache[domain.verifyingContract] = "0x";
- }
- // We are going to use the encoder to visit all the base values
- const encoder = TypedDataEncoder.from(types);
- // Get a list of all the addresses
- encoder.visit(value, (type, value) => {
- if (type === "address" && !isHexString(value, 20)) {
- ensCache[value] = "0x";
- }
- return value;
- });
- // Lookup each name
- for (const name in ensCache) {
- ensCache[name] = await resolveName(name);
- }
- // Replace the domain verifyingContract if needed
- if (domain.verifyingContract && ensCache[domain.verifyingContract]) {
- domain.verifyingContract = ensCache[domain.verifyingContract];
- }
- // Replace all ENS names with their address
- value = encoder.visit(value, (type, value) => {
- if (type === "address" && ensCache[value]) {
- return ensCache[value];
- }
- return value;
- });
- return { domain, value };
- }
- /**
- * Returns the JSON-encoded payload expected by nodes which implement
- * the JSON-RPC [[link-eip-712]] method.
- */
- static getPayload(domain, types, value) {
- // Validate the domain fields
- TypedDataEncoder.hashDomain(domain);
- // Derive the EIP712Domain Struct reference type
- const domainValues = {};
- const domainTypes = [];
- domainFieldNames.forEach((name) => {
- const value = domain[name];
- if (value == null) {
- return;
- }
- domainValues[name] = domainChecks[name](value);
- domainTypes.push({ name, type: domainFieldTypes[name] });
- });
- const encoder = TypedDataEncoder.from(types);
- // Get the normalized types
- types = encoder.types;
- const typesWithDomain = Object.assign({}, types);
- assertArgument(typesWithDomain.EIP712Domain == null, "types must not contain EIP712Domain type", "types.EIP712Domain", types);
- typesWithDomain.EIP712Domain = domainTypes;
- // Validate the data structures and types
- encoder.encode(value);
- return {
- types: typesWithDomain,
- domain: domainValues,
- primaryType: encoder.primaryType,
- message: encoder.visit(value, (type, value) => {
- // bytes
- if (type.match(/^bytes(\d*)/)) {
- return hexlify(getBytes(value));
- }
- // uint or int
- if (type.match(/^u?int/)) {
- return getBigInt(value).toString();
- }
- switch (type) {
- case "address":
- return value.toLowerCase();
- case "bool":
- return !!value;
- case "string":
- assertArgument(typeof (value) === "string", "invalid string", "value", value);
- return value;
- }
- assertArgument(false, "unsupported type", "type", type);
- })
- };
- }
- }
- /**
- * Compute the address used to sign the typed data for the %%signature%%.
- */
- function verifyTypedData(domain, types, value, signature) {
- return recoverAddress(TypedDataEncoder.hash(domain, types, value), signature);
- }
- /**
- * A fragment is a single item from an ABI, which may represent any of:
- *
- * - [Functions](FunctionFragment)
- * - [Events](EventFragment)
- * - [Constructors](ConstructorFragment)
- * - Custom [Errors](ErrorFragment)
- * - [Fallback or Receive](FallbackFragment) functions
- *
- * @_subsection api/abi/abi-coder:Fragments [about-fragments]
- */
- // [ "a", "b" ] => { "a": 1, "b": 1 }
- function setify(items) {
- const result = new Set();
- items.forEach((k) => result.add(k));
- return Object.freeze(result);
- }
- const _kwVisibDeploy = "external public payable override";
- const KwVisibDeploy = setify(_kwVisibDeploy.split(" "));
- // Visibility Keywords
- const _kwVisib = "constant external internal payable private public pure view override";
- const KwVisib = setify(_kwVisib.split(" "));
- const _kwTypes = "constructor error event fallback function receive struct";
- const KwTypes = setify(_kwTypes.split(" "));
- const _kwModifiers = "calldata memory storage payable indexed";
- const KwModifiers = setify(_kwModifiers.split(" "));
- const _kwOther = "tuple returns";
- // All Keywords
- const _keywords = [_kwTypes, _kwModifiers, _kwOther, _kwVisib].join(" ");
- const Keywords = setify(_keywords.split(" "));
- // Single character tokens
- const SimpleTokens = {
- "(": "OPEN_PAREN", ")": "CLOSE_PAREN",
- "[": "OPEN_BRACKET", "]": "CLOSE_BRACKET",
- ",": "COMMA", "@": "AT"
- };
- // Parser regexes to consume the next token
- const regexWhitespacePrefix = new RegExp("^(\\s*)");
- const regexNumberPrefix = new RegExp("^([0-9]+)");
- const regexIdPrefix = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)");
- // Parser regexs to check validity
- const regexId = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)$");
- const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))$");
- class TokenString {
- #offset;
- #tokens;
- get offset() { return this.#offset; }
- get length() { return this.#tokens.length - this.#offset; }
- constructor(tokens) {
- this.#offset = 0;
- this.#tokens = tokens.slice();
- }
- clone() { return new TokenString(this.#tokens); }
- reset() { this.#offset = 0; }
- #subTokenString(from = 0, to = 0) {
- return new TokenString(this.#tokens.slice(from, to).map((t) => {
- return Object.freeze(Object.assign({}, t, {
- match: (t.match - from),
- linkBack: (t.linkBack - from),
- linkNext: (t.linkNext - from),
- }));
- }));
- }
- // Pops and returns the value of the next token, if it is a keyword in allowed; throws if out of tokens
- popKeyword(allowed) {
- const top = this.peek();
- if (top.type !== "KEYWORD" || !allowed.has(top.text)) {
- throw new Error(`expected keyword ${top.text}`);
- }
- return this.pop().text;
- }
- // Pops and returns the value of the next token if it is `type`; throws if out of tokens
- popType(type) {
- if (this.peek().type !== type) {
- const top = this.peek();
- throw new Error(`expected ${type}; got ${top.type} ${JSON.stringify(top.text)}`);
- }
- return this.pop().text;
- }
- // Pops and returns a "(" TOKENS ")"
- popParen() {
- const top = this.peek();
- if (top.type !== "OPEN_PAREN") {
- throw new Error("bad start");
- }
- const result = this.#subTokenString(this.#offset + 1, top.match + 1);
- this.#offset = top.match + 1;
- return result;
- }
- // Pops and returns the items within "(" ITEM1 "," ITEM2 "," ... ")"
- popParams() {
- const top = this.peek();
- if (top.type !== "OPEN_PAREN") {
- throw new Error("bad start");
- }
- const result = [];
- while (this.#offset < top.match - 1) {
- const link = this.peek().linkNext;
- result.push(this.#subTokenString(this.#offset + 1, link));
- this.#offset = link;
- }
- this.#offset = top.match + 1;
- return result;
- }
- // Returns the top Token, throwing if out of tokens
- peek() {
- if (this.#offset >= this.#tokens.length) {
- throw new Error("out-of-bounds");
- }
- return this.#tokens[this.#offset];
- }
- // Returns the next value, if it is a keyword in `allowed`
- peekKeyword(allowed) {
- const top = this.peekType("KEYWORD");
- return (top != null && allowed.has(top)) ? top : null;
- }
- // Returns the value of the next token if it is `type`
- peekType(type) {
- if (this.length === 0) {
- return null;
- }
- const top = this.peek();
- return (top.type === type) ? top.text : null;
- }
- // Returns the next token; throws if out of tokens
- pop() {
- const result = this.peek();
- this.#offset++;
- return result;
- }
- toString() {
- const tokens = [];
- for (let i = this.#offset; i < this.#tokens.length; i++) {
- const token = this.#tokens[i];
- tokens.push(`${token.type}:${token.text}`);
- }
- return `<TokenString ${tokens.join(" ")}>`;
- }
- }
- function lex(text) {
- const tokens = [];
- const throwError = (message) => {
- const token = (offset < text.length) ? JSON.stringify(text[offset]) : "$EOI";
- throw new Error(`invalid token ${token} at ${offset}: ${message}`);
- };
- let brackets = [];
- let commas = [];
- let offset = 0;
- while (offset < text.length) {
- // Strip off any leading whitespace
- let cur = text.substring(offset);
- let match = cur.match(regexWhitespacePrefix);
- if (match) {
- offset += match[1].length;
- cur = text.substring(offset);
- }
- const token = { depth: brackets.length, linkBack: -1, linkNext: -1, match: -1, type: "", text: "", offset, value: -1 };
- tokens.push(token);
- let type = (SimpleTokens[cur[0]] || "");
- if (type) {
- token.type = type;
- token.text = cur[0];
- offset++;
- if (type === "OPEN_PAREN") {
- brackets.push(tokens.length - 1);
- commas.push(tokens.length - 1);
- }
- else if (type == "CLOSE_PAREN") {
- if (brackets.length === 0) {
- throwError("no matching open bracket");
- }
- token.match = brackets.pop();
- (tokens[token.match]).match = tokens.length - 1;
- token.depth--;
- token.linkBack = commas.pop();
- (tokens[token.linkBack]).linkNext = tokens.length - 1;
- }
- else if (type === "COMMA") {
- token.linkBack = commas.pop();
- (tokens[token.linkBack]).linkNext = tokens.length - 1;
- commas.push(tokens.length - 1);
- }
- else if (type === "OPEN_BRACKET") {
- token.type = "BRACKET";
- }
- else if (type === "CLOSE_BRACKET") {
- // Remove the CLOSE_BRACKET
- let suffix = tokens.pop().text;
- if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") {
- const value = tokens.pop().text;
- suffix = value + suffix;
- (tokens[tokens.length - 1]).value = getNumber(value);
- }
- if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") {
- throw new Error("missing opening bracket");
- }
- (tokens[tokens.length - 1]).text += suffix;
- }
- continue;
- }
- match = cur.match(regexIdPrefix);
- if (match) {
- token.text = match[1];
- offset += token.text.length;
- if (Keywords.has(token.text)) {
- token.type = "KEYWORD";
- continue;
- }
- if (token.text.match(regexType)) {
- token.type = "TYPE";
- continue;
- }
- token.type = "ID";
- continue;
- }
- match = cur.match(regexNumberPrefix);
- if (match) {
- token.text = match[1];
- token.type = "NUMBER";
- offset += token.text.length;
- continue;
- }
- throw new Error(`unexpected token ${JSON.stringify(cur[0])} at position ${offset}`);
- }
- return new TokenString(tokens.map((t) => Object.freeze(t)));
- }
- // Check only one of `allowed` is in `set`
- function allowSingle(set, allowed) {
- let included = [];
- for (const key in allowed.keys()) {
- if (set.has(key)) {
- included.push(key);
- }
- }
- if (included.length > 1) {
- throw new Error(`conflicting types: ${included.join(", ")}`);
- }
- }
- // Functions to process a Solidity Signature TokenString from left-to-right for...
- // ...the name with an optional type, returning the name
- function consumeName(type, tokens) {
- if (tokens.peekKeyword(KwTypes)) {
- const keyword = tokens.pop().text;
- if (keyword !== type) {
- throw new Error(`expected ${type}, got ${keyword}`);
- }
- }
- return tokens.popType("ID");
- }
- // ...all keywords matching allowed, returning the keywords
- function consumeKeywords(tokens, allowed) {
- const keywords = new Set();
- while (true) {
- const keyword = tokens.peekType("KEYWORD");
- if (keyword == null || (allowed && !allowed.has(keyword))) {
- break;
- }
- tokens.pop();
- if (keywords.has(keyword)) {
- throw new Error(`duplicate keywords: ${JSON.stringify(keyword)}`);
- }
- keywords.add(keyword);
- }
- return Object.freeze(keywords);
- }
- // ...all visibility keywords, returning the coalesced mutability
- function consumeMutability(tokens) {
- let modifiers = consumeKeywords(tokens, KwVisib);
- // Detect conflicting modifiers
- allowSingle(modifiers, setify("constant payable nonpayable".split(" ")));
- allowSingle(modifiers, setify("pure view payable nonpayable".split(" ")));
- // Process mutability states
- if (modifiers.has("view")) {
- return "view";
- }
- if (modifiers.has("pure")) {
- return "pure";
- }
- if (modifiers.has("payable")) {
- return "payable";
- }
- if (modifiers.has("nonpayable")) {
- return "nonpayable";
- }
- // Process legacy `constant` last
- if (modifiers.has("constant")) {
- return "view";
- }
- return "nonpayable";
- }
- // ...a parameter list, returning the ParamType list
- function consumeParams(tokens, allowIndexed) {
- return tokens.popParams().map((t) => ParamType.from(t, allowIndexed));
- }
- // ...a gas limit, returning a BigNumber or null if none
- function consumeGas(tokens) {
- if (tokens.peekType("AT")) {
- tokens.pop();
- if (tokens.peekType("NUMBER")) {
- return getBigInt(tokens.pop().text);
- }
- throw new Error("invalid gas");
- }
- return null;
- }
- function consumeEoi(tokens) {
- if (tokens.length) {
- throw new Error(`unexpected tokens at offset ${tokens.offset}: ${tokens.toString()}`);
- }
- }
- const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/);
- function verifyBasicType(type) {
- const match = type.match(regexType);
- assertArgument(match, "invalid type", "type", type);
- if (type === "uint") {
- return "uint256";
- }
- if (type === "int") {
- return "int256";
- }
- if (match[2]) {
- // bytesXX
- const length = parseInt(match[2]);
- assertArgument(length !== 0 && length <= 32, "invalid bytes length", "type", type);
- }
- else if (match[3]) {
- // intXX or uintXX
- const size = parseInt(match[3]);
- assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid numeric width", "type", type);
- }
- return type;
- }
- // Make the Fragment constructors effectively private
- const _guard$2 = {};
- const internal$1 = Symbol.for("_ethers_internal");
- const ParamTypeInternal = "_ParamTypeInternal";
- const ErrorFragmentInternal = "_ErrorInternal";
- const EventFragmentInternal = "_EventInternal";
- const ConstructorFragmentInternal = "_ConstructorInternal";
- const FallbackFragmentInternal = "_FallbackInternal";
- const FunctionFragmentInternal = "_FunctionInternal";
- const StructFragmentInternal = "_StructInternal";
- /**
- * Each input and output of a [[Fragment]] is an Array of **ParamType**.
- */
- class ParamType {
- /**
- * The local name of the parameter (or ``""`` if unbound)
- */
- name;
- /**
- * The fully qualified type (e.g. ``"address"``, ``"tuple(address)"``,
- * ``"uint256[3][]"``)
- */
- type;
- /**
- * The base type (e.g. ``"address"``, ``"tuple"``, ``"array"``)
- */
- baseType;
- /**
- * True if the parameters is indexed.
- *
- * For non-indexable types this is ``null``.
- */
- indexed;
- /**
- * The components for the tuple.
- *
- * For non-tuple types this is ``null``.
- */
- components;
- /**
- * The array length, or ``-1`` for dynamic-lengthed arrays.
- *
- * For non-array types this is ``null``.
- */
- arrayLength;
- /**
- * The type of each child in the array.
- *
- * For non-array types this is ``null``.
- */
- arrayChildren;
- /**
- * @private
- */
- constructor(guard, name, type, baseType, indexed, components, arrayLength, arrayChildren) {
- assertPrivate(guard, _guard$2, "ParamType");
- Object.defineProperty(this, internal$1, { value: ParamTypeInternal });
- if (components) {
- components = Object.freeze(components.slice());
- }
- if (baseType === "array") {
- if (arrayLength == null || arrayChildren == null) {
- throw new Error("");
- }
- }
- else if (arrayLength != null || arrayChildren != null) {
- throw new Error("");
- }
- if (baseType === "tuple") {
- if (components == null) {
- throw new Error("");
- }
- }
- else if (components != null) {
- throw new Error("");
- }
- defineProperties(this, {
- name, type, baseType, indexed, components, arrayLength, arrayChildren
- });
- }
- /**
- * Return a string representation of this type.
- *
- * For example,
- *
- * ``sighash" => "(uint256,address)"``
- *
- * ``"minimal" => "tuple(uint256,address) indexed"``
- *
- * ``"full" => "tuple(uint256 foo, address bar) indexed baz"``
- */
- format(format) {
- if (format == null) {
- format = "sighash";
- }
- if (format === "json") {
- const name = this.name || "";
- if (this.isArray()) {
- const result = JSON.parse(this.arrayChildren.format("json"));
- result.name = name;
- result.type += `[${(this.arrayLength < 0 ? "" : String(this.arrayLength))}]`;
- return JSON.stringify(result);
- }
- const result = {
- type: ((this.baseType === "tuple") ? "tuple" : this.type),
- name
- };
- if (typeof (this.indexed) === "boolean") {
- result.indexed = this.indexed;
- }
- if (this.isTuple()) {
- result.components = this.components.map((c) => JSON.parse(c.format(format)));
- }
- return JSON.stringify(result);
- }
- let result = "";
- // Array
- if (this.isArray()) {
- result += this.arrayChildren.format(format);
- result += `[${(this.arrayLength < 0 ? "" : String(this.arrayLength))}]`;
- }
- else {
- if (this.isTuple()) {
- result += "(" + this.components.map((comp) => comp.format(format)).join((format === "full") ? ", " : ",") + ")";
- }
- else {
- result += this.type;
- }
- }
- if (format !== "sighash") {
- if (this.indexed === true) {
- result += " indexed";
- }
- if (format === "full" && this.name) {
- result += " " + this.name;
- }
- }
- return result;
- }
- /**
- * Returns true if %%this%% is an Array type.
- *
- * This provides a type gaurd ensuring that [[arrayChildren]]
- * and [[arrayLength]] are non-null.
- */
- isArray() {
- return (this.baseType === "array");
- }
- /**
- * Returns true if %%this%% is a Tuple type.
- *
- * This provides a type gaurd ensuring that [[components]]
- * is non-null.
- */
- isTuple() {
- return (this.baseType === "tuple");
- }
- /**
- * Returns true if %%this%% is an Indexable type.
- *
- * This provides a type gaurd ensuring that [[indexed]]
- * is non-null.
- */
- isIndexable() {
- return (this.indexed != null);
- }
- /**
- * Walks the **ParamType** with %%value%%, calling %%process%%
- * on each type, destructing the %%value%% recursively.
- */
- walk(value, process) {
- if (this.isArray()) {
- if (!Array.isArray(value)) {
- throw new Error("invalid array value");
- }
- if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
- throw new Error("array is wrong length");
- }
- const _this = this;
- return value.map((v) => (_this.arrayChildren.walk(v, process)));
- }
- if (this.isTuple()) {
- if (!Array.isArray(value)) {
- throw new Error("invalid tuple value");
- }
- if (value.length !== this.components.length) {
- throw new Error("array is wrong length");
- }
- const _this = this;
- return value.map((v, i) => (_this.components[i].walk(v, process)));
- }
- return process(this.type, value);
- }
- #walkAsync(promises, value, process, setValue) {
- if (this.isArray()) {
- if (!Array.isArray(value)) {
- throw new Error("invalid array value");
- }
- if (this.arrayLength !== -1 && value.length !== this.arrayLength) {
- throw new Error("array is wrong length");
- }
- const childType = this.arrayChildren;
- const result = value.slice();
- result.forEach((value, index) => {
- childType.#walkAsync(promises, value, process, (value) => {
- result[index] = value;
- });
- });
- setValue(result);
- return;
- }
- if (this.isTuple()) {
- const components = this.components;
- // Convert the object into an array
- let result;
- if (Array.isArray(value)) {
- result = value.slice();
- }
- else {
- if (value == null || typeof (value) !== "object") {
- throw new Error("invalid tuple value");
- }
- result = components.map((param) => {
- if (!param.name) {
- throw new Error("cannot use object value with unnamed components");
- }
- if (!(param.name in value)) {
- throw new Error(`missing value for component ${param.name}`);
- }
- return value[param.name];
- });
- }
- if (result.length !== this.components.length) {
- throw new Error("array is wrong length");
- }
- result.forEach((value, index) => {
- components[index].#walkAsync(promises, value, process, (value) => {
- result[index] = value;
- });
- });
- setValue(result);
- return;
- }
- const result = process(this.type, value);
- if (result.then) {
- promises.push((async function () { setValue(await result); })());
- }
- else {
- setValue(result);
- }
- }
- /**
- * Walks the **ParamType** with %%value%%, asynchronously calling
- * %%process%% on each type, destructing the %%value%% recursively.
- *
- * This can be used to resolve ENS names by walking and resolving each
- * ``"address"`` type.
- */
- async walkAsync(value, process) {
- const promises = [];
- const result = [value];
- this.#walkAsync(promises, value, process, (value) => {
- result[0] = value;
- });
- if (promises.length) {
- await Promise.all(promises);
- }
- return result[0];
- }
- /**
- * Creates a new **ParamType** for %%obj%%.
- *
- * If %%allowIndexed%% then the ``indexed`` keyword is permitted,
- * otherwise the ``indexed`` keyword will throw an error.
- */
- static from(obj, allowIndexed) {
- if (ParamType.isParamType(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- try {
- return ParamType.from(lex(obj), allowIndexed);
- }
- catch (error) {
- assertArgument(false, "invalid param type", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- let type = "", baseType = "";
- let comps = null;
- if (consumeKeywords(obj, setify(["tuple"])).has("tuple") || obj.peekType("OPEN_PAREN")) {
- // Tuple
- baseType = "tuple";
- comps = obj.popParams().map((t) => ParamType.from(t));
- type = `tuple(${comps.map((c) => c.format()).join(",")})`;
- }
- else {
- // Normal
- type = verifyBasicType(obj.popType("TYPE"));
- baseType = type;
- }
- // Check for Array
- let arrayChildren = null;
- let arrayLength = null;
- while (obj.length && obj.peekType("BRACKET")) {
- const bracket = obj.pop(); //arrays[i];
- arrayChildren = new ParamType(_guard$2, "", type, baseType, null, comps, arrayLength, arrayChildren);
- arrayLength = bracket.value;
- type += bracket.text;
- baseType = "array";
- comps = null;
- }
- let indexed = null;
- const keywords = consumeKeywords(obj, KwModifiers);
- if (keywords.has("indexed")) {
- if (!allowIndexed) {
- throw new Error("");
- }
- indexed = true;
- }
- const name = (obj.peekType("ID") ? obj.pop().text : "");
- if (obj.length) {
- throw new Error("leftover tokens");
- }
- return new ParamType(_guard$2, name, type, baseType, indexed, comps, arrayLength, arrayChildren);
- }
- const name = obj.name;
- assertArgument(!name || (typeof (name) === "string" && name.match(regexId)), "invalid name", "obj.name", name);
- let indexed = obj.indexed;
- if (indexed != null) {
- assertArgument(allowIndexed, "parameter cannot be indexed", "obj.indexed", obj.indexed);
- indexed = !!indexed;
- }
- let type = obj.type;
- let arrayMatch = type.match(regexArrayType);
- if (arrayMatch) {
- const arrayLength = parseInt(arrayMatch[2] || "-1");
- const arrayChildren = ParamType.from({
- type: arrayMatch[1],
- components: obj.components
- });
- return new ParamType(_guard$2, name || "", type, "array", indexed, null, arrayLength, arrayChildren);
- }
- if (type === "tuple" || type.startsWith("tuple(" /* fix: ) */) || type.startsWith("(" /* fix: ) */)) {
- const comps = (obj.components != null) ? obj.components.map((c) => ParamType.from(c)) : null;
- const tuple = new ParamType(_guard$2, name || "", type, "tuple", indexed, comps, null, null);
- // @TODO: use lexer to validate and normalize type
- return tuple;
- }
- type = verifyBasicType(obj.type);
- return new ParamType(_guard$2, name || "", type, type, indexed, null, null, null);
- }
- /**
- * Returns true if %%value%% is a **ParamType**.
- */
- static isParamType(value) {
- return (value && value[internal$1] === ParamTypeInternal);
- }
- }
- /**
- * An abstract class to represent An individual fragment from a parse ABI.
- */
- class Fragment {
- /**
- * The type of the fragment.
- */
- type;
- /**
- * The inputs for the fragment.
- */
- inputs;
- /**
- * @private
- */
- constructor(guard, type, inputs) {
- assertPrivate(guard, _guard$2, "Fragment");
- inputs = Object.freeze(inputs.slice());
- defineProperties(this, { type, inputs });
- }
- /**
- * Creates a new **Fragment** for %%obj%%, wich can be any supported
- * ABI frgament type.
- */
- static from(obj) {
- if (typeof (obj) === "string") {
- // Try parsing JSON...
- try {
- Fragment.from(JSON.parse(obj));
- }
- catch (e) { }
- // ...otherwise, use the human-readable lexer
- return Fragment.from(lex(obj));
- }
- if (obj instanceof TokenString) {
- // Human-readable ABI (already lexed)
- const type = obj.peekKeyword(KwTypes);
- switch (type) {
- case "constructor": return ConstructorFragment.from(obj);
- case "error": return ErrorFragment.from(obj);
- case "event": return EventFragment.from(obj);
- case "fallback":
- case "receive":
- return FallbackFragment.from(obj);
- case "function": return FunctionFragment.from(obj);
- case "struct": return StructFragment.from(obj);
- }
- }
- else if (typeof (obj) === "object") {
- // JSON ABI
- switch (obj.type) {
- case "constructor": return ConstructorFragment.from(obj);
- case "error": return ErrorFragment.from(obj);
- case "event": return EventFragment.from(obj);
- case "fallback":
- case "receive":
- return FallbackFragment.from(obj);
- case "function": return FunctionFragment.from(obj);
- case "struct": return StructFragment.from(obj);
- }
- assert(false, `unsupported type: ${obj.type}`, "UNSUPPORTED_OPERATION", {
- operation: "Fragment.from"
- });
- }
- assertArgument(false, "unsupported frgament object", "obj", obj);
- }
- /**
- * Returns true if %%value%% is a [[ConstructorFragment]].
- */
- static isConstructor(value) {
- return ConstructorFragment.isFragment(value);
- }
- /**
- * Returns true if %%value%% is an [[ErrorFragment]].
- */
- static isError(value) {
- return ErrorFragment.isFragment(value);
- }
- /**
- * Returns true if %%value%% is an [[EventFragment]].
- */
- static isEvent(value) {
- return EventFragment.isFragment(value);
- }
- /**
- * Returns true if %%value%% is a [[FunctionFragment]].
- */
- static isFunction(value) {
- return FunctionFragment.isFragment(value);
- }
- /**
- * Returns true if %%value%% is a [[StructFragment]].
- */
- static isStruct(value) {
- return StructFragment.isFragment(value);
- }
- }
- /**
- * An abstract class to represent An individual fragment
- * which has a name from a parse ABI.
- */
- class NamedFragment extends Fragment {
- /**
- * The name of the fragment.
- */
- name;
- /**
- * @private
- */
- constructor(guard, type, name, inputs) {
- super(guard, type, inputs);
- assertArgument(typeof (name) === "string" && name.match(regexId), "invalid identifier", "name", name);
- inputs = Object.freeze(inputs.slice());
- defineProperties(this, { name });
- }
- }
- function joinParams(format, params) {
- return "(" + params.map((p) => p.format(format)).join((format === "full") ? ", " : ",") + ")";
- }
- /**
- * A Fragment which represents a //Custom Error//.
- */
- class ErrorFragment extends NamedFragment {
- /**
- * @private
- */
- constructor(guard, name, inputs) {
- super(guard, "error", name, inputs);
- Object.defineProperty(this, internal$1, { value: ErrorFragmentInternal });
- }
- /**
- * The Custom Error selector.
- */
- get selector() {
- return id(this.format("sighash")).substring(0, 10);
- }
- /**
- * Returns a string representation of this fragment as %%format%%.
- */
- format(format) {
- if (format == null) {
- format = "sighash";
- }
- if (format === "json") {
- return JSON.stringify({
- type: "error",
- name: this.name,
- inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
- });
- }
- const result = [];
- if (format !== "sighash") {
- result.push("error");
- }
- result.push(this.name + joinParams(format, this.inputs));
- return result.join(" ");
- }
- /**
- * Returns a new **ErrorFragment** for %%obj%%.
- */
- static from(obj) {
- if (ErrorFragment.isFragment(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- return ErrorFragment.from(lex(obj));
- }
- else if (obj instanceof TokenString) {
- const name = consumeName("error", obj);
- const inputs = consumeParams(obj);
- consumeEoi(obj);
- return new ErrorFragment(_guard$2, name, inputs);
- }
- return new ErrorFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
- }
- /**
- * Returns ``true`` and provides a type guard if %%value%% is an
- * **ErrorFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === ErrorFragmentInternal);
- }
- }
- /**
- * A Fragment which represents an Event.
- */
- class EventFragment extends NamedFragment {
- /**
- * Whether this event is anonymous.
- */
- anonymous;
- /**
- * @private
- */
- constructor(guard, name, inputs, anonymous) {
- super(guard, "event", name, inputs);
- Object.defineProperty(this, internal$1, { value: EventFragmentInternal });
- defineProperties(this, { anonymous });
- }
- /**
- * The Event topic hash.
- */
- get topicHash() {
- return id(this.format("sighash"));
- }
- /**
- * Returns a string representation of this event as %%format%%.
- */
- format(format) {
- if (format == null) {
- format = "sighash";
- }
- if (format === "json") {
- return JSON.stringify({
- type: "event",
- anonymous: this.anonymous,
- name: this.name,
- inputs: this.inputs.map((i) => JSON.parse(i.format(format)))
- });
- }
- const result = [];
- if (format !== "sighash") {
- result.push("event");
- }
- result.push(this.name + joinParams(format, this.inputs));
- if (format !== "sighash" && this.anonymous) {
- result.push("anonymous");
- }
- return result.join(" ");
- }
- /**
- * Return the topic hash for an event with %%name%% and %%params%%.
- */
- static getTopicHash(name, params) {
- params = (params || []).map((p) => ParamType.from(p));
- const fragment = new EventFragment(_guard$2, name, params, false);
- return fragment.topicHash;
- }
- /**
- * Returns a new **EventFragment** for %%obj%%.
- */
- static from(obj) {
- if (EventFragment.isFragment(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- try {
- return EventFragment.from(lex(obj));
- }
- catch (error) {
- assertArgument(false, "invalid event fragment", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- const name = consumeName("event", obj);
- const inputs = consumeParams(obj, true);
- const anonymous = !!consumeKeywords(obj, setify(["anonymous"])).has("anonymous");
- consumeEoi(obj);
- return new EventFragment(_guard$2, name, inputs, anonymous);
- }
- return new EventFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map((p) => ParamType.from(p, true)) : [], !!obj.anonymous);
- }
- /**
- * Returns ``true`` and provides a type guard if %%value%% is an
- * **EventFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === EventFragmentInternal);
- }
- }
- /**
- * A Fragment which represents a constructor.
- */
- class ConstructorFragment extends Fragment {
- /**
- * Whether the constructor can receive an endowment.
- */
- payable;
- /**
- * The recommended gas limit for deployment or ``null``.
- */
- gas;
- /**
- * @private
- */
- constructor(guard, type, inputs, payable, gas) {
- super(guard, type, inputs);
- Object.defineProperty(this, internal$1, { value: ConstructorFragmentInternal });
- defineProperties(this, { payable, gas });
- }
- /**
- * Returns a string representation of this constructor as %%format%%.
- */
- format(format) {
- assert(format != null && format !== "sighash", "cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", { operation: "format(sighash)" });
- if (format === "json") {
- return JSON.stringify({
- type: "constructor",
- stateMutability: (this.payable ? "payable" : "undefined"),
- payable: this.payable,
- gas: ((this.gas != null) ? this.gas : undefined),
- inputs: this.inputs.map((i) => JSON.parse(i.format(format)))
- });
- }
- const result = [`constructor${joinParams(format, this.inputs)}`];
- if (this.payable) {
- result.push("payable");
- }
- if (this.gas != null) {
- result.push(`@${this.gas.toString()}`);
- }
- return result.join(" ");
- }
- /**
- * Returns a new **ConstructorFragment** for %%obj%%.
- */
- static from(obj) {
- if (ConstructorFragment.isFragment(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- try {
- return ConstructorFragment.from(lex(obj));
- }
- catch (error) {
- assertArgument(false, "invalid constuctor fragment", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- consumeKeywords(obj, setify(["constructor"]));
- const inputs = consumeParams(obj);
- const payable = !!consumeKeywords(obj, KwVisibDeploy).has("payable");
- const gas = consumeGas(obj);
- consumeEoi(obj);
- return new ConstructorFragment(_guard$2, "constructor", inputs, payable, gas);
- }
- return new ConstructorFragment(_guard$2, "constructor", obj.inputs ? obj.inputs.map(ParamType.from) : [], !!obj.payable, (obj.gas != null) ? obj.gas : null);
- }
- /**
- * Returns ``true`` and provides a type guard if %%value%% is a
- * **ConstructorFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === ConstructorFragmentInternal);
- }
- }
- /**
- * A Fragment which represents a method.
- */
- class FallbackFragment extends Fragment {
- /**
- * If the function can be sent value during invocation.
- */
- payable;
- constructor(guard, inputs, payable) {
- super(guard, "fallback", inputs);
- Object.defineProperty(this, internal$1, { value: FallbackFragmentInternal });
- defineProperties(this, { payable });
- }
- /**
- * Returns a string representation of this fallback as %%format%%.
- */
- format(format) {
- const type = ((this.inputs.length === 0) ? "receive" : "fallback");
- if (format === "json") {
- const stateMutability = (this.payable ? "payable" : "nonpayable");
- return JSON.stringify({ type, stateMutability });
- }
- return `${type}()${this.payable ? " payable" : ""}`;
- }
- /**
- * Returns a new **FallbackFragment** for %%obj%%.
- */
- static from(obj) {
- if (FallbackFragment.isFragment(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- try {
- return FallbackFragment.from(lex(obj));
- }
- catch (error) {
- assertArgument(false, "invalid fallback fragment", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- const errorObj = obj.toString();
- const topIsValid = obj.peekKeyword(setify(["fallback", "receive"]));
- assertArgument(topIsValid, "type must be fallback or receive", "obj", errorObj);
- const type = obj.popKeyword(setify(["fallback", "receive"]));
- // receive()
- if (type === "receive") {
- const inputs = consumeParams(obj);
- assertArgument(inputs.length === 0, `receive cannot have arguments`, "obj.inputs", inputs);
- consumeKeywords(obj, setify(["payable"]));
- consumeEoi(obj);
- return new FallbackFragment(_guard$2, [], true);
- }
- // fallback() [payable]
- // fallback(bytes) [payable] returns (bytes)
- let inputs = consumeParams(obj);
- if (inputs.length) {
- assertArgument(inputs.length === 1 && inputs[0].type === "bytes", "invalid fallback inputs", "obj.inputs", inputs.map((i) => i.format("minimal")).join(", "));
- }
- else {
- inputs = [ParamType.from("bytes")];
- }
- const mutability = consumeMutability(obj);
- assertArgument(mutability === "nonpayable" || mutability === "payable", "fallback cannot be constants", "obj.stateMutability", mutability);
- if (consumeKeywords(obj, setify(["returns"])).has("returns")) {
- const outputs = consumeParams(obj);
- assertArgument(outputs.length === 1 && outputs[0].type === "bytes", "invalid fallback outputs", "obj.outputs", outputs.map((i) => i.format("minimal")).join(", "));
- }
- consumeEoi(obj);
- return new FallbackFragment(_guard$2, inputs, mutability === "payable");
- }
- if (obj.type === "receive") {
- return new FallbackFragment(_guard$2, [], true);
- }
- if (obj.type === "fallback") {
- const inputs = [ParamType.from("bytes")];
- const payable = (obj.stateMutability === "payable");
- return new FallbackFragment(_guard$2, inputs, payable);
- }
- assertArgument(false, "invalid fallback description", "obj", obj);
- }
- /**
- * Returns ``true`` and provides a type guard if %%value%% is a
- * **FallbackFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === FallbackFragmentInternal);
- }
- }
- /**
- * A Fragment which represents a method.
- */
- class FunctionFragment extends NamedFragment {
- /**
- * If the function is constant (e.g. ``pure`` or ``view`` functions).
- */
- constant;
- /**
- * The returned types for the result of calling this function.
- */
- outputs;
- /**
- * The state mutability (e.g. ``payable``, ``nonpayable``, ``view``
- * or ``pure``)
- */
- stateMutability;
- /**
- * If the function can be sent value during invocation.
- */
- payable;
- /**
- * The recommended gas limit to send when calling this function.
- */
- gas;
- /**
- * @private
- */
- constructor(guard, name, stateMutability, inputs, outputs, gas) {
- super(guard, "function", name, inputs);
- Object.defineProperty(this, internal$1, { value: FunctionFragmentInternal });
- outputs = Object.freeze(outputs.slice());
- const constant = (stateMutability === "view" || stateMutability === "pure");
- const payable = (stateMutability === "payable");
- defineProperties(this, { constant, gas, outputs, payable, stateMutability });
- }
- /**
- * The Function selector.
- */
- get selector() {
- return id(this.format("sighash")).substring(0, 10);
- }
- /**
- * Returns a string representation of this function as %%format%%.
- */
- format(format) {
- if (format == null) {
- format = "sighash";
- }
- if (format === "json") {
- return JSON.stringify({
- type: "function",
- name: this.name,
- constant: this.constant,
- stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined),
- payable: this.payable,
- gas: ((this.gas != null) ? this.gas : undefined),
- inputs: this.inputs.map((i) => JSON.parse(i.format(format))),
- outputs: this.outputs.map((o) => JSON.parse(o.format(format))),
- });
- }
- const result = [];
- if (format !== "sighash") {
- result.push("function");
- }
- result.push(this.name + joinParams(format, this.inputs));
- if (format !== "sighash") {
- if (this.stateMutability !== "nonpayable") {
- result.push(this.stateMutability);
- }
- if (this.outputs && this.outputs.length) {
- result.push("returns");
- result.push(joinParams(format, this.outputs));
- }
- if (this.gas != null) {
- result.push(`@${this.gas.toString()}`);
- }
- }
- return result.join(" ");
- }
- /**
- * Return the selector for a function with %%name%% and %%params%%.
- */
- static getSelector(name, params) {
- params = (params || []).map((p) => ParamType.from(p));
- const fragment = new FunctionFragment(_guard$2, name, "view", params, [], null);
- return fragment.selector;
- }
- /**
- * Returns a new **FunctionFragment** for %%obj%%.
- */
- static from(obj) {
- if (FunctionFragment.isFragment(obj)) {
- return obj;
- }
- if (typeof (obj) === "string") {
- try {
- return FunctionFragment.from(lex(obj));
- }
- catch (error) {
- assertArgument(false, "invalid function fragment", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- const name = consumeName("function", obj);
- const inputs = consumeParams(obj);
- const mutability = consumeMutability(obj);
- let outputs = [];
- if (consumeKeywords(obj, setify(["returns"])).has("returns")) {
- outputs = consumeParams(obj);
- }
- const gas = consumeGas(obj);
- consumeEoi(obj);
- return new FunctionFragment(_guard$2, name, mutability, inputs, outputs, gas);
- }
- let stateMutability = obj.stateMutability;
- // Use legacy Solidity ABI logic if stateMutability is missing
- if (stateMutability == null) {
- stateMutability = "payable";
- if (typeof (obj.constant) === "boolean") {
- stateMutability = "view";
- if (!obj.constant) {
- stateMutability = "payable";
- if (typeof (obj.payable) === "boolean" && !obj.payable) {
- stateMutability = "nonpayable";
- }
- }
- }
- else if (typeof (obj.payable) === "boolean" && !obj.payable) {
- stateMutability = "nonpayable";
- }
- }
- // @TODO: verifyState for stateMutability (e.g. throw if
- // payable: false but stateMutability is "nonpayable")
- return new FunctionFragment(_guard$2, obj.name, stateMutability, obj.inputs ? obj.inputs.map(ParamType.from) : [], obj.outputs ? obj.outputs.map(ParamType.from) : [], (obj.gas != null) ? obj.gas : null);
- }
- /**
- * Returns ``true`` and provides a type guard if %%value%% is a
- * **FunctionFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === FunctionFragmentInternal);
- }
- }
- /**
- * A Fragment which represents a structure.
- */
- class StructFragment extends NamedFragment {
- /**
- * @private
- */
- constructor(guard, name, inputs) {
- super(guard, "struct", name, inputs);
- Object.defineProperty(this, internal$1, { value: StructFragmentInternal });
- }
- /**
- * Returns a string representation of this struct as %%format%%.
- */
- format() {
- throw new Error("@TODO");
- }
- /**
- * Returns a new **StructFragment** for %%obj%%.
- */
- static from(obj) {
- if (typeof (obj) === "string") {
- try {
- return StructFragment.from(lex(obj));
- }
- catch (error) {
- assertArgument(false, "invalid struct fragment", "obj", obj);
- }
- }
- else if (obj instanceof TokenString) {
- const name = consumeName("struct", obj);
- const inputs = consumeParams(obj);
- consumeEoi(obj);
- return new StructFragment(_guard$2, name, inputs);
- }
- return new StructFragment(_guard$2, obj.name, obj.inputs ? obj.inputs.map(ParamType.from) : []);
- }
- // @TODO: fix this return type
- /**
- * Returns ``true`` and provides a type guard if %%value%% is a
- * **StructFragment**.
- */
- static isFragment(value) {
- return (value && value[internal$1] === StructFragmentInternal);
- }
- }
- /**
- * When sending values to or receiving values from a [[Contract]], the
- * data is generally encoded using the [ABI standard](link-solc-abi).
- *
- * The AbiCoder provides a utility to encode values to ABI data and
- * decode values from ABI data.
- *
- * Most of the time, developers should favour the [[Contract]] class,
- * which further abstracts a lot of the finer details of ABI data.
- *
- * @_section api/abi/abi-coder:ABI Encoding
- */
- // See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
- // https://docs.soliditylang.org/en/v0.8.17/control-structures.html
- const PanicReasons$1 = new Map();
- PanicReasons$1.set(0x00, "GENERIC_PANIC");
- PanicReasons$1.set(0x01, "ASSERT_FALSE");
- PanicReasons$1.set(0x11, "OVERFLOW");
- PanicReasons$1.set(0x12, "DIVIDE_BY_ZERO");
- PanicReasons$1.set(0x21, "ENUM_RANGE_ERROR");
- PanicReasons$1.set(0x22, "BAD_STORAGE_DATA");
- PanicReasons$1.set(0x31, "STACK_UNDERFLOW");
- PanicReasons$1.set(0x32, "ARRAY_RANGE_ERROR");
- PanicReasons$1.set(0x41, "OUT_OF_MEMORY");
- PanicReasons$1.set(0x51, "UNINITIALIZED_FUNCTION_CALL");
- const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
- const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
- let defaultCoder = null;
- let defaultMaxInflation = 1024;
- function getBuiltinCallException(action, tx, data, abiCoder) {
- let message = "missing revert data";
- let reason = null;
- const invocation = null;
- let revert = null;
- if (data) {
- message = "execution reverted";
- const bytes = getBytes(data);
- data = hexlify(data);
- if (bytes.length === 0) {
- message += " (no data present; likely require(false) occurred";
- reason = "require(false)";
- }
- else if (bytes.length % 32 !== 4) {
- message += " (could not decode reason; invalid data length)";
- }
- else if (hexlify(bytes.slice(0, 4)) === "0x08c379a0") {
- // Error(string)
- try {
- reason = abiCoder.decode(["string"], bytes.slice(4))[0];
- revert = {
- signature: "Error(string)",
- name: "Error",
- args: [reason]
- };
- message += `: ${JSON.stringify(reason)}`;
- }
- catch (error) {
- message += " (could not decode reason; invalid string data)";
- }
- }
- else if (hexlify(bytes.slice(0, 4)) === "0x4e487b71") {
- // Panic(uint256)
- try {
- const code = Number(abiCoder.decode(["uint256"], bytes.slice(4))[0]);
- revert = {
- signature: "Panic(uint256)",
- name: "Panic",
- args: [code]
- };
- reason = `Panic due to ${PanicReasons$1.get(code) || "UNKNOWN"}(${code})`;
- message += `: ${reason}`;
- }
- catch (error) {
- message += " (could not decode panic code)";
- }
- }
- else {
- message += " (unknown custom error)";
- }
- }
- const transaction = {
- to: (tx.to ? getAddress(tx.to) : null),
- data: (tx.data || "0x")
- };
- if (tx.from) {
- transaction.from = getAddress(tx.from);
- }
- return makeError(message, "CALL_EXCEPTION", {
- action, data, reason, transaction, invocation, revert
- });
- }
- /**
- * The **AbiCoder** is a low-level class responsible for encoding JavaScript
- * values into binary data and decoding binary data into JavaScript values.
- */
- class AbiCoder {
- #getCoder(param) {
- if (param.isArray()) {
- return new ArrayCoder(this.#getCoder(param.arrayChildren), param.arrayLength, param.name);
- }
- if (param.isTuple()) {
- return new TupleCoder(param.components.map((c) => this.#getCoder(c)), param.name);
- }
- switch (param.baseType) {
- case "address":
- return new AddressCoder(param.name);
- case "bool":
- return new BooleanCoder(param.name);
- case "string":
- return new StringCoder(param.name);
- case "bytes":
- return new BytesCoder(param.name);
- case "":
- return new NullCoder(param.name);
- }
- // u?int[0-9]*
- let match = param.type.match(paramTypeNumber);
- if (match) {
- let size = parseInt(match[2] || "256");
- assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid " + match[1] + " bit length", "param", param);
- return new NumberCoder(size / 8, (match[1] === "int"), param.name);
- }
- // bytes[0-9]+
- match = param.type.match(paramTypeBytes);
- if (match) {
- let size = parseInt(match[1]);
- assertArgument(size !== 0 && size <= 32, "invalid bytes length", "param", param);
- return new FixedBytesCoder(size, param.name);
- }
- assertArgument(false, "invalid type", "type", param.type);
- }
- /**
- * Get the default values for the given %%types%%.
- *
- * For example, a ``uint`` is by default ``0`` and ``bool``
- * is by default ``false``.
- */
- getDefaultValue(types) {
- const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
- const coder = new TupleCoder(coders, "_");
- return coder.defaultValue();
- }
- /**
- * Encode the %%values%% as the %%types%% into ABI data.
- *
- * @returns DataHexstring
- */
- encode(types, values) {
- assertArgumentCount(values.length, types.length, "types/values length mismatch");
- const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
- const coder = (new TupleCoder(coders, "_"));
- const writer = new Writer();
- coder.encode(writer, values);
- return writer.data;
- }
- /**
- * Decode the ABI %%data%% as the %%types%% into values.
- *
- * If %%loose%% decoding is enabled, then strict padding is
- * not enforced. Some older versions of Solidity incorrectly
- * padded event data emitted from ``external`` functions.
- */
- decode(types, data, loose) {
- const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
- const coder = new TupleCoder(coders, "_");
- return coder.decode(new Reader(data, loose, defaultMaxInflation));
- }
- static _setDefaultMaxInflation(value) {
- assertArgument(typeof (value) === "number" && Number.isInteger(value), "invalid defaultMaxInflation factor", "value", value);
- defaultMaxInflation = value;
- }
- /**
- * Returns the shared singleton instance of a default [[AbiCoder]].
- *
- * On the first call, the instance is created internally.
- */
- static defaultAbiCoder() {
- if (defaultCoder == null) {
- defaultCoder = new AbiCoder();
- }
- return defaultCoder;
- }
- /**
- * Returns an ethers-compatible [[CallExceptionError]] Error for the given
- * result %%data%% for the [[CallExceptionAction]] %%action%% against
- * the Transaction %%tx%%.
- */
- static getBuiltinCallException(action, tx, data) {
- return getBuiltinCallException(action, tx, data, AbiCoder.defaultAbiCoder());
- }
- }
- /**
- * About bytes32 strings...
- *
- * @_docloc: api/utils:Bytes32 Strings
- */
- /**
- * Encodes %%text%% as a Bytes32 string.
- */
- function encodeBytes32String(text) {
- // Get the bytes
- const bytes = toUtf8Bytes(text);
- // Check we have room for null-termination
- if (bytes.length > 31) {
- throw new Error("bytes32 string must be less than 32 bytes");
- }
- // Zero-pad (implicitly null-terminates)
- return zeroPadBytes(bytes, 32);
- }
- /**
- * Encodes the Bytes32-encoded %%bytes%% into a string.
- */
- function decodeBytes32String(_bytes) {
- const data = getBytes(_bytes, "bytes");
- // Must be 32 bytes with a null-termination
- if (data.length !== 32) {
- throw new Error("invalid bytes32 - not 32 bytes long");
- }
- if (data[31] !== 0) {
- throw new Error("invalid bytes32 string - no null terminator");
- }
- // Find the null termination
- let length = 31;
- while (data[length - 1] === 0) {
- length--;
- }
- // Determine the string value
- return toUtf8String(data.slice(0, length));
- }
- /**
- * The Interface class is a low-level class that accepts an
- * ABI and provides all the necessary functionality to encode
- * and decode paramaters to and results from methods, events
- * and errors.
- *
- * It also provides several convenience methods to automatically
- * search and find matching transactions and events to parse them.
- *
- * @_subsection api/abi:Interfaces [interfaces]
- */
- /**
- * When using the [[Interface-parseLog]] to automatically match a Log to its event
- * for parsing, a **LogDescription** is returned.
- */
- class LogDescription {
- /**
- * The matching fragment for the ``topic0``.
- */
- fragment;
- /**
- * The name of the Event.
- */
- name;
- /**
- * The full Event signature.
- */
- signature;
- /**
- * The topic hash for the Event.
- */
- topic;
- /**
- * The arguments passed into the Event with ``emit``.
- */
- args;
- /**
- * @_ignore:
- */
- constructor(fragment, topic, args) {
- const name = fragment.name, signature = fragment.format();
- defineProperties(this, {
- fragment, name, signature, topic, args
- });
- }
- }
- /**
- * When using the [[Interface-parseTransaction]] to automatically match
- * a transaction data to its function for parsing,
- * a **TransactionDescription** is returned.
- */
- class TransactionDescription {
- /**
- * The matching fragment from the transaction ``data``.
- */
- fragment;
- /**
- * The name of the Function from the transaction ``data``.
- */
- name;
- /**
- * The arguments passed to the Function from the transaction ``data``.
- */
- args;
- /**
- * The full Function signature from the transaction ``data``.
- */
- signature;
- /**
- * The selector for the Function from the transaction ``data``.
- */
- selector;
- /**
- * The ``value`` (in wei) from the transaction.
- */
- value;
- /**
- * @_ignore:
- */
- constructor(fragment, selector, args, value) {
- const name = fragment.name, signature = fragment.format();
- defineProperties(this, {
- fragment, name, args, signature, selector, value
- });
- }
- }
- /**
- * When using the [[Interface-parseError]] to automatically match an
- * error for a call result for parsing, an **ErrorDescription** is returned.
- */
- class ErrorDescription {
- /**
- * The matching fragment.
- */
- fragment;
- /**
- * The name of the Error.
- */
- name;
- /**
- * The arguments passed to the Error with ``revert``.
- */
- args;
- /**
- * The full Error signature.
- */
- signature;
- /**
- * The selector for the Error.
- */
- selector;
- /**
- * @_ignore:
- */
- constructor(fragment, selector, args) {
- const name = fragment.name, signature = fragment.format();
- defineProperties(this, {
- fragment, name, args, signature, selector
- });
- }
- }
- /**
- * An **Indexed** is used as a value when a value that does not
- * fit within a topic (i.e. not a fixed-length, 32-byte type). It
- * is the ``keccak256`` of the value, and used for types such as
- * arrays, tuples, bytes and strings.
- */
- class Indexed {
- /**
- * The ``keccak256`` of the value logged.
- */
- hash;
- /**
- * @_ignore:
- */
- _isIndexed;
- /**
- * Returns ``true`` if %%value%% is an **Indexed**.
- *
- * This provides a Type Guard for property access.
- */
- static isIndexed(value) {
- return !!(value && value._isIndexed);
- }
- /**
- * @_ignore:
- */
- constructor(hash) {
- defineProperties(this, { hash, _isIndexed: true });
- }
- }
- // https://docs.soliditylang.org/en/v0.8.13/control-structures.html?highlight=panic#panic-via-assert-and-error-via-require
- const PanicReasons = {
- "0": "generic panic",
- "1": "assert(false)",
- "17": "arithmetic overflow",
- "18": "division or modulo by zero",
- "33": "enum overflow",
- "34": "invalid encoded storage byte array accessed",
- "49": "out-of-bounds array access; popping on an empty array",
- "50": "out-of-bounds access of an array or bytesN",
- "65": "out of memory",
- "81": "uninitialized function",
- };
- const BuiltinErrors = {
- "0x08c379a0": {
- signature: "Error(string)",
- name: "Error",
- inputs: ["string"],
- reason: (message) => {
- return `reverted with reason string ${JSON.stringify(message)}`;
- }
- },
- "0x4e487b71": {
- signature: "Panic(uint256)",
- name: "Panic",
- inputs: ["uint256"],
- reason: (code) => {
- let reason = "unknown panic code";
- if (code >= 0 && code <= 0xff && PanicReasons[code.toString()]) {
- reason = PanicReasons[code.toString()];
- }
- return `reverted with panic code 0x${code.toString(16)} (${reason})`;
- }
- }
- };
- /**
- * An Interface abstracts many of the low-level details for
- * encoding and decoding the data on the blockchain.
- *
- * An ABI provides information on how to encode data to send to
- * a Contract, how to decode the results and events and how to
- * interpret revert errors.
- *
- * The ABI can be specified by [any supported format](InterfaceAbi).
- */
- class Interface {
- /**
- * All the Contract ABI members (i.e. methods, events, errors, etc).
- */
- fragments;
- /**
- * The Contract constructor.
- */
- deploy;
- /**
- * The Fallback method, if any.
- */
- fallback;
- /**
- * If receiving ether is supported.
- */
- receive;
- #errors;
- #events;
- #functions;
- // #structs: Map<string, StructFragment>;
- #abiCoder;
- /**
- * Create a new Interface for the %%fragments%%.
- */
- constructor(fragments) {
- let abi = [];
- if (typeof (fragments) === "string") {
- abi = JSON.parse(fragments);
- }
- else {
- abi = fragments;
- }
- this.#functions = new Map();
- this.#errors = new Map();
- this.#events = new Map();
- // this.#structs = new Map();
- const frags = [];
- for (const a of abi) {
- try {
- frags.push(Fragment.from(a));
- }
- catch (error) {
- console.log(`[Warning] Invalid Fragment ${JSON.stringify(a)}:`, error.message);
- }
- }
- defineProperties(this, {
- fragments: Object.freeze(frags)
- });
- let fallback = null;
- let receive = false;
- this.#abiCoder = this.getAbiCoder();
- // Add all fragments by their signature
- this.fragments.forEach((fragment, index) => {
- let bucket;
- switch (fragment.type) {
- case "constructor":
- if (this.deploy) {
- console.log("duplicate definition - constructor");
- return;
- }
- //checkNames(fragment, "input", fragment.inputs);
- defineProperties(this, { deploy: fragment });
- return;
- case "fallback":
- if (fragment.inputs.length === 0) {
- receive = true;
- }
- else {
- assertArgument(!fallback || fragment.payable !== fallback.payable, "conflicting fallback fragments", `fragments[${index}]`, fragment);
- fallback = fragment;
- receive = fallback.payable;
- }
- return;
- case "function":
- //checkNames(fragment, "input", fragment.inputs);
- //checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
- bucket = this.#functions;
- break;
- case "event":
- //checkNames(fragment, "input", fragment.inputs);
- bucket = this.#events;
- break;
- case "error":
- bucket = this.#errors;
- break;
- default:
- return;
- }
- // Two identical entries; ignore it
- const signature = fragment.format();
- if (bucket.has(signature)) {
- return;
- }
- bucket.set(signature, fragment);
- });
- // If we do not have a constructor add a default
- if (!this.deploy) {
- defineProperties(this, {
- deploy: ConstructorFragment.from("constructor()")
- });
- }
- defineProperties(this, { fallback, receive });
- }
- /**
- * Returns the entire Human-Readable ABI, as an array of
- * signatures, optionally as %%minimal%% strings, which
- * removes parameter names and unneceesary spaces.
- */
- format(minimal) {
- const format = (minimal ? "minimal" : "full");
- const abi = this.fragments.map((f) => f.format(format));
- return abi;
- }
- /**
- * Return the JSON-encoded ABI. This is the format Solidiy
- * returns.
- */
- formatJson() {
- const abi = this.fragments.map((f) => f.format("json"));
- // We need to re-bundle the JSON fragments a bit
- return JSON.stringify(abi.map((j) => JSON.parse(j)));
- }
- /**
- * The ABI coder that will be used to encode and decode binary
- * data.
- */
- getAbiCoder() {
- return AbiCoder.defaultAbiCoder();
- }
- // Find a function definition by any means necessary (unless it is ambiguous)
- #getFunction(key, values, forceUnique) {
- // Selector
- if (isHexString(key)) {
- const selector = key.toLowerCase();
- for (const fragment of this.#functions.values()) {
- if (selector === fragment.selector) {
- return fragment;
- }
- }
- return null;
- }
- // It is a bare name, look up the function (will return null if ambiguous)
- if (key.indexOf("(") === -1) {
- const matching = [];
- for (const [name, fragment] of this.#functions) {
- if (name.split("(" /* fix:) */)[0] === key) {
- matching.push(fragment);
- }
- }
- if (values) {
- const lastValue = (values.length > 0) ? values[values.length - 1] : null;
- let valueLength = values.length;
- let allowOptions = true;
- if (Typed.isTyped(lastValue) && lastValue.type === "overrides") {
- allowOptions = false;
- valueLength--;
- }
- // Remove all matches that don't have a compatible length. The args
- // may contain an overrides, so the match may have n or n - 1 parameters
- for (let i = matching.length - 1; i >= 0; i--) {
- const inputs = matching[i].inputs.length;
- if (inputs !== valueLength && (!allowOptions || inputs !== valueLength - 1)) {
- matching.splice(i, 1);
- }
- }
- // Remove all matches that don't match the Typed signature
- for (let i = matching.length - 1; i >= 0; i--) {
- const inputs = matching[i].inputs;
- for (let j = 0; j < values.length; j++) {
- // Not a typed value
- if (!Typed.isTyped(values[j])) {
- continue;
- }
- // We are past the inputs
- if (j >= inputs.length) {
- if (values[j].type === "overrides") {
- continue;
- }
- matching.splice(i, 1);
- break;
- }
- // Make sure the value type matches the input type
- if (values[j].type !== inputs[j].baseType) {
- matching.splice(i, 1);
- break;
- }
- }
- }
- }
- // We found a single matching signature with an overrides, but the
- // last value is something that cannot possibly be an options
- if (matching.length === 1 && values && values.length !== matching[0].inputs.length) {
- const lastArg = values[values.length - 1];
- if (lastArg == null || Array.isArray(lastArg) || typeof (lastArg) !== "object") {
- matching.splice(0, 1);
- }
- }
- if (matching.length === 0) {
- return null;
- }
- if (matching.length > 1 && forceUnique) {
- const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
- assertArgument(false, `ambiguous function description (i.e. matches ${matchStr})`, "key", key);
- }
- return matching[0];
- }
- // Normalize the signature and lookup the function
- const result = this.#functions.get(FunctionFragment.from(key).format());
- if (result) {
- return result;
- }
- return null;
- }
- /**
- * Get the function name for %%key%%, which may be a function selector,
- * function name or function signature that belongs to the ABI.
- */
- getFunctionName(key) {
- const fragment = this.#getFunction(key, null, false);
- assertArgument(fragment, "no matching function", "key", key);
- return fragment.name;
- }
- /**
- * Returns true if %%key%% (a function selector, function name or
- * function signature) is present in the ABI.
- *
- * In the case of a function name, the name may be ambiguous, so
- * accessing the [[FunctionFragment]] may require refinement.
- */
- hasFunction(key) {
- return !!this.#getFunction(key, null, false);
- }
- /**
- * Get the [[FunctionFragment]] for %%key%%, which may be a function
- * selector, function name or function signature that belongs to the ABI.
- *
- * If %%values%% is provided, it will use the Typed API to handle
- * ambiguous cases where multiple functions match by name.
- *
- * If the %%key%% and %%values%% do not refine to a single function in
- * the ABI, this will throw.
- */
- getFunction(key, values) {
- return this.#getFunction(key, values || null, true);
- }
- /**
- * Iterate over all functions, calling %%callback%%, sorted by their name.
- */
- forEachFunction(callback) {
- const names = Array.from(this.#functions.keys());
- names.sort((a, b) => a.localeCompare(b));
- for (let i = 0; i < names.length; i++) {
- const name = names[i];
- callback((this.#functions.get(name)), i);
- }
- }
- // Find an event definition by any means necessary (unless it is ambiguous)
- #getEvent(key, values, forceUnique) {
- // EventTopic
- if (isHexString(key)) {
- const eventTopic = key.toLowerCase();
- for (const fragment of this.#events.values()) {
- if (eventTopic === fragment.topicHash) {
- return fragment;
- }
- }
- return null;
- }
- // It is a bare name, look up the function (will return null if ambiguous)
- if (key.indexOf("(") === -1) {
- const matching = [];
- for (const [name, fragment] of this.#events) {
- if (name.split("(" /* fix:) */)[0] === key) {
- matching.push(fragment);
- }
- }
- if (values) {
- // Remove all matches that don't have a compatible length.
- for (let i = matching.length - 1; i >= 0; i--) {
- if (matching[i].inputs.length < values.length) {
- matching.splice(i, 1);
- }
- }
- // Remove all matches that don't match the Typed signature
- for (let i = matching.length - 1; i >= 0; i--) {
- const inputs = matching[i].inputs;
- for (let j = 0; j < values.length; j++) {
- // Not a typed value
- if (!Typed.isTyped(values[j])) {
- continue;
- }
- // Make sure the value type matches the input type
- if (values[j].type !== inputs[j].baseType) {
- matching.splice(i, 1);
- break;
- }
- }
- }
- }
- if (matching.length === 0) {
- return null;
- }
- if (matching.length > 1 && forceUnique) {
- const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
- assertArgument(false, `ambiguous event description (i.e. matches ${matchStr})`, "key", key);
- }
- return matching[0];
- }
- // Normalize the signature and lookup the function
- const result = this.#events.get(EventFragment.from(key).format());
- if (result) {
- return result;
- }
- return null;
- }
- /**
- * Get the event name for %%key%%, which may be a topic hash,
- * event name or event signature that belongs to the ABI.
- */
- getEventName(key) {
- const fragment = this.#getEvent(key, null, false);
- assertArgument(fragment, "no matching event", "key", key);
- return fragment.name;
- }
- /**
- * Returns true if %%key%% (an event topic hash, event name or
- * event signature) is present in the ABI.
- *
- * In the case of an event name, the name may be ambiguous, so
- * accessing the [[EventFragment]] may require refinement.
- */
- hasEvent(key) {
- return !!this.#getEvent(key, null, false);
- }
- /**
- * Get the [[EventFragment]] for %%key%%, which may be a topic hash,
- * event name or event signature that belongs to the ABI.
- *
- * If %%values%% is provided, it will use the Typed API to handle
- * ambiguous cases where multiple events match by name.
- *
- * If the %%key%% and %%values%% do not refine to a single event in
- * the ABI, this will throw.
- */
- getEvent(key, values) {
- return this.#getEvent(key, values || null, true);
- }
- /**
- * Iterate over all events, calling %%callback%%, sorted by their name.
- */
- forEachEvent(callback) {
- const names = Array.from(this.#events.keys());
- names.sort((a, b) => a.localeCompare(b));
- for (let i = 0; i < names.length; i++) {
- const name = names[i];
- callback((this.#events.get(name)), i);
- }
- }
- /**
- * Get the [[ErrorFragment]] for %%key%%, which may be an error
- * selector, error name or error signature that belongs to the ABI.
- *
- * If %%values%% is provided, it will use the Typed API to handle
- * ambiguous cases where multiple errors match by name.
- *
- * If the %%key%% and %%values%% do not refine to a single error in
- * the ABI, this will throw.
- */
- getError(key, values) {
- if (isHexString(key)) {
- const selector = key.toLowerCase();
- if (BuiltinErrors[selector]) {
- return ErrorFragment.from(BuiltinErrors[selector].signature);
- }
- for (const fragment of this.#errors.values()) {
- if (selector === fragment.selector) {
- return fragment;
- }
- }
- return null;
- }
- // It is a bare name, look up the function (will return null if ambiguous)
- if (key.indexOf("(") === -1) {
- const matching = [];
- for (const [name, fragment] of this.#errors) {
- if (name.split("(" /* fix:) */)[0] === key) {
- matching.push(fragment);
- }
- }
- if (matching.length === 0) {
- if (key === "Error") {
- return ErrorFragment.from("error Error(string)");
- }
- if (key === "Panic") {
- return ErrorFragment.from("error Panic(uint256)");
- }
- return null;
- }
- else if (matching.length > 1) {
- const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
- assertArgument(false, `ambiguous error description (i.e. ${matchStr})`, "name", key);
- }
- return matching[0];
- }
- // Normalize the signature and lookup the function
- key = ErrorFragment.from(key).format();
- if (key === "Error(string)") {
- return ErrorFragment.from("error Error(string)");
- }
- if (key === "Panic(uint256)") {
- return ErrorFragment.from("error Panic(uint256)");
- }
- const result = this.#errors.get(key);
- if (result) {
- return result;
- }
- return null;
- }
- /**
- * Iterate over all errors, calling %%callback%%, sorted by their name.
- */
- forEachError(callback) {
- const names = Array.from(this.#errors.keys());
- names.sort((a, b) => a.localeCompare(b));
- for (let i = 0; i < names.length; i++) {
- const name = names[i];
- callback((this.#errors.get(name)), i);
- }
- }
- // Get the 4-byte selector used by Solidity to identify a function
- /*
- getSelector(fragment: ErrorFragment | FunctionFragment): string {
- if (typeof(fragment) === "string") {
- const matches: Array<Fragment> = [ ];
- try { matches.push(this.getFunction(fragment)); } catch (error) { }
- try { matches.push(this.getError(<string>fragment)); } catch (_) { }
- if (matches.length === 0) {
- logger.throwArgumentError("unknown fragment", "key", fragment);
- } else if (matches.length > 1) {
- logger.throwArgumentError("ambiguous fragment matches function and error", "key", fragment);
- }
- fragment = matches[0];
- }
- return dataSlice(id(fragment.format()), 0, 4);
- }
- */
- // Get the 32-byte topic hash used by Solidity to identify an event
- /*
- getEventTopic(fragment: EventFragment): string {
- //if (typeof(fragment) === "string") { fragment = this.getEvent(eventFragment); }
- return id(fragment.format());
- }
- */
- _decodeParams(params, data) {
- return this.#abiCoder.decode(params, data);
- }
- _encodeParams(params, values) {
- return this.#abiCoder.encode(params, values);
- }
- /**
- * Encodes a ``tx.data`` object for deploying the Contract with
- * the %%values%% as the constructor arguments.
- */
- encodeDeploy(values) {
- return this._encodeParams(this.deploy.inputs, values || []);
- }
- /**
- * Decodes the result %%data%% (e.g. from an ``eth_call``) for the
- * specified error (see [[getError]] for valid values for
- * %%key%%).
- *
- * Most developers should prefer the [[parseCallResult]] method instead,
- * which will automatically detect a ``CALL_EXCEPTION`` and throw the
- * corresponding error.
- */
- decodeErrorResult(fragment, data) {
- if (typeof (fragment) === "string") {
- const f = this.getError(fragment);
- assertArgument(f, "unknown error", "fragment", fragment);
- fragment = f;
- }
- assertArgument(dataSlice(data, 0, 4) === fragment.selector, `data signature does not match error ${fragment.name}.`, "data", data);
- return this._decodeParams(fragment.inputs, dataSlice(data, 4));
- }
- /**
- * Encodes the transaction revert data for a call result that
- * reverted from the the Contract with the sepcified %%error%%
- * (see [[getError]] for valid values for %%fragment%%) with the %%values%%.
- *
- * This is generally not used by most developers, unless trying to mock
- * a result from a Contract.
- */
- encodeErrorResult(fragment, values) {
- if (typeof (fragment) === "string") {
- const f = this.getError(fragment);
- assertArgument(f, "unknown error", "fragment", fragment);
- fragment = f;
- }
- return concat([
- fragment.selector,
- this._encodeParams(fragment.inputs, values || [])
- ]);
- }
- /**
- * Decodes the %%data%% from a transaction ``tx.data`` for
- * the function specified (see [[getFunction]] for valid values
- * for %%fragment%%).
- *
- * Most developers should prefer the [[parseTransaction]] method
- * instead, which will automatically detect the fragment.
- */
- decodeFunctionData(fragment, data) {
- if (typeof (fragment) === "string") {
- const f = this.getFunction(fragment);
- assertArgument(f, "unknown function", "fragment", fragment);
- fragment = f;
- }
- assertArgument(dataSlice(data, 0, 4) === fragment.selector, `data signature does not match function ${fragment.name}.`, "data", data);
- return this._decodeParams(fragment.inputs, dataSlice(data, 4));
- }
- /**
- * Encodes the ``tx.data`` for a transaction that calls the function
- * specified (see [[getFunction]] for valid values for %%fragment%%) with
- * the %%values%%.
- */
- encodeFunctionData(fragment, values) {
- if (typeof (fragment) === "string") {
- const f = this.getFunction(fragment);
- assertArgument(f, "unknown function", "fragment", fragment);
- fragment = f;
- }
- return concat([
- fragment.selector,
- this._encodeParams(fragment.inputs, values || [])
- ]);
- }
- /**
- * Decodes the result %%data%% (e.g. from an ``eth_call``) for the
- * specified function (see [[getFunction]] for valid values for
- * %%key%%).
- *
- * Most developers should prefer the [[parseCallResult]] method instead,
- * which will automatically detect a ``CALL_EXCEPTION`` and throw the
- * corresponding error.
- */
- decodeFunctionResult(fragment, data) {
- if (typeof (fragment) === "string") {
- const f = this.getFunction(fragment);
- assertArgument(f, "unknown function", "fragment", fragment);
- fragment = f;
- }
- let message = "invalid length for result data";
- const bytes = getBytesCopy(data);
- if ((bytes.length % 32) === 0) {
- try {
- return this.#abiCoder.decode(fragment.outputs, bytes);
- }
- catch (error) {
- message = "could not decode result data";
- }
- }
- // Call returned data with no error, but the data is junk
- assert(false, message, "BAD_DATA", {
- value: hexlify(bytes),
- info: { method: fragment.name, signature: fragment.format() }
- });
- }
- makeError(_data, tx) {
- const data = getBytes(_data, "data");
- const error = AbiCoder.getBuiltinCallException("call", tx, data);
- // Not a built-in error; try finding a custom error
- const customPrefix = "execution reverted (unknown custom error)";
- if (error.message.startsWith(customPrefix)) {
- const selector = hexlify(data.slice(0, 4));
- const ef = this.getError(selector);
- if (ef) {
- try {
- const args = this.#abiCoder.decode(ef.inputs, data.slice(4));
- error.revert = {
- name: ef.name, signature: ef.format(), args
- };
- error.reason = error.revert.signature;
- error.message = `execution reverted: ${error.reason}`;
- }
- catch (e) {
- error.message = `execution reverted (coult not decode custom error)`;
- }
- }
- }
- // Add the invocation, if available
- const parsed = this.parseTransaction(tx);
- if (parsed) {
- error.invocation = {
- method: parsed.name,
- signature: parsed.signature,
- args: parsed.args
- };
- }
- return error;
- }
- /**
- * Encodes the result data (e.g. from an ``eth_call``) for the
- * specified function (see [[getFunction]] for valid values
- * for %%fragment%%) with %%values%%.
- *
- * This is generally not used by most developers, unless trying to mock
- * a result from a Contract.
- */
- encodeFunctionResult(fragment, values) {
- if (typeof (fragment) === "string") {
- const f = this.getFunction(fragment);
- assertArgument(f, "unknown function", "fragment", fragment);
- fragment = f;
- }
- return hexlify(this.#abiCoder.encode(fragment.outputs, values || []));
- }
- /*
- spelunk(inputs: Array<ParamType>, values: ReadonlyArray<any>, processfunc: (type: string, value: any) => Promise<any>): Promise<Array<any>> {
- const promises: Array<Promise<>> = [ ];
- const process = function(type: ParamType, value: any): any {
- if (type.baseType === "array") {
- return descend(type.child
- }
- if (type. === "address") {
- }
- };
-
- const descend = function (inputs: Array<ParamType>, values: ReadonlyArray<any>) {
- if (inputs.length !== values.length) { throw new Error("length mismatch"); }
-
- };
-
- const result: Array<any> = [ ];
- values.forEach((value, index) => {
- if (value == null) {
- topics.push(null);
- } else if (param.baseType === "array" || param.baseType === "tuple") {
- logger.throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
- } else if (Array.isArray(value)) {
- topics.push(value.map((value) => encodeTopic(param, value)));
- } else {
- topics.push(encodeTopic(param, value));
- }
- });
- }
- */
- // Create the filter for the event with search criteria (e.g. for eth_filterLog)
- encodeFilterTopics(fragment, values) {
- if (typeof (fragment) === "string") {
- const f = this.getEvent(fragment);
- assertArgument(f, "unknown event", "eventFragment", fragment);
- fragment = f;
- }
- assert(values.length <= fragment.inputs.length, `too many arguments for ${fragment.format()}`, "UNEXPECTED_ARGUMENT", { count: values.length, expectedCount: fragment.inputs.length });
- const topics = [];
- if (!fragment.anonymous) {
- topics.push(fragment.topicHash);
- }
- // @TODO: Use the coders for this; to properly support tuples, etc.
- const encodeTopic = (param, value) => {
- if (param.type === "string") {
- return id(value);
- }
- else if (param.type === "bytes") {
- return keccak256(hexlify(value));
- }
- if (param.type === "bool" && typeof (value) === "boolean") {
- value = (value ? "0x01" : "0x00");
- }
- else if (param.type.match(/^u?int/)) {
- value = toBeHex(value); // @TODO: Should this toTwos??
- }
- else if (param.type.match(/^bytes/)) {
- value = zeroPadBytes(value, 32);
- }
- else if (param.type === "address") {
- // Check addresses are valid
- this.#abiCoder.encode(["address"], [value]);
- }
- return zeroPadValue(hexlify(value), 32);
- };
- values.forEach((value, index) => {
- const param = fragment.inputs[index];
- if (!param.indexed) {
- assertArgument(value == null, "cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
- return;
- }
- if (value == null) {
- topics.push(null);
- }
- else if (param.baseType === "array" || param.baseType === "tuple") {
- assertArgument(false, "filtering with tuples or arrays not supported", ("contract." + param.name), value);
- }
- else if (Array.isArray(value)) {
- topics.push(value.map((value) => encodeTopic(param, value)));
- }
- else {
- topics.push(encodeTopic(param, value));
- }
- });
- // Trim off trailing nulls
- while (topics.length && topics[topics.length - 1] === null) {
- topics.pop();
- }
- return topics;
- }
- encodeEventLog(fragment, values) {
- if (typeof (fragment) === "string") {
- const f = this.getEvent(fragment);
- assertArgument(f, "unknown event", "eventFragment", fragment);
- fragment = f;
- }
- const topics = [];
- const dataTypes = [];
- const dataValues = [];
- if (!fragment.anonymous) {
- topics.push(fragment.topicHash);
- }
- assertArgument(values.length === fragment.inputs.length, "event arguments/values mismatch", "values", values);
- fragment.inputs.forEach((param, index) => {
- const value = values[index];
- if (param.indexed) {
- if (param.type === "string") {
- topics.push(id(value));
- }
- else if (param.type === "bytes") {
- topics.push(keccak256(value));
- }
- else if (param.baseType === "tuple" || param.baseType === "array") {
- // @TODO
- throw new Error("not implemented");
- }
- else {
- topics.push(this.#abiCoder.encode([param.type], [value]));
- }
- }
- else {
- dataTypes.push(param);
- dataValues.push(value);
- }
- });
- return {
- data: this.#abiCoder.encode(dataTypes, dataValues),
- topics: topics
- };
- }
- // Decode a filter for the event and the search criteria
- decodeEventLog(fragment, data, topics) {
- if (typeof (fragment) === "string") {
- const f = this.getEvent(fragment);
- assertArgument(f, "unknown event", "eventFragment", fragment);
- fragment = f;
- }
- if (topics != null && !fragment.anonymous) {
- const eventTopic = fragment.topicHash;
- assertArgument(isHexString(topics[0], 32) && topics[0].toLowerCase() === eventTopic, "fragment/topic mismatch", "topics[0]", topics[0]);
- topics = topics.slice(1);
- }
- const indexed = [];
- const nonIndexed = [];
- const dynamic = [];
- fragment.inputs.forEach((param, index) => {
- if (param.indexed) {
- if (param.type === "string" || param.type === "bytes" || param.baseType === "tuple" || param.baseType === "array") {
- indexed.push(ParamType.from({ type: "bytes32", name: param.name }));
- dynamic.push(true);
- }
- else {
- indexed.push(param);
- dynamic.push(false);
- }
- }
- else {
- nonIndexed.push(param);
- dynamic.push(false);
- }
- });
- const resultIndexed = (topics != null) ? this.#abiCoder.decode(indexed, concat(topics)) : null;
- const resultNonIndexed = this.#abiCoder.decode(nonIndexed, data, true);
- //const result: (Array<any> & { [ key: string ]: any }) = [ ];
- const values = [];
- const keys = [];
- let nonIndexedIndex = 0, indexedIndex = 0;
- fragment.inputs.forEach((param, index) => {
- let value = null;
- if (param.indexed) {
- if (resultIndexed == null) {
- value = new Indexed(null);
- }
- else if (dynamic[index]) {
- value = new Indexed(resultIndexed[indexedIndex++]);
- }
- else {
- try {
- value = resultIndexed[indexedIndex++];
- }
- catch (error) {
- value = error;
- }
- }
- }
- else {
- try {
- value = resultNonIndexed[nonIndexedIndex++];
- }
- catch (error) {
- value = error;
- }
- }
- values.push(value);
- keys.push(param.name || null);
- });
- return Result.fromItems(values, keys);
- }
- /**
- * Parses a transaction, finding the matching function and extracts
- * the parameter values along with other useful function details.
- *
- * If the matching function cannot be found, return null.
- */
- parseTransaction(tx) {
- const data = getBytes(tx.data, "tx.data");
- const value = getBigInt((tx.value != null) ? tx.value : 0, "tx.value");
- const fragment = this.getFunction(hexlify(data.slice(0, 4)));
- if (!fragment) {
- return null;
- }
- const args = this.#abiCoder.decode(fragment.inputs, data.slice(4));
- return new TransactionDescription(fragment, fragment.selector, args, value);
- }
- parseCallResult(data) {
- throw new Error("@TODO");
- }
- /**
- * Parses a receipt log, finding the matching event and extracts
- * the parameter values along with other useful event details.
- *
- * If the matching event cannot be found, returns null.
- */
- parseLog(log) {
- const fragment = this.getEvent(log.topics[0]);
- if (!fragment || fragment.anonymous) {
- return null;
- }
- // @TODO: If anonymous, and the only method, and the input count matches, should we parse?
- // Probably not, because just because it is the only event in the ABI does
- // not mean we have the full ABI; maybe just a fragment?
- return new LogDescription(fragment, fragment.topicHash, this.decodeEventLog(fragment, log.data, log.topics));
- }
- /**
- * Parses a revert data, finding the matching error and extracts
- * the parameter values along with other useful error details.
- *
- * If the matching error cannot be found, returns null.
- */
- parseError(data) {
- const hexData = hexlify(data);
- const fragment = this.getError(dataSlice(hexData, 0, 4));
- if (!fragment) {
- return null;
- }
- const args = this.#abiCoder.decode(fragment.inputs, dataSlice(hexData, 4));
- return new ErrorDescription(fragment, fragment.selector, args);
- }
- /**
- * Creates a new [[Interface]] from the ABI %%value%%.
- *
- * The %%value%% may be provided as an existing [[Interface]] object,
- * a JSON-encoded ABI or any Human-Readable ABI format.
- */
- static from(value) {
- // Already an Interface, which is immutable
- if (value instanceof Interface) {
- return value;
- }
- // JSON
- if (typeof (value) === "string") {
- return new Interface(JSON.parse(value));
- }
- // An Interface; possibly from another v6 instance
- if (typeof (value.formatJson) === "function") {
- return new Interface(value.formatJson());
- }
- // A legacy Interface; from an older version
- if (typeof (value.format) === "function") {
- return new Interface(value.format("json"));
- }
- // Array of fragments
- return new Interface(value);
- }
- }
- //import { resolveAddress } from "@ethersproject/address";
- const BN_0$2 = BigInt(0);
- // -----------------------
- function getValue(value) {
- if (value == null) {
- return null;
- }
- return value;
- }
- function toJson(value) {
- if (value == null) {
- return null;
- }
- return value.toString();
- }
- // @TODO? <T extends FeeData = { }> implements Required<T>
- /**
- * A **FeeData** wraps all the fee-related values associated with
- * the network.
- */
- class FeeData {
- /**
- * The gas price for legacy networks.
- */
- gasPrice;
- /**
- * The maximum fee to pay per gas.
- *
- * The base fee per gas is defined by the network and based on
- * congestion, increasing the cost during times of heavy load
- * and lowering when less busy.
- *
- * The actual fee per gas will be the base fee for the block
- * and the priority fee, up to the max fee per gas.
- *
- * This will be ``null`` on legacy networks (i.e. [pre-EIP-1559](link-eip-1559))
- */
- maxFeePerGas;
- /**
- * The additional amout to pay per gas to encourage a validator
- * to include the transaction.
- *
- * The purpose of this is to compensate the validator for the
- * adjusted risk for including a given transaction.
- *
- * This will be ``null`` on legacy networks (i.e. [pre-EIP-1559](link-eip-1559))
- */
- maxPriorityFeePerGas;
- /**
- * Creates a new FeeData for %%gasPrice%%, %%maxFeePerGas%% and
- * %%maxPriorityFeePerGas%%.
- */
- constructor(gasPrice, maxFeePerGas, maxPriorityFeePerGas) {
- defineProperties(this, {
- gasPrice: getValue(gasPrice),
- maxFeePerGas: getValue(maxFeePerGas),
- maxPriorityFeePerGas: getValue(maxPriorityFeePerGas)
- });
- }
- /**
- * Returns a JSON-friendly value.
- */
- toJSON() {
- const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } = this;
- return {
- _type: "FeeData",
- gasPrice: toJson(gasPrice),
- maxFeePerGas: toJson(maxFeePerGas),
- maxPriorityFeePerGas: toJson(maxPriorityFeePerGas),
- };
- }
- }
- /**
- * Returns a copy of %%req%% with all properties coerced to their strict
- * types.
- */
- function copyRequest(req) {
- const result = {};
- // These could be addresses, ENS names or Addressables
- if (req.to) {
- result.to = req.to;
- }
- if (req.from) {
- result.from = req.from;
- }
- if (req.data) {
- result.data = hexlify(req.data);
- }
- const bigIntKeys = "chainId,gasLimit,gasPrice,maxFeePerBlobGas,maxFeePerGas,maxPriorityFeePerGas,value".split(/,/);
- for (const key of bigIntKeys) {
- if (!(key in req) || req[key] == null) {
- continue;
- }
- result[key] = getBigInt(req[key], `request.${key}`);
- }
- const numberKeys = "type,nonce".split(/,/);
- for (const key of numberKeys) {
- if (!(key in req) || req[key] == null) {
- continue;
- }
- result[key] = getNumber(req[key], `request.${key}`);
- }
- if (req.accessList) {
- result.accessList = accessListify(req.accessList);
- }
- if ("blockTag" in req) {
- result.blockTag = req.blockTag;
- }
- if ("enableCcipRead" in req) {
- result.enableCcipRead = !!req.enableCcipRead;
- }
- if ("customData" in req) {
- result.customData = req.customData;
- }
- if ("blobVersionedHashes" in req && req.blobVersionedHashes) {
- result.blobVersionedHashes = req.blobVersionedHashes.slice();
- }
- if ("kzg" in req) {
- result.kzg = req.kzg;
- }
- if ("blobs" in req && req.blobs) {
- result.blobs = req.blobs.map((b) => {
- if (isBytesLike(b)) {
- return hexlify(b);
- }
- return Object.assign({}, b);
- });
- }
- return result;
- }
- /**
- * A **Block** represents the data associated with a full block on
- * Ethereum.
- */
- class Block {
- /**
- * The provider connected to the block used to fetch additional details
- * if necessary.
- */
- provider;
- /**
- * The block number, sometimes called the block height. This is a
- * sequential number that is one higher than the parent block.
- */
- number;
- /**
- * The block hash.
- *
- * This hash includes all properties, so can be safely used to identify
- * an exact set of block properties.
- */
- hash;
- /**
- * The timestamp for this block, which is the number of seconds since
- * epoch that this block was included.
- */
- timestamp;
- /**
- * The block hash of the parent block.
- */
- parentHash;
- /**
- * The hash tree root of the parent beacon block for the given
- * execution block. See [[link-eip-4788]].
- */
- parentBeaconBlockRoot;
- /**
- * The nonce.
- *
- * On legacy networks, this is the random number inserted which
- * permitted the difficulty target to be reached.
- */
- nonce;
- /**
- * The difficulty target.
- *
- * On legacy networks, this is the proof-of-work target required
- * for a block to meet the protocol rules to be included.
- *
- * On modern networks, this is a random number arrived at using
- * randao. @TODO: Find links?
- */
- difficulty;
- /**
- * The total gas limit for this block.
- */
- gasLimit;
- /**
- * The total gas used in this block.
- */
- gasUsed;
- /**
- * The root hash for the global state after applying changes
- * in this block.
- */
- stateRoot;
- /**
- * The hash of the transaction receipts trie.
- */
- receiptsRoot;
- /**
- * The total amount of blob gas consumed by the transactions
- * within the block. See [[link-eip-4844]].
- */
- blobGasUsed;
- /**
- * The running total of blob gas consumed in excess of the
- * target, prior to the block. See [[link-eip-4844]].
- */
- excessBlobGas;
- /**
- * The miner coinbase address, wihch receives any subsidies for
- * including this block.
- */
- miner;
- /**
- * The latest RANDAO mix of the post beacon state of
- * the previous block.
- */
- prevRandao;
- /**
- * Any extra data the validator wished to include.
- */
- extraData;
- /**
- * The base fee per gas that all transactions in this block were
- * charged.
- *
- * This adjusts after each block, depending on how congested the network
- * is.
- */
- baseFeePerGas;
- #transactions;
- /**
- * Create a new **Block** object.
- *
- * This should generally not be necessary as the unless implementing a
- * low-level library.
- */
- constructor(block, provider) {
- this.#transactions = block.transactions.map((tx) => {
- if (typeof (tx) !== "string") {
- return new TransactionResponse(tx, provider);
- }
- return tx;
- });
- defineProperties(this, {
- provider,
- hash: getValue(block.hash),
- number: block.number,
- timestamp: block.timestamp,
- parentHash: block.parentHash,
- parentBeaconBlockRoot: block.parentBeaconBlockRoot,
- nonce: block.nonce,
- difficulty: block.difficulty,
- gasLimit: block.gasLimit,
- gasUsed: block.gasUsed,
- blobGasUsed: block.blobGasUsed,
- excessBlobGas: block.excessBlobGas,
- miner: block.miner,
- prevRandao: getValue(block.prevRandao),
- extraData: block.extraData,
- baseFeePerGas: getValue(block.baseFeePerGas),
- stateRoot: block.stateRoot,
- receiptsRoot: block.receiptsRoot,
- });
- }
- /**
- * Returns the list of transaction hashes, in the order
- * they were executed within the block.
- */
- get transactions() {
- return this.#transactions.map((tx) => {
- if (typeof (tx) === "string") {
- return tx;
- }
- return tx.hash;
- });
- }
- /**
- * Returns the complete transactions, in the order they
- * were executed within the block.
- *
- * This is only available for blocks which prefetched
- * transactions, by passing ``true`` to %%prefetchTxs%%
- * into [[Provider-getBlock]].
- */
- get prefetchedTransactions() {
- const txs = this.#transactions.slice();
- // Doesn't matter...
- if (txs.length === 0) {
- return [];
- }
- // Make sure we prefetched the transactions
- assert(typeof (txs[0]) === "object", "transactions were not prefetched with block request", "UNSUPPORTED_OPERATION", {
- operation: "transactionResponses()"
- });
- return txs;
- }
- /**
- * Returns a JSON-friendly value.
- */
- toJSON() {
- const { baseFeePerGas, difficulty, extraData, gasLimit, gasUsed, hash, miner, prevRandao, nonce, number, parentHash, parentBeaconBlockRoot, stateRoot, receiptsRoot, timestamp, transactions } = this;
- return {
- _type: "Block",
- baseFeePerGas: toJson(baseFeePerGas),
- difficulty: toJson(difficulty),
- extraData,
- gasLimit: toJson(gasLimit),
- gasUsed: toJson(gasUsed),
- blobGasUsed: toJson(this.blobGasUsed),
- excessBlobGas: toJson(this.excessBlobGas),
- hash, miner, prevRandao, nonce, number, parentHash, timestamp,
- parentBeaconBlockRoot, stateRoot, receiptsRoot,
- transactions,
- };
- }
- [Symbol.iterator]() {
- let index = 0;
- const txs = this.transactions;
- return {
- next: () => {
- if (index < this.length) {
- return {
- value: txs[index++], done: false
- };
- }
- return { value: undefined, done: true };
- }
- };
- }
- /**
- * The number of transactions in this block.
- */
- get length() { return this.#transactions.length; }
- /**
- * The [[link-js-date]] this block was included at.
- */
- get date() {
- if (this.timestamp == null) {
- return null;
- }
- return new Date(this.timestamp * 1000);
- }
- /**
- * Get the transaction at %%indexe%% within this block.
- */
- async getTransaction(indexOrHash) {
- // Find the internal value by its index or hash
- let tx = undefined;
- if (typeof (indexOrHash) === "number") {
- tx = this.#transactions[indexOrHash];
- }
- else {
- const hash = indexOrHash.toLowerCase();
- for (const v of this.#transactions) {
- if (typeof (v) === "string") {
- if (v !== hash) {
- continue;
- }
- tx = v;
- break;
- }
- else {
- if (v.hash !== hash) {
- continue;
- }
- tx = v;
- break;
- }
- }
- }
- if (tx == null) {
- throw new Error("no such tx");
- }
- if (typeof (tx) === "string") {
- return (await this.provider.getTransaction(tx));
- }
- else {
- return tx;
- }
- }
- /**
- * If a **Block** was fetched with a request to include the transactions
- * this will allow synchronous access to those transactions.
- *
- * If the transactions were not prefetched, this will throw.
- */
- getPrefetchedTransaction(indexOrHash) {
- const txs = this.prefetchedTransactions;
- if (typeof (indexOrHash) === "number") {
- return txs[indexOrHash];
- }
- indexOrHash = indexOrHash.toLowerCase();
- for (const tx of txs) {
- if (tx.hash === indexOrHash) {
- return tx;
- }
- }
- assertArgument(false, "no matching transaction", "indexOrHash", indexOrHash);
- }
- /**
- * Returns true if this block been mined. This provides a type guard
- * for all properties on a [[MinedBlock]].
- */
- isMined() { return !!this.hash; }
- /**
- * Returns true if this block is an [[link-eip-2930]] block.
- */
- isLondon() {
- return !!this.baseFeePerGas;
- }
- /**
- * @_ignore:
- */
- orphanedEvent() {
- if (!this.isMined()) {
- throw new Error("");
- }
- return createOrphanedBlockFilter(this);
- }
- }
- //////////////////////
- // Log
- /**
- * A **Log** in Ethereum represents an event that has been included in a
- * transaction using the ``LOG*`` opcodes, which are most commonly used by
- * Solidity's emit for announcing events.
- */
- class Log {
- /**
- * The provider connected to the log used to fetch additional details
- * if necessary.
- */
- provider;
- /**
- * The transaction hash of the transaction this log occurred in. Use the
- * [[Log-getTransaction]] to get the [[TransactionResponse]].
- */
- transactionHash;
- /**
- * The block hash of the block this log occurred in. Use the
- * [[Log-getBlock]] to get the [[Block]].
- */
- blockHash;
- /**
- * The block number of the block this log occurred in. It is preferred
- * to use the [[Block-hash]] when fetching the related [[Block]],
- * since in the case of an orphaned block, the block at that height may
- * have changed.
- */
- blockNumber;
- /**
- * If the **Log** represents a block that was removed due to an orphaned
- * block, this will be true.
- *
- * This can only happen within an orphan event listener.
- */
- removed;
- /**
- * The address of the contract that emitted this log.
- */
- address;
- /**
- * The data included in this log when it was emitted.
- */
- data;
- /**
- * The indexed topics included in this log when it was emitted.
- *
- * All topics are included in the bloom filters, so they can be
- * efficiently filtered using the [[Provider-getLogs]] method.
- */
- topics;
- /**
- * The index within the block this log occurred at. This is generally
- * not useful to developers, but can be used with the various roots
- * to proof inclusion within a block.
- */
- index;
- /**
- * The index within the transaction of this log.
- */
- transactionIndex;
- /**
- * @_ignore:
- */
- constructor(log, provider) {
- this.provider = provider;
- const topics = Object.freeze(log.topics.slice());
- defineProperties(this, {
- transactionHash: log.transactionHash,
- blockHash: log.blockHash,
- blockNumber: log.blockNumber,
- removed: log.removed,
- address: log.address,
- data: log.data,
- topics,
- index: log.index,
- transactionIndex: log.transactionIndex,
- });
- }
- /**
- * Returns a JSON-compatible object.
- */
- toJSON() {
- const { address, blockHash, blockNumber, data, index, removed, topics, transactionHash, transactionIndex } = this;
- return {
- _type: "log",
- address, blockHash, blockNumber, data, index,
- removed, topics, transactionHash, transactionIndex
- };
- }
- /**
- * Returns the block that this log occurred in.
- */
- async getBlock() {
- const block = await this.provider.getBlock(this.blockHash);
- assert(!!block, "failed to find transaction", "UNKNOWN_ERROR", {});
- return block;
- }
- /**
- * Returns the transaction that this log occurred in.
- */
- async getTransaction() {
- const tx = await this.provider.getTransaction(this.transactionHash);
- assert(!!tx, "failed to find transaction", "UNKNOWN_ERROR", {});
- return tx;
- }
- /**
- * Returns the transaction receipt fot the transaction that this
- * log occurred in.
- */
- async getTransactionReceipt() {
- const receipt = await this.provider.getTransactionReceipt(this.transactionHash);
- assert(!!receipt, "failed to find transaction receipt", "UNKNOWN_ERROR", {});
- return receipt;
- }
- /**
- * @_ignore:
- */
- removedEvent() {
- return createRemovedLogFilter(this);
- }
- }
- //////////////////////
- // Transaction Receipt
- /*
- export interface LegacyTransactionReceipt {
- byzantium: false;
- status: null;
- root: string;
- }
- export interface ByzantiumTransactionReceipt {
- byzantium: true;
- status: number;
- root: null;
- }
- */
- /**
- * A **TransactionReceipt** includes additional information about a
- * transaction that is only available after it has been mined.
- */
- class TransactionReceipt {
- /**
- * The provider connected to the log used to fetch additional details
- * if necessary.
- */
- provider;
- /**
- * The address the transaction was sent to.
- */
- to;
- /**
- * The sender of the transaction.
- */
- from;
- /**
- * The address of the contract if the transaction was directly
- * responsible for deploying one.
- *
- * This is non-null **only** if the ``to`` is empty and the ``data``
- * was successfully executed as initcode.
- */
- contractAddress;
- /**
- * The transaction hash.
- */
- hash;
- /**
- * The index of this transaction within the block transactions.
- */
- index;
- /**
- * The block hash of the [[Block]] this transaction was included in.
- */
- blockHash;
- /**
- * The block number of the [[Block]] this transaction was included in.
- */
- blockNumber;
- /**
- * The bloom filter bytes that represent all logs that occurred within
- * this transaction. This is generally not useful for most developers,
- * but can be used to validate the included logs.
- */
- logsBloom;
- /**
- * The actual amount of gas used by this transaction.
- *
- * When creating a transaction, the amount of gas that will be used can
- * only be approximated, but the sender must pay the gas fee for the
- * entire gas limit. After the transaction, the difference is refunded.
- */
- gasUsed;
- /**
- * The gas used for BLObs. See [[link-eip-4844]].
- */
- blobGasUsed;
- /**
- * The amount of gas used by all transactions within the block for this
- * and all transactions with a lower ``index``.
- *
- * This is generally not useful for developers but can be used to
- * validate certain aspects of execution.
- */
- cumulativeGasUsed;
- /**
- * The actual gas price used during execution.
- *
- * Due to the complexity of [[link-eip-1559]] this value can only
- * be caluclated after the transaction has been mined, snce the base
- * fee is protocol-enforced.
- */
- gasPrice;
- /**
- * The price paid per BLOB in gas. See [[link-eip-4844]].
- */
- blobGasPrice;
- /**
- * The [[link-eip-2718]] transaction type.
- */
- type;
- //readonly byzantium!: boolean;
- /**
- * The status of this transaction, indicating success (i.e. ``1``) or
- * a revert (i.e. ``0``).
- *
- * This is available in post-byzantium blocks, but some backends may
- * backfill this value.
- */
- status;
- /**
- * The root hash of this transaction.
- *
- * This is no present and was only included in pre-byzantium blocks, but
- * could be used to validate certain parts of the receipt.
- */
- root;
- #logs;
- /**
- * @_ignore:
- */
- constructor(tx, provider) {
- this.#logs = Object.freeze(tx.logs.map((log) => {
- return new Log(log, provider);
- }));
- let gasPrice = BN_0$2;
- if (tx.effectiveGasPrice != null) {
- gasPrice = tx.effectiveGasPrice;
- }
- else if (tx.gasPrice != null) {
- gasPrice = tx.gasPrice;
- }
- defineProperties(this, {
- provider,
- to: tx.to,
- from: tx.from,
- contractAddress: tx.contractAddress,
- hash: tx.hash,
- index: tx.index,
- blockHash: tx.blockHash,
- blockNumber: tx.blockNumber,
- logsBloom: tx.logsBloom,
- gasUsed: tx.gasUsed,
- cumulativeGasUsed: tx.cumulativeGasUsed,
- blobGasUsed: tx.blobGasUsed,
- gasPrice,
- blobGasPrice: tx.blobGasPrice,
- type: tx.type,
- //byzantium: tx.byzantium,
- status: tx.status,
- root: tx.root
- });
- }
- /**
- * The logs for this transaction.
- */
- get logs() { return this.#logs; }
- /**
- * Returns a JSON-compatible representation.
- */
- toJSON() {
- const { to, from, contractAddress, hash, index, blockHash, blockNumber, logsBloom, logs, //byzantium,
- status, root } = this;
- return {
- _type: "TransactionReceipt",
- blockHash, blockNumber,
- //byzantium,
- contractAddress,
- cumulativeGasUsed: toJson(this.cumulativeGasUsed),
- from,
- gasPrice: toJson(this.gasPrice),
- blobGasUsed: toJson(this.blobGasUsed),
- blobGasPrice: toJson(this.blobGasPrice),
- gasUsed: toJson(this.gasUsed),
- hash, index, logs, logsBloom, root, status, to
- };
- }
- /**
- * @_ignore:
- */
- get length() { return this.logs.length; }
- [Symbol.iterator]() {
- let index = 0;
- return {
- next: () => {
- if (index < this.length) {
- return { value: this.logs[index++], done: false };
- }
- return { value: undefined, done: true };
- }
- };
- }
- /**
- * The total fee for this transaction, in wei.
- */
- get fee() {
- return this.gasUsed * this.gasPrice;
- }
- /**
- * Resolves to the block this transaction occurred in.
- */
- async getBlock() {
- const block = await this.provider.getBlock(this.blockHash);
- if (block == null) {
- throw new Error("TODO");
- }
- return block;
- }
- /**
- * Resolves to the transaction this transaction occurred in.
- */
- async getTransaction() {
- const tx = await this.provider.getTransaction(this.hash);
- if (tx == null) {
- throw new Error("TODO");
- }
- return tx;
- }
- /**
- * Resolves to the return value of the execution of this transaction.
- *
- * Support for this feature is limited, as it requires an archive node
- * with the ``debug_`` or ``trace_`` API enabled.
- */
- async getResult() {
- return (await this.provider.getTransactionResult(this.hash));
- }
- /**
- * Resolves to the number of confirmations this transaction has.
- */
- async confirmations() {
- return (await this.provider.getBlockNumber()) - this.blockNumber + 1;
- }
- /**
- * @_ignore:
- */
- removedEvent() {
- return createRemovedTransactionFilter(this);
- }
- /**
- * @_ignore:
- */
- reorderedEvent(other) {
- assert(!other || other.isMined(), "unmined 'other' transction cannot be orphaned", "UNSUPPORTED_OPERATION", { operation: "reorderedEvent(other)" });
- return createReorderedTransactionFilter(this, other);
- }
- }
- /**
- * A **TransactionResponse** includes all properties about a transaction
- * that was sent to the network, which may or may not be included in a
- * block.
- *
- * The [[TransactionResponse-isMined]] can be used to check if the
- * transaction has been mined as well as type guard that the otherwise
- * possibly ``null`` properties are defined.
- */
- class TransactionResponse {
- /**
- * The provider this is connected to, which will influence how its
- * methods will resolve its async inspection methods.
- */
- provider;
- /**
- * The block number of the block that this transaction was included in.
- *
- * This is ``null`` for pending transactions.
- */
- blockNumber;
- /**
- * The blockHash of the block that this transaction was included in.
- *
- * This is ``null`` for pending transactions.
- */
- blockHash;
- /**
- * The index within the block that this transaction resides at.
- */
- index;
- /**
- * The transaction hash.
- */
- hash;
- /**
- * The [[link-eip-2718]] transaction envelope type. This is
- * ``0`` for legacy transactions types.
- */
- type;
- /**
- * The receiver of this transaction.
- *
- * If ``null``, then the transaction is an initcode transaction.
- * This means the result of executing the [[data]] will be deployed
- * as a new contract on chain (assuming it does not revert) and the
- * address may be computed using [[getCreateAddress]].
- */
- to;
- /**
- * The sender of this transaction. It is implicitly computed
- * from the transaction pre-image hash (as the digest) and the
- * [[signature]] using ecrecover.
- */
- from;
- /**
- * The nonce, which is used to prevent replay attacks and offer
- * a method to ensure transactions from a given sender are explicitly
- * ordered.
- *
- * When sending a transaction, this must be equal to the number of
- * transactions ever sent by [[from]].
- */
- nonce;
- /**
- * The maximum units of gas this transaction can consume. If execution
- * exceeds this, the entries transaction is reverted and the sender
- * is charged for the full amount, despite not state changes being made.
- */
- gasLimit;
- /**
- * The gas price can have various values, depending on the network.
- *
- * In modern networks, for transactions that are included this is
- * the //effective gas price// (the fee per gas that was actually
- * charged), while for transactions that have not been included yet
- * is the [[maxFeePerGas]].
- *
- * For legacy transactions, or transactions on legacy networks, this
- * is the fee that will be charged per unit of gas the transaction
- * consumes.
- */
- gasPrice;
- /**
- * The maximum priority fee (per unit of gas) to allow a
- * validator to charge the sender. This is inclusive of the
- * [[maxFeeFeePerGas]].
- */
- maxPriorityFeePerGas;
- /**
- * The maximum fee (per unit of gas) to allow this transaction
- * to charge the sender.
- */
- maxFeePerGas;
- /**
- * The [[link-eip-4844]] max fee per BLOb gas.
- */
- maxFeePerBlobGas;
- /**
- * The data.
- */
- data;
- /**
- * The value, in wei. Use [[formatEther]] to format this value
- * as ether.
- */
- value;
- /**
- * The chain ID.
- */
- chainId;
- /**
- * The signature.
- */
- signature;
- /**
- * The [[link-eip-2930]] access list for transaction types that
- * support it, otherwise ``null``.
- */
- accessList;
- /**
- * The [[link-eip-4844]] BLOb versioned hashes.
- */
- blobVersionedHashes;
- #startBlock;
- /**
- * @_ignore:
- */
- constructor(tx, provider) {
- this.provider = provider;
- this.blockNumber = (tx.blockNumber != null) ? tx.blockNumber : null;
- this.blockHash = (tx.blockHash != null) ? tx.blockHash : null;
- this.hash = tx.hash;
- this.index = tx.index;
- this.type = tx.type;
- this.from = tx.from;
- this.to = tx.to || null;
- this.gasLimit = tx.gasLimit;
- this.nonce = tx.nonce;
- this.data = tx.data;
- this.value = tx.value;
- this.gasPrice = tx.gasPrice;
- this.maxPriorityFeePerGas = (tx.maxPriorityFeePerGas != null) ? tx.maxPriorityFeePerGas : null;
- this.maxFeePerGas = (tx.maxFeePerGas != null) ? tx.maxFeePerGas : null;
- this.maxFeePerBlobGas = (tx.maxFeePerBlobGas != null) ? tx.maxFeePerBlobGas : null;
- this.chainId = tx.chainId;
- this.signature = tx.signature;
- this.accessList = (tx.accessList != null) ? tx.accessList : null;
- this.blobVersionedHashes = (tx.blobVersionedHashes != null) ? tx.blobVersionedHashes : null;
- this.#startBlock = -1;
- }
- /**
- * Returns a JSON-compatible representation of this transaction.
- */
- toJSON() {
- const { blockNumber, blockHash, index, hash, type, to, from, nonce, data, signature, accessList, blobVersionedHashes } = this;
- return {
- _type: "TransactionResponse",
- accessList, blockNumber, blockHash,
- blobVersionedHashes,
- chainId: toJson(this.chainId),
- data, from,
- gasLimit: toJson(this.gasLimit),
- gasPrice: toJson(this.gasPrice),
- hash,
- maxFeePerGas: toJson(this.maxFeePerGas),
- maxPriorityFeePerGas: toJson(this.maxPriorityFeePerGas),
- maxFeePerBlobGas: toJson(this.maxFeePerBlobGas),
- nonce, signature, to, index, type,
- value: toJson(this.value),
- };
- }
- /**
- * Resolves to the Block that this transaction was included in.
- *
- * This will return null if the transaction has not been included yet.
- */
- async getBlock() {
- let blockNumber = this.blockNumber;
- if (blockNumber == null) {
- const tx = await this.getTransaction();
- if (tx) {
- blockNumber = tx.blockNumber;
- }
- }
- if (blockNumber == null) {
- return null;
- }
- const block = this.provider.getBlock(blockNumber);
- if (block == null) {
- throw new Error("TODO");
- }
- return block;
- }
- /**
- * Resolves to this transaction being re-requested from the
- * provider. This can be used if you have an unmined transaction
- * and wish to get an up-to-date populated instance.
- */
- async getTransaction() {
- return this.provider.getTransaction(this.hash);
- }
- /**
- * Resolve to the number of confirmations this transaction has.
- */
- async confirmations() {
- if (this.blockNumber == null) {
- const { tx, blockNumber } = await resolveProperties({
- tx: this.getTransaction(),
- blockNumber: this.provider.getBlockNumber()
- });
- // Not mined yet...
- if (tx == null || tx.blockNumber == null) {
- return 0;
- }
- return blockNumber - tx.blockNumber + 1;
- }
- const blockNumber = await this.provider.getBlockNumber();
- return blockNumber - this.blockNumber + 1;
- }
- /**
- * Resolves once this transaction has been mined and has
- * %%confirms%% blocks including it (default: ``1``) with an
- * optional %%timeout%%.
- *
- * This can resolve to ``null`` only if %%confirms%% is ``0``
- * and the transaction has not been mined, otherwise this will
- * wait until enough confirmations have completed.
- */
- async wait(_confirms, _timeout) {
- const confirms = (_confirms == null) ? 1 : _confirms;
- const timeout = (_timeout == null) ? 0 : _timeout;
- let startBlock = this.#startBlock;
- let nextScan = -1;
- let stopScanning = (startBlock === -1) ? true : false;
- const checkReplacement = async () => {
- // Get the current transaction count for this sender
- if (stopScanning) {
- return null;
- }
- const { blockNumber, nonce } = await resolveProperties({
- blockNumber: this.provider.getBlockNumber(),
- nonce: this.provider.getTransactionCount(this.from)
- });
- // No transaction or our nonce has not been mined yet; but we
- // can start scanning later when we do start
- if (nonce < this.nonce) {
- startBlock = blockNumber;
- return;
- }
- // We were mined; no replacement
- if (stopScanning) {
- return null;
- }
- const mined = await this.getTransaction();
- if (mined && mined.blockNumber != null) {
- return;
- }
- // We were replaced; start scanning for that transaction
- // Starting to scan; look back a few extra blocks for safety
- if (nextScan === -1) {
- nextScan = startBlock - 3;
- if (nextScan < this.#startBlock) {
- nextScan = this.#startBlock;
- }
- }
- while (nextScan <= blockNumber) {
- // Get the next block to scan
- if (stopScanning) {
- return null;
- }
- const block = await this.provider.getBlock(nextScan, true);
- // This should not happen; but we'll try again shortly
- if (block == null) {
- return;
- }
- // We were mined; no replacement
- for (const hash of block) {
- if (hash === this.hash) {
- return;
- }
- }
- // Search for the transaction that replaced us
- for (let i = 0; i < block.length; i++) {
- const tx = await block.getTransaction(i);
- if (tx.from === this.from && tx.nonce === this.nonce) {
- // Get the receipt
- if (stopScanning) {
- return null;
- }
- const receipt = await this.provider.getTransactionReceipt(tx.hash);
- // This should not happen; but we'll try again shortly
- if (receipt == null) {
- return;
- }
- // We will retry this on the next block (this case could be optimized)
- if ((blockNumber - receipt.blockNumber + 1) < confirms) {
- return;
- }
- // The reason we were replaced
- let reason = "replaced";
- if (tx.data === this.data && tx.to === this.to && tx.value === this.value) {
- reason = "repriced";
- }
- else if (tx.data === "0x" && tx.from === tx.to && tx.value === BN_0$2) {
- reason = "cancelled";
- }
- assert(false, "transaction was replaced", "TRANSACTION_REPLACED", {
- cancelled: (reason === "replaced" || reason === "cancelled"),
- reason,
- replacement: tx.replaceableTransaction(startBlock),
- hash: tx.hash,
- receipt
- });
- }
- }
- nextScan++;
- }
- return;
- };
- const checkReceipt = (receipt) => {
- if (receipt == null || receipt.status !== 0) {
- return receipt;
- }
- assert(false, "transaction execution reverted", "CALL_EXCEPTION", {
- action: "sendTransaction",
- data: null, reason: null, invocation: null, revert: null,
- transaction: {
- to: receipt.to,
- from: receipt.from,
- data: "" // @TODO: in v7, split out sendTransaction properties
- }, receipt
- });
- };
- const receipt = await this.provider.getTransactionReceipt(this.hash);
- if (confirms === 0) {
- return checkReceipt(receipt);
- }
- if (receipt) {
- if ((await receipt.confirmations()) >= confirms) {
- return checkReceipt(receipt);
- }
- }
- else {
- // Check for a replacement; throws if a replacement was found
- await checkReplacement();
- // Allow null only when the confirms is 0
- if (confirms === 0) {
- return null;
- }
- }
- const waiter = new Promise((resolve, reject) => {
- // List of things to cancel when we have a result (one way or the other)
- const cancellers = [];
- const cancel = () => { cancellers.forEach((c) => c()); };
- // On cancel, stop scanning for replacements
- cancellers.push(() => { stopScanning = true; });
- // Set up any timeout requested
- if (timeout > 0) {
- const timer = setTimeout(() => {
- cancel();
- reject(makeError("wait for transaction timeout", "TIMEOUT"));
- }, timeout);
- cancellers.push(() => { clearTimeout(timer); });
- }
- const txListener = async (receipt) => {
- // Done; return it!
- if ((await receipt.confirmations()) >= confirms) {
- cancel();
- try {
- resolve(checkReceipt(receipt));
- }
- catch (error) {
- reject(error);
- }
- }
- };
- cancellers.push(() => { this.provider.off(this.hash, txListener); });
- this.provider.on(this.hash, txListener);
- // We support replacement detection; start checking
- if (startBlock >= 0) {
- const replaceListener = async () => {
- try {
- // Check for a replacement; this throws only if one is found
- await checkReplacement();
- }
- catch (error) {
- // We were replaced (with enough confirms); re-throw the error
- if (isError(error, "TRANSACTION_REPLACED")) {
- cancel();
- reject(error);
- return;
- }
- }
- // Rescheudle a check on the next block
- if (!stopScanning) {
- this.provider.once("block", replaceListener);
- }
- };
- cancellers.push(() => { this.provider.off("block", replaceListener); });
- this.provider.once("block", replaceListener);
- }
- });
- return await waiter;
- }
- /**
- * Returns ``true`` if this transaction has been included.
- *
- * This is effective only as of the time the TransactionResponse
- * was instantiated. To get up-to-date information, use
- * [[getTransaction]].
- *
- * This provides a Type Guard that this transaction will have
- * non-null property values for properties that are null for
- * unmined transactions.
- */
- isMined() {
- return (this.blockHash != null);
- }
- /**
- * Returns true if the transaction is a legacy (i.e. ``type == 0``)
- * transaction.
- *
- * This provides a Type Guard that this transaction will have
- * the ``null``-ness for hardfork-specific properties set correctly.
- */
- isLegacy() {
- return (this.type === 0);
- }
- /**
- * Returns true if the transaction is a Berlin (i.e. ``type == 1``)
- * transaction. See [[link-eip-2070]].
- *
- * This provides a Type Guard that this transaction will have
- * the ``null``-ness for hardfork-specific properties set correctly.
- */
- isBerlin() {
- return (this.type === 1);
- }
- /**
- * Returns true if the transaction is a London (i.e. ``type == 2``)
- * transaction. See [[link-eip-1559]].
- *
- * This provides a Type Guard that this transaction will have
- * the ``null``-ness for hardfork-specific properties set correctly.
- */
- isLondon() {
- return (this.type === 2);
- }
- /**
- * Returns true if hte transaction is a Cancun (i.e. ``type == 3``)
- * transaction. See [[link-eip-4844]].
- */
- isCancun() {
- return (this.type === 3);
- }
- /**
- * Returns a filter which can be used to listen for orphan events
- * that evict this transaction.
- */
- removedEvent() {
- assert(this.isMined(), "unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", { operation: "removeEvent()" });
- return createRemovedTransactionFilter(this);
- }
- /**
- * Returns a filter which can be used to listen for orphan events
- * that re-order this event against %%other%%.
- */
- reorderedEvent(other) {
- assert(this.isMined(), "unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", { operation: "removeEvent()" });
- assert(!other || other.isMined(), "unmined 'other' transaction canot be orphaned", "UNSUPPORTED_OPERATION", { operation: "removeEvent()" });
- return createReorderedTransactionFilter(this, other);
- }
- /**
- * Returns a new TransactionResponse instance which has the ability to
- * detect (and throw an error) if the transaction is replaced, which
- * will begin scanning at %%startBlock%%.
- *
- * This should generally not be used by developers and is intended
- * primarily for internal use. Setting an incorrect %%startBlock%% can
- * have devastating performance consequences if used incorrectly.
- */
- replaceableTransaction(startBlock) {
- assertArgument(Number.isInteger(startBlock) && startBlock >= 0, "invalid startBlock", "startBlock", startBlock);
- const tx = new TransactionResponse(this, this.provider);
- tx.#startBlock = startBlock;
- return tx;
- }
- }
- function createOrphanedBlockFilter(block) {
- return { orphan: "drop-block", hash: block.hash, number: block.number };
- }
- function createReorderedTransactionFilter(tx, other) {
- return { orphan: "reorder-transaction", tx, other };
- }
- function createRemovedTransactionFilter(tx) {
- return { orphan: "drop-transaction", tx };
- }
- function createRemovedLogFilter(log) {
- return { orphan: "drop-log", log: {
- transactionHash: log.transactionHash,
- blockHash: log.blockHash,
- blockNumber: log.blockNumber,
- address: log.address,
- data: log.data,
- topics: Object.freeze(log.topics.slice()),
- index: log.index
- } };
- }
- // import from provider.ts instead of index.ts to prevent circular dep
- // from EtherscanProvider
- /**
- * An **EventLog** contains additional properties parsed from the [[Log]].
- */
- class EventLog extends Log {
- /**
- * The Contract Interface.
- */
- interface;
- /**
- * The matching event.
- */
- fragment;
- /**
- * The parsed arguments passed to the event by ``emit``.
- */
- args;
- /**
- * @_ignore:
- */
- constructor(log, iface, fragment) {
- super(log, log.provider);
- const args = iface.decodeEventLog(fragment, log.data, log.topics);
- defineProperties(this, { args, fragment, interface: iface });
- }
- /**
- * The name of the event.
- */
- get eventName() { return this.fragment.name; }
- /**
- * The signature of the event.
- */
- get eventSignature() { return this.fragment.format(); }
- }
- /**
- * An **EventLog** contains additional properties parsed from the [[Log]].
- */
- class UndecodedEventLog extends Log {
- /**
- * The error encounted when trying to decode the log.
- */
- error;
- /**
- * @_ignore:
- */
- constructor(log, error) {
- super(log, log.provider);
- defineProperties(this, { error });
- }
- }
- /**
- * A **ContractTransactionReceipt** includes the parsed logs from a
- * [[TransactionReceipt]].
- */
- class ContractTransactionReceipt extends TransactionReceipt {
- #iface;
- /**
- * @_ignore:
- */
- constructor(iface, provider, tx) {
- super(tx, provider);
- this.#iface = iface;
- }
- /**
- * The parsed logs for any [[Log]] which has a matching event in the
- * Contract ABI.
- */
- get logs() {
- return super.logs.map((log) => {
- const fragment = log.topics.length ? this.#iface.getEvent(log.topics[0]) : null;
- if (fragment) {
- try {
- return new EventLog(log, this.#iface, fragment);
- }
- catch (error) {
- return new UndecodedEventLog(log, error);
- }
- }
- return log;
- });
- }
- }
- /**
- * A **ContractTransactionResponse** will return a
- * [[ContractTransactionReceipt]] when waited on.
- */
- class ContractTransactionResponse extends TransactionResponse {
- #iface;
- /**
- * @_ignore:
- */
- constructor(iface, provider, tx) {
- super(tx, provider);
- this.#iface = iface;
- }
- /**
- * Resolves once this transaction has been mined and has
- * %%confirms%% blocks including it (default: ``1``) with an
- * optional %%timeout%%.
- *
- * This can resolve to ``null`` only if %%confirms%% is ``0``
- * and the transaction has not been mined, otherwise this will
- * wait until enough confirmations have completed.
- */
- async wait(confirms, timeout) {
- const receipt = await super.wait(confirms, timeout);
- if (receipt == null) {
- return null;
- }
- return new ContractTransactionReceipt(this.#iface, this.provider, receipt);
- }
- }
- /**
- * A **ContractUnknownEventPayload** is included as the last parameter to
- * Contract Events when the event does not match any events in the ABI.
- */
- class ContractUnknownEventPayload extends EventPayload {
- /**
- * The log with no matching events.
- */
- log;
- /**
- * @_event:
- */
- constructor(contract, listener, filter, log) {
- super(contract, listener, filter);
- defineProperties(this, { log });
- }
- /**
- * Resolves to the block the event occured in.
- */
- async getBlock() {
- return await this.log.getBlock();
- }
- /**
- * Resolves to the transaction the event occured in.
- */
- async getTransaction() {
- return await this.log.getTransaction();
- }
- /**
- * Resolves to the transaction receipt the event occured in.
- */
- async getTransactionReceipt() {
- return await this.log.getTransactionReceipt();
- }
- }
- /**
- * A **ContractEventPayload** is included as the last parameter to
- * Contract Events when the event is known.
- */
- class ContractEventPayload extends ContractUnknownEventPayload {
- /**
- * @_ignore:
- */
- constructor(contract, listener, filter, fragment, _log) {
- super(contract, listener, filter, new EventLog(_log, contract.interface, fragment));
- const args = contract.interface.decodeEventLog(fragment, this.log.data, this.log.topics);
- defineProperties(this, { args, fragment });
- }
- /**
- * The event name.
- */
- get eventName() {
- return this.fragment.name;
- }
- /**
- * The event signature.
- */
- get eventSignature() {
- return this.fragment.format();
- }
- }
- const BN_0$1 = BigInt(0);
- function canCall(value) {
- return (value && typeof (value.call) === "function");
- }
- function canEstimate(value) {
- return (value && typeof (value.estimateGas) === "function");
- }
- function canResolve(value) {
- return (value && typeof (value.resolveName) === "function");
- }
- function canSend(value) {
- return (value && typeof (value.sendTransaction) === "function");
- }
- function getResolver(value) {
- if (value != null) {
- if (canResolve(value)) {
- return value;
- }
- if (value.provider) {
- return value.provider;
- }
- }
- return undefined;
- }
- class PreparedTopicFilter {
- #filter;
- fragment;
- constructor(contract, fragment, args) {
- defineProperties(this, { fragment });
- if (fragment.inputs.length < args.length) {
- throw new Error("too many arguments");
- }
- // Recursively descend into args and resolve any addresses
- const runner = getRunner(contract.runner, "resolveName");
- const resolver = canResolve(runner) ? runner : null;
- this.#filter = (async function () {
- const resolvedArgs = await Promise.all(fragment.inputs.map((param, index) => {
- const arg = args[index];
- if (arg == null) {
- return null;
- }
- return param.walkAsync(args[index], (type, value) => {
- if (type === "address") {
- if (Array.isArray(value)) {
- return Promise.all(value.map((v) => resolveAddress(v, resolver)));
- }
- return resolveAddress(value, resolver);
- }
- return value;
- });
- }));
- return contract.interface.encodeFilterTopics(fragment, resolvedArgs);
- })();
- }
- getTopicFilter() {
- return this.#filter;
- }
- }
- // A = Arguments passed in as a tuple
- // R = The result type of the call (i.e. if only one return type,
- // the qualified type, otherwise Result)
- // D = The type the default call will return (i.e. R for view/pure,
- // TransactionResponse otherwise)
- //export interface ContractMethod<A extends Array<any> = Array<any>, R = any, D extends R | ContractTransactionResponse = ContractTransactionResponse> {
- function getRunner(value, feature) {
- if (value == null) {
- return null;
- }
- if (typeof (value[feature]) === "function") {
- return value;
- }
- if (value.provider && typeof (value.provider[feature]) === "function") {
- return value.provider;
- }
- return null;
- }
- function getProvider(value) {
- if (value == null) {
- return null;
- }
- return value.provider || null;
- }
- /**
- * @_ignore:
- */
- async function copyOverrides(arg, allowed) {
- // Make sure the overrides passed in are a valid overrides object
- const _overrides = Typed.dereference(arg, "overrides");
- assertArgument(typeof (_overrides) === "object", "invalid overrides parameter", "overrides", arg);
- // Create a shallow copy (we'll deep-ify anything needed during normalizing)
- const overrides = copyRequest(_overrides);
- assertArgument(overrides.to == null || (allowed || []).indexOf("to") >= 0, "cannot override to", "overrides.to", overrides.to);
- assertArgument(overrides.data == null || (allowed || []).indexOf("data") >= 0, "cannot override data", "overrides.data", overrides.data);
- // Resolve any from
- if (overrides.from) {
- overrides.from = overrides.from;
- }
- return overrides;
- }
- /**
- * @_ignore:
- */
- async function resolveArgs(_runner, inputs, args) {
- // Recursively descend into args and resolve any addresses
- const runner = getRunner(_runner, "resolveName");
- const resolver = canResolve(runner) ? runner : null;
- return await Promise.all(inputs.map((param, index) => {
- return param.walkAsync(args[index], (type, value) => {
- value = Typed.dereference(value, type);
- if (type === "address") {
- return resolveAddress(value, resolver);
- }
- return value;
- });
- }));
- }
- function buildWrappedFallback(contract) {
- const populateTransaction = async function (overrides) {
- // If an overrides was passed in, copy it and normalize the values
- const tx = (await copyOverrides(overrides, ["data"]));
- tx.to = await contract.getAddress();
- if (tx.from) {
- tx.from = await resolveAddress(tx.from, getResolver(contract.runner));
- }
- const iface = contract.interface;
- const noValue = (getBigInt((tx.value || BN_0$1), "overrides.value") === BN_0$1);
- const noData = ((tx.data || "0x") === "0x");
- if (iface.fallback && !iface.fallback.payable && iface.receive && !noData && !noValue) {
- assertArgument(false, "cannot send data to receive or send value to non-payable fallback", "overrides", overrides);
- }
- assertArgument(iface.fallback || noData, "cannot send data to receive-only contract", "overrides.data", tx.data);
- // Only allow payable contracts to set non-zero value
- const payable = iface.receive || (iface.fallback && iface.fallback.payable);
- assertArgument(payable || noValue, "cannot send value to non-payable fallback", "overrides.value", tx.value);
- // Only allow fallback contracts to set non-empty data
- assertArgument(iface.fallback || noData, "cannot send data to receive-only contract", "overrides.data", tx.data);
- return tx;
- };
- const staticCall = async function (overrides) {
- const runner = getRunner(contract.runner, "call");
- assert(canCall(runner), "contract runner does not support calling", "UNSUPPORTED_OPERATION", { operation: "call" });
- const tx = await populateTransaction(overrides);
- try {
- return await runner.call(tx);
- }
- catch (error) {
- if (isCallException(error) && error.data) {
- throw contract.interface.makeError(error.data, tx);
- }
- throw error;
- }
- };
- const send = async function (overrides) {
- const runner = contract.runner;
- assert(canSend(runner), "contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", { operation: "sendTransaction" });
- const tx = await runner.sendTransaction(await populateTransaction(overrides));
- const provider = getProvider(contract.runner);
- // @TODO: the provider can be null; make a custom dummy provider that will throw a
- // meaningful error
- return new ContractTransactionResponse(contract.interface, provider, tx);
- };
- const estimateGas = async function (overrides) {
- const runner = getRunner(contract.runner, "estimateGas");
- assert(canEstimate(runner), "contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", { operation: "estimateGas" });
- return await runner.estimateGas(await populateTransaction(overrides));
- };
- const method = async (overrides) => {
- return await send(overrides);
- };
- defineProperties(method, {
- _contract: contract,
- estimateGas,
- populateTransaction,
- send, staticCall
- });
- return method;
- }
- function buildWrappedMethod(contract, key) {
- const getFragment = function (...args) {
- const fragment = contract.interface.getFunction(key, args);
- assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
- operation: "fragment",
- info: { key, args }
- });
- return fragment;
- };
- const populateTransaction = async function (...args) {
- const fragment = getFragment(...args);
- // If an overrides was passed in, copy it and normalize the values
- let overrides = {};
- if (fragment.inputs.length + 1 === args.length) {
- overrides = await copyOverrides(args.pop());
- if (overrides.from) {
- overrides.from = await resolveAddress(overrides.from, getResolver(contract.runner));
- }
- }
- if (fragment.inputs.length !== args.length) {
- throw new Error("internal error: fragment inputs doesn't match arguments; should not happen");
- }
- const resolvedArgs = await resolveArgs(contract.runner, fragment.inputs, args);
- return Object.assign({}, overrides, await resolveProperties({
- to: contract.getAddress(),
- data: contract.interface.encodeFunctionData(fragment, resolvedArgs)
- }));
- };
- const staticCall = async function (...args) {
- const result = await staticCallResult(...args);
- if (result.length === 1) {
- return result[0];
- }
- return result;
- };
- const send = async function (...args) {
- const runner = contract.runner;
- assert(canSend(runner), "contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", { operation: "sendTransaction" });
- const tx = await runner.sendTransaction(await populateTransaction(...args));
- const provider = getProvider(contract.runner);
- // @TODO: the provider can be null; make a custom dummy provider that will throw a
- // meaningful error
- return new ContractTransactionResponse(contract.interface, provider, tx);
- };
- const estimateGas = async function (...args) {
- const runner = getRunner(contract.runner, "estimateGas");
- assert(canEstimate(runner), "contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", { operation: "estimateGas" });
- return await runner.estimateGas(await populateTransaction(...args));
- };
- const staticCallResult = async function (...args) {
- const runner = getRunner(contract.runner, "call");
- assert(canCall(runner), "contract runner does not support calling", "UNSUPPORTED_OPERATION", { operation: "call" });
- const tx = await populateTransaction(...args);
- let result = "0x";
- try {
- result = await runner.call(tx);
- }
- catch (error) {
- if (isCallException(error) && error.data) {
- throw contract.interface.makeError(error.data, tx);
- }
- throw error;
- }
- const fragment = getFragment(...args);
- return contract.interface.decodeFunctionResult(fragment, result);
- };
- const method = async (...args) => {
- const fragment = getFragment(...args);
- if (fragment.constant) {
- return await staticCall(...args);
- }
- return await send(...args);
- };
- defineProperties(method, {
- name: contract.interface.getFunctionName(key),
- _contract: contract, _key: key,
- getFragment,
- estimateGas,
- populateTransaction,
- send, staticCall, staticCallResult,
- });
- // Only works on non-ambiguous keys (refined fragment is always non-ambiguous)
- Object.defineProperty(method, "fragment", {
- configurable: false,
- enumerable: true,
- get: () => {
- const fragment = contract.interface.getFunction(key);
- assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
- operation: "fragment",
- info: { key }
- });
- return fragment;
- }
- });
- return method;
- }
- function buildWrappedEvent(contract, key) {
- const getFragment = function (...args) {
- const fragment = contract.interface.getEvent(key, args);
- assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
- operation: "fragment",
- info: { key, args }
- });
- return fragment;
- };
- const method = function (...args) {
- return new PreparedTopicFilter(contract, getFragment(...args), args);
- };
- defineProperties(method, {
- name: contract.interface.getEventName(key),
- _contract: contract, _key: key,
- getFragment
- });
- // Only works on non-ambiguous keys (refined fragment is always non-ambiguous)
- Object.defineProperty(method, "fragment", {
- configurable: false,
- enumerable: true,
- get: () => {
- const fragment = contract.interface.getEvent(key);
- assert(fragment, "no matching fragment", "UNSUPPORTED_OPERATION", {
- operation: "fragment",
- info: { key }
- });
- return fragment;
- }
- });
- return method;
- }
- // The combination of TypeScrype, Private Fields and Proxies makes
- // the world go boom; so we hide variables with some trickery keeping
- // a symbol attached to each BaseContract which its sub-class (even
- // via a Proxy) can reach and use to look up its internal values.
- const internal = Symbol.for("_ethersInternal_contract");
- const internalValues = new WeakMap();
- function setInternal(contract, values) {
- internalValues.set(contract[internal], values);
- }
- function getInternal(contract) {
- return internalValues.get(contract[internal]);
- }
- function isDeferred(value) {
- return (value && typeof (value) === "object" && ("getTopicFilter" in value) &&
- (typeof (value.getTopicFilter) === "function") && value.fragment);
- }
- async function getSubInfo(contract, event) {
- let topics;
- let fragment = null;
- // Convert named events to topicHash and get the fragment for
- // events which need deconstructing.
- if (Array.isArray(event)) {
- const topicHashify = function (name) {
- if (isHexString(name, 32)) {
- return name;
- }
- const fragment = contract.interface.getEvent(name);
- assertArgument(fragment, "unknown fragment", "name", name);
- return fragment.topicHash;
- };
- // Array of Topics and Names; e.g. `[ "0x1234...89ab", "Transfer(address)" ]`
- topics = event.map((e) => {
- if (e == null) {
- return null;
- }
- if (Array.isArray(e)) {
- return e.map(topicHashify);
- }
- return topicHashify(e);
- });
- }
- else if (event === "*") {
- topics = [null];
- }
- else if (typeof (event) === "string") {
- if (isHexString(event, 32)) {
- // Topic Hash
- topics = [event];
- }
- else {
- // Name or Signature; e.g. `"Transfer", `"Transfer(address)"`
- fragment = contract.interface.getEvent(event);
- assertArgument(fragment, "unknown fragment", "event", event);
- topics = [fragment.topicHash];
- }
- }
- else if (isDeferred(event)) {
- // Deferred Topic Filter; e.g. `contract.filter.Transfer(from)`
- topics = await event.getTopicFilter();
- }
- else if ("fragment" in event) {
- // ContractEvent; e.g. `contract.filter.Transfer`
- fragment = event.fragment;
- topics = [fragment.topicHash];
- }
- else {
- assertArgument(false, "unknown event name", "event", event);
- }
- // Normalize topics and sort TopicSets
- topics = topics.map((t) => {
- if (t == null) {
- return null;
- }
- if (Array.isArray(t)) {
- const items = Array.from(new Set(t.map((t) => t.toLowerCase())).values());
- if (items.length === 1) {
- return items[0];
- }
- items.sort();
- return items;
- }
- return t.toLowerCase();
- });
- const tag = topics.map((t) => {
- if (t == null) {
- return "null";
- }
- if (Array.isArray(t)) {
- return t.join("|");
- }
- return t;
- }).join("&");
- return { fragment, tag, topics };
- }
- async function hasSub(contract, event) {
- const { subs } = getInternal(contract);
- return subs.get((await getSubInfo(contract, event)).tag) || null;
- }
- async function getSub(contract, operation, event) {
- // Make sure our runner can actually subscribe to events
- const provider = getProvider(contract.runner);
- assert(provider, "contract runner does not support subscribing", "UNSUPPORTED_OPERATION", { operation });
- const { fragment, tag, topics } = await getSubInfo(contract, event);
- const { addr, subs } = getInternal(contract);
- let sub = subs.get(tag);
- if (!sub) {
- const address = (addr ? addr : contract);
- const filter = { address, topics };
- const listener = (log) => {
- let foundFragment = fragment;
- if (foundFragment == null) {
- try {
- foundFragment = contract.interface.getEvent(log.topics[0]);
- }
- catch (error) { }
- }
- // If fragment is null, we do not deconstruct the args to emit
- if (foundFragment) {
- const _foundFragment = foundFragment;
- const args = fragment ? contract.interface.decodeEventLog(fragment, log.data, log.topics) : [];
- emit(contract, event, args, (listener) => {
- return new ContractEventPayload(contract, listener, event, _foundFragment, log);
- });
- }
- else {
- emit(contract, event, [], (listener) => {
- return new ContractUnknownEventPayload(contract, listener, event, log);
- });
- }
- };
- let starting = [];
- const start = () => {
- if (starting.length) {
- return;
- }
- starting.push(provider.on(filter, listener));
- };
- const stop = async () => {
- if (starting.length == 0) {
- return;
- }
- let started = starting;
- starting = [];
- await Promise.all(started);
- provider.off(filter, listener);
- };
- sub = { tag, listeners: [], start, stop };
- subs.set(tag, sub);
- }
- return sub;
- }
- // We use this to ensure one emit resolves before firing the next to
- // ensure correct ordering (note this cannot throw and just adds the
- // notice to the event queu using setTimeout).
- let lastEmit = Promise.resolve();
- async function _emit(contract, event, args, payloadFunc) {
- await lastEmit;
- const sub = await hasSub(contract, event);
- if (!sub) {
- return false;
- }
- const count = sub.listeners.length;
- sub.listeners = sub.listeners.filter(({ listener, once }) => {
- const passArgs = Array.from(args);
- if (payloadFunc) {
- passArgs.push(payloadFunc(once ? null : listener));
- }
- try {
- listener.call(contract, ...passArgs);
- }
- catch (error) { }
- return !once;
- });
- if (sub.listeners.length === 0) {
- sub.stop();
- getInternal(contract).subs.delete(sub.tag);
- }
- return (count > 0);
- }
- async function emit(contract, event, args, payloadFunc) {
- try {
- await lastEmit;
- }
- catch (error) { }
- const resultPromise = _emit(contract, event, args, payloadFunc);
- lastEmit = resultPromise;
- return await resultPromise;
- }
- const passProperties = ["then"];
- class BaseContract {
- /**
- * The target to connect to.
- *
- * This can be an address, ENS name or any [[Addressable]], such as
- * another contract. To get the resovled address, use the ``getAddress``
- * method.
- */
- target;
- /**
- * The contract Interface.
- */
- interface;
- /**
- * The connected runner. This is generally a [[Provider]] or a
- * [[Signer]], which dictates what operations are supported.
- *
- * For example, a **Contract** connected to a [[Provider]] may
- * only execute read-only operations.
- */
- runner;
- /**
- * All the Events available on this contract.
- */
- filters;
- /**
- * @_ignore:
- */
- [internal];
- /**
- * The fallback or receive function if any.
- */
- fallback;
- /**
- * Creates a new contract connected to %%target%% with the %%abi%% and
- * optionally connected to a %%runner%% to perform operations on behalf
- * of.
- */
- constructor(target, abi, runner, _deployTx) {
- assertArgument(typeof (target) === "string" || isAddressable(target), "invalid value for Contract target", "target", target);
- if (runner == null) {
- runner = null;
- }
- const iface = Interface.from(abi);
- defineProperties(this, { target, runner, interface: iface });
- Object.defineProperty(this, internal, { value: {} });
- let addrPromise;
- let addr = null;
- let deployTx = null;
- if (_deployTx) {
- const provider = getProvider(runner);
- // @TODO: the provider can be null; make a custom dummy provider that will throw a
- // meaningful error
- deployTx = new ContractTransactionResponse(this.interface, provider, _deployTx);
- }
- let subs = new Map();
- // Resolve the target as the address
- if (typeof (target) === "string") {
- if (isHexString(target)) {
- addr = target;
- addrPromise = Promise.resolve(target);
- }
- else {
- const resolver = getRunner(runner, "resolveName");
- if (!canResolve(resolver)) {
- throw makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
- operation: "resolveName"
- });
- }
- addrPromise = resolver.resolveName(target).then((addr) => {
- if (addr == null) {
- throw makeError("an ENS name used for a contract target must be correctly configured", "UNCONFIGURED_NAME", {
- value: target
- });
- }
- getInternal(this).addr = addr;
- return addr;
- });
- }
- }
- else {
- addrPromise = target.getAddress().then((addr) => {
- if (addr == null) {
- throw new Error("TODO");
- }
- getInternal(this).addr = addr;
- return addr;
- });
- }
- // Set our private values
- setInternal(this, { addrPromise, addr, deployTx, subs });
- // Add the event filters
- const filters = new Proxy({}, {
- get: (target, prop, receiver) => {
- // Pass important checks (like `then` for Promise) through
- if (typeof (prop) === "symbol" || passProperties.indexOf(prop) >= 0) {
- return Reflect.get(target, prop, receiver);
- }
- try {
- return this.getEvent(prop);
- }
- catch (error) {
- if (!isError(error, "INVALID_ARGUMENT") || error.argument !== "key") {
- throw error;
- }
- }
- return undefined;
- },
- has: (target, prop) => {
- // Pass important checks (like `then` for Promise) through
- if (passProperties.indexOf(prop) >= 0) {
- return Reflect.has(target, prop);
- }
- return Reflect.has(target, prop) || this.interface.hasEvent(String(prop));
- }
- });
- defineProperties(this, { filters });
- defineProperties(this, {
- fallback: ((iface.receive || iface.fallback) ? (buildWrappedFallback(this)) : null)
- });
- // Return a Proxy that will respond to functions
- return new Proxy(this, {
- get: (target, prop, receiver) => {
- if (typeof (prop) === "symbol" || prop in target || passProperties.indexOf(prop) >= 0) {
- return Reflect.get(target, prop, receiver);
- }
- // Undefined properties should return undefined
- try {
- return target.getFunction(prop);
- }
- catch (error) {
- if (!isError(error, "INVALID_ARGUMENT") || error.argument !== "key") {
- throw error;
- }
- }
- return undefined;
- },
- has: (target, prop) => {
- if (typeof (prop) === "symbol" || prop in target || passProperties.indexOf(prop) >= 0) {
- return Reflect.has(target, prop);
- }
- return target.interface.hasFunction(prop);
- }
- });
- }
- /**
- * Return a new Contract instance with the same target and ABI, but
- * a different %%runner%%.
- */
- connect(runner) {
- return new BaseContract(this.target, this.interface, runner);
- }
- /**
- * Return a new Contract instance with the same ABI and runner, but
- * a different %%target%%.
- */
- attach(target) {
- return new BaseContract(target, this.interface, this.runner);
- }
- /**
- * Return the resolved address of this Contract.
- */
- async getAddress() { return await getInternal(this).addrPromise; }
- /**
- * Return the deployed bytecode or null if no bytecode is found.
- */
- async getDeployedCode() {
- const provider = getProvider(this.runner);
- assert(provider, "runner does not support .provider", "UNSUPPORTED_OPERATION", { operation: "getDeployedCode" });
- const code = await provider.getCode(await this.getAddress());
- if (code === "0x") {
- return null;
- }
- return code;
- }
- /**
- * Resolve to this Contract once the bytecode has been deployed, or
- * resolve immediately if already deployed.
- */
- async waitForDeployment() {
- // We have the deployement transaction; just use that (throws if deployement fails)
- const deployTx = this.deploymentTransaction();
- if (deployTx) {
- await deployTx.wait();
- return this;
- }
- // Check for code
- const code = await this.getDeployedCode();
- if (code != null) {
- return this;
- }
- // Make sure we can subscribe to a provider event
- const provider = getProvider(this.runner);
- assert(provider != null, "contract runner does not support .provider", "UNSUPPORTED_OPERATION", { operation: "waitForDeployment" });
- return new Promise((resolve, reject) => {
- const checkCode = async () => {
- try {
- const code = await this.getDeployedCode();
- if (code != null) {
- return resolve(this);
- }
- provider.once("block", checkCode);
- }
- catch (error) {
- reject(error);
- }
- };
- checkCode();
- });
- }
- /**
- * Return the transaction used to deploy this contract.
- *
- * This is only available if this instance was returned from a
- * [[ContractFactory]].
- */
- deploymentTransaction() {
- return getInternal(this).deployTx;
- }
- /**
- * Return the function for a given name. This is useful when a contract
- * method name conflicts with a JavaScript name such as ``prototype`` or
- * when using a Contract programatically.
- */
- getFunction(key) {
- if (typeof (key) !== "string") {
- key = key.format();
- }
- const func = buildWrappedMethod(this, key);
- return func;
- }
- /**
- * Return the event for a given name. This is useful when a contract
- * event name conflicts with a JavaScript name such as ``prototype`` or
- * when using a Contract programatically.
- */
- getEvent(key) {
- if (typeof (key) !== "string") {
- key = key.format();
- }
- return buildWrappedEvent(this, key);
- }
- /**
- * @_ignore:
- */
- async queryTransaction(hash) {
- throw new Error("@TODO");
- }
- /*
- // @TODO: this is a non-backwards compatible change, but will be added
- // in v7 and in a potential SmartContract class in an upcoming
- // v6 release
- async getTransactionReceipt(hash: string): Promise<null | ContractTransactionReceipt> {
- const provider = getProvider(this.runner);
- assert(provider, "contract runner does not have a provider",
- "UNSUPPORTED_OPERATION", { operation: "queryTransaction" });
- const receipt = await provider.getTransactionReceipt(hash);
- if (receipt == null) { return null; }
- return new ContractTransactionReceipt(this.interface, provider, receipt);
- }
- */
- /**
- * Provide historic access to event data for %%event%% in the range
- * %%fromBlock%% (default: ``0``) to %%toBlock%% (default: ``"latest"``)
- * inclusive.
- */
- async queryFilter(event, fromBlock, toBlock) {
- if (fromBlock == null) {
- fromBlock = 0;
- }
- if (toBlock == null) {
- toBlock = "latest";
- }
- const { addr, addrPromise } = getInternal(this);
- const address = (addr ? addr : (await addrPromise));
- const { fragment, topics } = await getSubInfo(this, event);
- const filter = { address, topics, fromBlock, toBlock };
- const provider = getProvider(this.runner);
- assert(provider, "contract runner does not have a provider", "UNSUPPORTED_OPERATION", { operation: "queryFilter" });
- return (await provider.getLogs(filter)).map((log) => {
- let foundFragment = fragment;
- if (foundFragment == null) {
- try {
- foundFragment = this.interface.getEvent(log.topics[0]);
- }
- catch (error) { }
- }
- if (foundFragment) {
- try {
- return new EventLog(log, this.interface, foundFragment);
- }
- catch (error) {
- return new UndecodedEventLog(log, error);
- }
- }
- return new Log(log, provider);
- });
- }
- /**
- * Add an event %%listener%% for the %%event%%.
- */
- async on(event, listener) {
- const sub = await getSub(this, "on", event);
- sub.listeners.push({ listener, once: false });
- sub.start();
- return this;
- }
- /**
- * Add an event %%listener%% for the %%event%%, but remove the listener
- * after it is fired once.
- */
- async once(event, listener) {
- const sub = await getSub(this, "once", event);
- sub.listeners.push({ listener, once: true });
- sub.start();
- return this;
- }
- /**
- * Emit an %%event%% calling all listeners with %%args%%.
- *
- * Resolves to ``true`` if any listeners were called.
- */
- async emit(event, ...args) {
- return await emit(this, event, args, null);
- }
- /**
- * Resolves to the number of listeners of %%event%% or the total number
- * of listeners if unspecified.
- */
- async listenerCount(event) {
- if (event) {
- const sub = await hasSub(this, event);
- if (!sub) {
- return 0;
- }
- return sub.listeners.length;
- }
- const { subs } = getInternal(this);
- let total = 0;
- for (const { listeners } of subs.values()) {
- total += listeners.length;
- }
- return total;
- }
- /**
- * Resolves to the listeners subscribed to %%event%% or all listeners
- * if unspecified.
- */
- async listeners(event) {
- if (event) {
- const sub = await hasSub(this, event);
- if (!sub) {
- return [];
- }
- return sub.listeners.map(({ listener }) => listener);
- }
- const { subs } = getInternal(this);
- let result = [];
- for (const { listeners } of subs.values()) {
- result = result.concat(listeners.map(({ listener }) => listener));
- }
- return result;
- }
- /**
- * Remove the %%listener%% from the listeners for %%event%% or remove
- * all listeners if unspecified.
- */
- async off(event, listener) {
- const sub = await hasSub(this, event);
- if (!sub) {
- return this;
- }
- if (listener) {
- const index = sub.listeners.map(({ listener }) => listener).indexOf(listener);
- if (index >= 0) {
- sub.listeners.splice(index, 1);
- }
- }
- if (listener == null || sub.listeners.length === 0) {
- sub.stop();
- getInternal(this).subs.delete(sub.tag);
- }
- return this;
- }
- /**
- * Remove all the listeners for %%event%% or remove all listeners if
- * unspecified.
- */
- async removeAllListeners(event) {
- if (event) {
- const sub = await hasSub(this, event);
- if (!sub) {
- return this;
- }
- sub.stop();
- getInternal(this).subs.delete(sub.tag);
- }
- else {
- const { subs } = getInternal(this);
- for (const { tag, stop } of subs.values()) {
- stop();
- subs.delete(tag);
- }
- }
- return this;
- }
- /**
- * Alias for [on].
- */
- async addListener(event, listener) {
- return await this.on(event, listener);
- }
- /**
- * Alias for [off].
- */
- async removeListener(event, listener) {
- return await this.off(event, listener);
- }
- /**
- * Create a new Class for the %%abi%%.
- */
- static buildClass(abi) {
- class CustomContract extends BaseContract {
- constructor(address, runner = null) {
- super(address, abi, runner);
- }
- }
- return CustomContract;
- }
- ;
- /**
- * Create a new BaseContract with a specified Interface.
- */
- static from(target, abi, runner) {
- if (runner == null) {
- runner = null;
- }
- const contract = new this(target, abi, runner);
- return contract;
- }
- }
- function _ContractBase() {
- return BaseContract;
- }
- /**
- * A [[BaseContract]] with no type guards on its methods or events.
- */
- class Contract extends _ContractBase() {
- }
- // A = Arguments to the constructor
- // I = Interface of deployed contracts
- /**
- * A **ContractFactory** is used to deploy a Contract to the blockchain.
- */
- class ContractFactory {
- /**
- * The Contract Interface.
- */
- interface;
- /**
- * The Contract deployment bytecode. Often called the initcode.
- */
- bytecode;
- /**
- * The ContractRunner to deploy the Contract as.
- */
- runner;
- /**
- * Create a new **ContractFactory** with %%abi%% and %%bytecode%%,
- * optionally connected to %%runner%%.
- *
- * The %%bytecode%% may be the ``bytecode`` property within the
- * standard Solidity JSON output.
- */
- constructor(abi, bytecode, runner) {
- const iface = Interface.from(abi);
- // Dereference Solidity bytecode objects and allow a missing `0x`-prefix
- if (bytecode instanceof Uint8Array) {
- bytecode = hexlify(getBytes(bytecode));
- }
- else {
- if (typeof (bytecode) === "object") {
- bytecode = bytecode.object;
- }
- if (!bytecode.startsWith("0x")) {
- bytecode = "0x" + bytecode;
- }
- bytecode = hexlify(getBytes(bytecode));
- }
- defineProperties(this, {
- bytecode, interface: iface, runner: (runner || null)
- });
- }
- attach(target) {
- return new BaseContract(target, this.interface, this.runner);
- }
- /**
- * Resolves to the transaction to deploy the contract, passing %%args%%
- * into the constructor.
- */
- async getDeployTransaction(...args) {
- let overrides = {};
- const fragment = this.interface.deploy;
- if (fragment.inputs.length + 1 === args.length) {
- overrides = await copyOverrides(args.pop());
- }
- if (fragment.inputs.length !== args.length) {
- throw new Error("incorrect number of arguments to constructor");
- }
- const resolvedArgs = await resolveArgs(this.runner, fragment.inputs, args);
- const data = concat([this.bytecode, this.interface.encodeDeploy(resolvedArgs)]);
- return Object.assign({}, overrides, { data });
- }
- /**
- * Resolves to the Contract deployed by passing %%args%% into the
- * constructor.
- *
- * This will resolve to the Contract before it has been deployed to the
- * network, so the [[BaseContract-waitForDeployment]] should be used before
- * sending any transactions to it.
- */
- async deploy(...args) {
- const tx = await this.getDeployTransaction(...args);
- assert(this.runner && typeof (this.runner.sendTransaction) === "function", "factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
- operation: "sendTransaction"
- });
- const sentTx = await this.runner.sendTransaction(tx);
- const address = getCreateAddress(sentTx);
- return new BaseContract(address, this.interface, this.runner, sentTx);
- }
- /**
- * Return a new **ContractFactory** with the same ABI and bytecode,
- * but connected to %%runner%%.
- */
- connect(runner) {
- return new ContractFactory(this.interface, this.bytecode, runner);
- }
- /**
- * Create a new **ContractFactory** from the standard Solidity JSON output.
- */
- static fromSolidity(output, runner) {
- assertArgument(output != null, "bad compiler output", "output", output);
- if (typeof (output) === "string") {
- output = JSON.parse(output);
- }
- const abi = output.abi;
- let bytecode = "";
- if (output.bytecode) {
- bytecode = output.bytecode;
- }
- else if (output.evm && output.evm.bytecode) {
- bytecode = output.evm.bytecode;
- }
- return new this(abi, bytecode, runner);
- }
- }
- /**
- * ENS is a service which allows easy-to-remember names to map to
- * network addresses.
- *
- * @_section: api/providers/ens-resolver:ENS Resolver [about-ens-rsolver]
- */
- // @TODO: This should use the fetch-data:ipfs gateway
- // Trim off the ipfs:// prefix and return the default gateway URL
- function getIpfsLink(link) {
- if (link.match(/^ipfs:\/\/ipfs\//i)) {
- link = link.substring(12);
- }
- else if (link.match(/^ipfs:\/\//i)) {
- link = link.substring(7);
- }
- else {
- assertArgument(false, "unsupported IPFS format", "link", link);
- }
- return `https:/\/gateway.ipfs.io/ipfs/${link}`;
- }
- /**
- * A provider plugin super-class for processing multicoin address types.
- */
- class MulticoinProviderPlugin {
- /**
- * The name.
- */
- name;
- /**
- * Creates a new **MulticoinProviderPluing** for %%name%%.
- */
- constructor(name) {
- defineProperties(this, { name });
- }
- connect(proivder) {
- return this;
- }
- /**
- * Returns ``true`` if %%coinType%% is supported by this plugin.
- */
- supportsCoinType(coinType) {
- return false;
- }
- /**
- * Resolves to the encoded %%address%% for %%coinType%%.
- */
- async encodeAddress(coinType, address) {
- throw new Error("unsupported coin");
- }
- /**
- * Resolves to the decoded %%data%% for %%coinType%%.
- */
- async decodeAddress(coinType, data) {
- throw new Error("unsupported coin");
- }
- }
- const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
- const matchers = [
- new RegExp("^(https):/\/(.*)$", "i"),
- new RegExp("^(data):(.*)$", "i"),
- matcherIpfs,
- new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
- ];
- /**
- * A connected object to a resolved ENS name resolver, which can be
- * used to query additional details.
- */
- class EnsResolver {
- /**
- * The connected provider.
- */
- provider;
- /**
- * The address of the resolver.
- */
- address;
- /**
- * The name this resolver was resolved against.
- */
- name;
- // For EIP-2544 names, the ancestor that provided the resolver
- #supports2544;
- #resolver;
- constructor(provider, address, name) {
- defineProperties(this, { provider, address, name });
- this.#supports2544 = null;
- this.#resolver = new Contract(address, [
- "function supportsInterface(bytes4) view returns (bool)",
- "function resolve(bytes, bytes) view returns (bytes)",
- "function addr(bytes32) view returns (address)",
- "function addr(bytes32, uint) view returns (bytes)",
- "function text(bytes32, string) view returns (string)",
- "function contenthash(bytes32) view returns (bytes)",
- ], provider);
- }
- /**
- * Resolves to true if the resolver supports wildcard resolution.
- */
- async supportsWildcard() {
- if (this.#supports2544 == null) {
- this.#supports2544 = (async () => {
- try {
- return await this.#resolver.supportsInterface("0x9061b923");
- }
- catch (error) {
- // Wildcard resolvers must understand supportsInterface
- // and return true.
- if (isError(error, "CALL_EXCEPTION")) {
- return false;
- }
- // Let future attempts try again...
- this.#supports2544 = null;
- throw error;
- }
- })();
- }
- return await this.#supports2544;
- }
- async #fetch(funcName, params) {
- params = (params || []).slice();
- const iface = this.#resolver.interface;
- // The first parameters is always the nodehash
- params.unshift(namehash(this.name));
- let fragment = null;
- if (await this.supportsWildcard()) {
- fragment = iface.getFunction(funcName);
- assert(fragment, "missing fragment", "UNKNOWN_ERROR", {
- info: { funcName }
- });
- params = [
- dnsEncode(this.name, 255),
- iface.encodeFunctionData(fragment, params)
- ];
- funcName = "resolve(bytes,bytes)";
- }
- params.push({
- enableCcipRead: true
- });
- try {
- const result = await this.#resolver[funcName](...params);
- if (fragment) {
- return iface.decodeFunctionResult(fragment, result)[0];
- }
- return result;
- }
- catch (error) {
- if (!isError(error, "CALL_EXCEPTION")) {
- throw error;
- }
- }
- return null;
- }
- /**
- * Resolves to the address for %%coinType%% or null if the
- * provided %%coinType%% has not been configured.
- */
- async getAddress(coinType) {
- if (coinType == null) {
- coinType = 60;
- }
- if (coinType === 60) {
- try {
- const result = await this.#fetch("addr(bytes32)");
- // No address
- if (result == null || result === ZeroAddress) {
- return null;
- }
- return result;
- }
- catch (error) {
- if (isError(error, "CALL_EXCEPTION")) {
- return null;
- }
- throw error;
- }
- }
- // Try decoding its EVM canonical chain as an EVM chain address first
- if (coinType >= 0 && coinType < 0x80000000) {
- let ethCoinType = coinType + 0x80000000;
- const data = await this.#fetch("addr(bytes32,uint)", [ethCoinType]);
- if (isHexString(data, 20)) {
- return getAddress(data);
- }
- }
- let coinPlugin = null;
- for (const plugin of this.provider.plugins) {
- if (!(plugin instanceof MulticoinProviderPlugin)) {
- continue;
- }
- if (plugin.supportsCoinType(coinType)) {
- coinPlugin = plugin;
- break;
- }
- }
- if (coinPlugin == null) {
- return null;
- }
- // keccak256("addr(bytes32,uint256")
- const data = await this.#fetch("addr(bytes32,uint)", [coinType]);
- // No address
- if (data == null || data === "0x") {
- return null;
- }
- // Compute the address
- const address = await coinPlugin.decodeAddress(coinType, data);
- if (address != null) {
- return address;
- }
- assert(false, `invalid coin data`, "UNSUPPORTED_OPERATION", {
- operation: `getAddress(${coinType})`,
- info: { coinType, data }
- });
- }
- /**
- * Resolves to the EIP-634 text record for %%key%%, or ``null``
- * if unconfigured.
- */
- async getText(key) {
- const data = await this.#fetch("text(bytes32,string)", [key]);
- if (data == null || data === "0x") {
- return null;
- }
- return data;
- }
- /**
- * Rsolves to the content-hash or ``null`` if unconfigured.
- */
- async getContentHash() {
- // keccak256("contenthash()")
- const data = await this.#fetch("contenthash(bytes32)");
- // No contenthash
- if (data == null || data === "0x") {
- return null;
- }
- // IPFS (CID: 1, Type: 70=DAG-PB, 72=libp2p-key)
- const ipfs = data.match(/^0x(e3010170|e5010172)(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/);
- if (ipfs) {
- const scheme = (ipfs[1] === "e3010170") ? "ipfs" : "ipns";
- const length = parseInt(ipfs[4], 16);
- if (ipfs[5].length === length * 2) {
- return `${scheme}:/\/${encodeBase58("0x" + ipfs[2])}`;
- }
- }
- // Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
- const swarm = data.match(/^0xe40101fa011b20([0-9a-f]*)$/);
- if (swarm && swarm[1].length === 64) {
- return `bzz:/\/${swarm[1]}`;
- }
- assert(false, `invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
- operation: "getContentHash()",
- info: { data }
- });
- }
- /**
- * Resolves to the avatar url or ``null`` if the avatar is either
- * unconfigured or incorrectly configured (e.g. references an NFT
- * not owned by the address).
- *
- * If diagnosing issues with configurations, the [[_getAvatar]]
- * method may be useful.
- */
- async getAvatar() {
- const avatar = await this._getAvatar();
- return avatar.url;
- }
- /**
- * When resolving an avatar, there are many steps involved, such
- * fetching metadata and possibly validating ownership of an
- * NFT.
- *
- * This method can be used to examine each step and the value it
- * was working from.
- */
- async _getAvatar() {
- const linkage = [{ type: "name", value: this.name }];
- try {
- // test data for ricmoo.eth
- //const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
- const avatar = await this.getText("avatar");
- if (avatar == null) {
- linkage.push({ type: "!avatar", value: "" });
- return { url: null, linkage };
- }
- linkage.push({ type: "avatar", value: avatar });
- for (let i = 0; i < matchers.length; i++) {
- const match = avatar.match(matchers[i]);
- if (match == null) {
- continue;
- }
- const scheme = match[1].toLowerCase();
- switch (scheme) {
- case "https":
- case "data":
- linkage.push({ type: "url", value: avatar });
- return { linkage, url: avatar };
- case "ipfs": {
- const url = getIpfsLink(avatar);
- linkage.push({ type: "ipfs", value: avatar });
- linkage.push({ type: "url", value: url });
- return { linkage, url };
- }
- case "erc721":
- case "erc1155": {
- // Depending on the ERC type, use tokenURI(uint256) or url(uint256)
- const selector = (scheme === "erc721") ? "tokenURI(uint256)" : "uri(uint256)";
- linkage.push({ type: scheme, value: avatar });
- // The owner of this name
- const owner = await this.getAddress();
- if (owner == null) {
- linkage.push({ type: "!owner", value: "" });
- return { url: null, linkage };
- }
- const comps = (match[2] || "").split("/");
- if (comps.length !== 2) {
- linkage.push({ type: `!${scheme}caip`, value: (match[2] || "") });
- return { url: null, linkage };
- }
- const tokenId = comps[1];
- const contract = new Contract(comps[0], [
- // ERC-721
- "function tokenURI(uint) view returns (string)",
- "function ownerOf(uint) view returns (address)",
- // ERC-1155
- "function uri(uint) view returns (string)",
- "function balanceOf(address, uint256) view returns (uint)"
- ], this.provider);
- // Check that this account owns the token
- if (scheme === "erc721") {
- const tokenOwner = await contract.ownerOf(tokenId);
- if (owner !== tokenOwner) {
- linkage.push({ type: "!owner", value: tokenOwner });
- return { url: null, linkage };
- }
- linkage.push({ type: "owner", value: tokenOwner });
- }
- else if (scheme === "erc1155") {
- const balance = await contract.balanceOf(owner, tokenId);
- if (!balance) {
- linkage.push({ type: "!balance", value: "0" });
- return { url: null, linkage };
- }
- linkage.push({ type: "balance", value: balance.toString() });
- }
- // Call the token contract for the metadata URL
- let metadataUrl = await contract[selector](tokenId);
- if (metadataUrl == null || metadataUrl === "0x") {
- linkage.push({ type: "!metadata-url", value: "" });
- return { url: null, linkage };
- }
- linkage.push({ type: "metadata-url-base", value: metadataUrl });
- // ERC-1155 allows a generic {id} in the URL
- if (scheme === "erc1155") {
- metadataUrl = metadataUrl.replace("{id}", toBeHex(tokenId, 32).substring(2));
- linkage.push({ type: "metadata-url-expanded", value: metadataUrl });
- }
- // Transform IPFS metadata links
- if (metadataUrl.match(/^ipfs:/i)) {
- metadataUrl = getIpfsLink(metadataUrl);
- }
- linkage.push({ type: "metadata-url", value: metadataUrl });
- // Get the token metadata
- let metadata = {};
- const response = await (new FetchRequest(metadataUrl)).send();
- response.assertOk();
- try {
- metadata = response.bodyJson;
- }
- catch (error) {
- try {
- linkage.push({ type: "!metadata", value: response.bodyText });
- }
- catch (error) {
- const bytes = response.body;
- if (bytes) {
- linkage.push({ type: "!metadata", value: hexlify(bytes) });
- }
- return { url: null, linkage };
- }
- return { url: null, linkage };
- }
- if (!metadata) {
- linkage.push({ type: "!metadata", value: "" });
- return { url: null, linkage };
- }
- linkage.push({ type: "metadata", value: JSON.stringify(metadata) });
- // Pull the image URL out
- let imageUrl = metadata.image;
- if (typeof (imageUrl) !== "string") {
- linkage.push({ type: "!imageUrl", value: "" });
- return { url: null, linkage };
- }
- if (imageUrl.match(/^(https:\/\/|data:)/i)) {
- // Allow
- }
- else {
- // Transform IPFS link to gateway
- const ipfs = imageUrl.match(matcherIpfs);
- if (ipfs == null) {
- linkage.push({ type: "!imageUrl-ipfs", value: imageUrl });
- return { url: null, linkage };
- }
- linkage.push({ type: "imageUrl-ipfs", value: imageUrl });
- imageUrl = getIpfsLink(imageUrl);
- }
- linkage.push({ type: "url", value: imageUrl });
- return { linkage, url: imageUrl };
- }
- }
- }
- }
- catch (error) { }
- return { linkage, url: null };
- }
- static async getEnsAddress(provider) {
- const network = await provider.getNetwork();
- const ensPlugin = network.getPlugin("org.ethers.plugins.network.Ens");
- // No ENS...
- assert(ensPlugin, "network does not support ENS", "UNSUPPORTED_OPERATION", {
- operation: "getEnsAddress", info: { network }
- });
- return ensPlugin.address;
- }
- static async #getResolver(provider, name) {
- const ensAddr = await EnsResolver.getEnsAddress(provider);
- try {
- const contract = new Contract(ensAddr, [
- "function resolver(bytes32) view returns (address)"
- ], provider);
- const addr = await contract.resolver(namehash(name), {
- enableCcipRead: true
- });
- if (addr === ZeroAddress) {
- return null;
- }
- return addr;
- }
- catch (error) {
- // ENS registry cannot throw errors on resolver(bytes32),
- // so probably a link error
- throw error;
- }
- return null;
- }
- /**
- * Resolve to the ENS resolver for %%name%% using %%provider%% or
- * ``null`` if unconfigured.
- */
- static async fromName(provider, name) {
- let currentName = name;
- while (true) {
- if (currentName === "" || currentName === ".") {
- return null;
- }
- // Optimization since the eth node cannot change and does
- // not have a wildcard resolver
- if (name !== "eth" && currentName === "eth") {
- return null;
- }
- // Check the current node for a resolver
- const addr = await EnsResolver.#getResolver(provider, currentName);
- // Found a resolver!
- if (addr != null) {
- const resolver = new EnsResolver(provider, addr, name);
- // Legacy resolver found, using EIP-2544 so it isn't safe to use
- if (currentName !== name && !(await resolver.supportsWildcard())) {
- return null;
- }
- return resolver;
- }
- // Get the parent node
- currentName = currentName.split(".").slice(1).join(".");
- }
- }
- }
- /**
- * @_ignore
- */
- const BN_0 = BigInt(0);
- function allowNull(format, nullValue) {
- return (function (value) {
- if (value == null) {
- return nullValue;
- }
- return format(value);
- });
- }
- function arrayOf(format, allowNull) {
- return ((array) => {
- if (allowNull && array == null) {
- return null;
- }
- if (!Array.isArray(array)) {
- throw new Error("not an array");
- }
- return array.map((i) => format(i));
- });
- }
- // Requires an object which matches a fleet of other formatters
- // Any FormatFunc may return `undefined` to have the value omitted
- // from the result object. Calls preserve `this`.
- function object(format, altNames) {
- return ((value) => {
- const result = {};
- for (const key in format) {
- let srcKey = key;
- if (altNames && key in altNames && !(srcKey in value)) {
- for (const altKey of altNames[key]) {
- if (altKey in value) {
- srcKey = altKey;
- break;
- }
- }
- }
- try {
- const nv = format[key](value[srcKey]);
- if (nv !== undefined) {
- result[key] = nv;
- }
- }
- catch (error) {
- const message = (error instanceof Error) ? error.message : "not-an-error";
- assert(false, `invalid value for value.${key} (${message})`, "BAD_DATA", { value });
- }
- }
- return result;
- });
- }
- function formatBoolean(value) {
- switch (value) {
- case true:
- case "true":
- return true;
- case false:
- case "false":
- return false;
- }
- assertArgument(false, `invalid boolean; ${JSON.stringify(value)}`, "value", value);
- }
- function formatData(value) {
- assertArgument(isHexString(value, true), "invalid data", "value", value);
- return value;
- }
- function formatHash(value) {
- assertArgument(isHexString(value, 32), "invalid hash", "value", value);
- return value;
- }
- const _formatLog = object({
- address: getAddress,
- blockHash: formatHash,
- blockNumber: getNumber,
- data: formatData,
- index: getNumber,
- removed: allowNull(formatBoolean, false),
- topics: arrayOf(formatHash),
- transactionHash: formatHash,
- transactionIndex: getNumber,
- }, {
- index: ["logIndex"]
- });
- function formatLog(value) {
- return _formatLog(value);
- }
- const _formatBlock = object({
- hash: allowNull(formatHash),
- parentHash: formatHash,
- parentBeaconBlockRoot: allowNull(formatHash, null),
- number: getNumber,
- timestamp: getNumber,
- nonce: allowNull(formatData),
- difficulty: getBigInt,
- gasLimit: getBigInt,
- gasUsed: getBigInt,
- stateRoot: allowNull(formatHash, null),
- receiptsRoot: allowNull(formatHash, null),
- blobGasUsed: allowNull(getBigInt, null),
- excessBlobGas: allowNull(getBigInt, null),
- miner: allowNull(getAddress),
- prevRandao: allowNull(formatHash, null),
- extraData: formatData,
- baseFeePerGas: allowNull(getBigInt)
- }, {
- prevRandao: ["mixHash"]
- });
- function formatBlock(value) {
- const result = _formatBlock(value);
- result.transactions = value.transactions.map((tx) => {
- if (typeof (tx) === "string") {
- return tx;
- }
- return formatTransactionResponse(tx);
- });
- return result;
- }
- const _formatReceiptLog = object({
- transactionIndex: getNumber,
- blockNumber: getNumber,
- transactionHash: formatHash,
- address: getAddress,
- topics: arrayOf(formatHash),
- data: formatData,
- index: getNumber,
- blockHash: formatHash,
- }, {
- index: ["logIndex"]
- });
- function formatReceiptLog(value) {
- return _formatReceiptLog(value);
- }
- const _formatTransactionReceipt = object({
- to: allowNull(getAddress, null),
- from: allowNull(getAddress, null),
- contractAddress: allowNull(getAddress, null),
- // should be allowNull(hash), but broken-EIP-658 support is handled in receipt
- index: getNumber,
- root: allowNull(hexlify),
- gasUsed: getBigInt,
- blobGasUsed: allowNull(getBigInt, null),
- logsBloom: allowNull(formatData),
- blockHash: formatHash,
- hash: formatHash,
- logs: arrayOf(formatReceiptLog),
- blockNumber: getNumber,
- //confirmations: allowNull(getNumber, null),
- cumulativeGasUsed: getBigInt,
- effectiveGasPrice: allowNull(getBigInt),
- blobGasPrice: allowNull(getBigInt, null),
- status: allowNull(getNumber),
- type: allowNull(getNumber, 0)
- }, {
- effectiveGasPrice: ["gasPrice"],
- hash: ["transactionHash"],
- index: ["transactionIndex"],
- });
- function formatTransactionReceipt(value) {
- return _formatTransactionReceipt(value);
- }
- function formatTransactionResponse(value) {
- // Some clients (TestRPC) do strange things like return 0x0 for the
- // 0 address; correct this to be a real address
- if (value.to && getBigInt(value.to) === BN_0) {
- value.to = "0x0000000000000000000000000000000000000000";
- }
- const result = object({
- hash: formatHash,
- // Some nodes do not return this, usually test nodes (like Ganache)
- index: allowNull(getNumber, undefined),
- type: (value) => {
- if (value === "0x" || value == null) {
- return 0;
- }
- return getNumber(value);
- },
- accessList: allowNull(accessListify, null),
- blobVersionedHashes: allowNull(arrayOf(formatHash, true), null),
- blockHash: allowNull(formatHash, null),
- blockNumber: allowNull(getNumber, null),
- transactionIndex: allowNull(getNumber, null),
- from: getAddress,
- // either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas) must be set
- gasPrice: allowNull(getBigInt),
- maxPriorityFeePerGas: allowNull(getBigInt),
- maxFeePerGas: allowNull(getBigInt),
- maxFeePerBlobGas: allowNull(getBigInt, null),
- gasLimit: getBigInt,
- to: allowNull(getAddress, null),
- value: getBigInt,
- nonce: getNumber,
- data: formatData,
- creates: allowNull(getAddress, null),
- chainId: allowNull(getBigInt, null)
- }, {
- data: ["input"],
- gasLimit: ["gas"],
- index: ["transactionIndex"]
- })(value);
- // If to and creates are empty, populate the creates from the value
- if (result.to == null && result.creates == null) {
- result.creates = getCreateAddress(result);
- }
- // @TODO: Check fee data
- // Add an access list to supported transaction types
- if ((value.type === 1 || value.type === 2) && value.accessList == null) {
- result.accessList = [];
- }
- // Compute the signature
- if (value.signature) {
- result.signature = Signature.from(value.signature);
- }
- else {
- result.signature = Signature.from(value);
- }
- // Some backends omit ChainId on legacy transactions, but we can compute it
- if (result.chainId == null) {
- const chainId = result.signature.legacyChainId;
- if (chainId != null) {
- result.chainId = chainId;
- }
- }
- // @TODO: check chainID
- /*
- if (value.chainId != null) {
- let chainId = value.chainId;
- if (isHexString(chainId)) {
- chainId = BigNumber.from(chainId).toNumber();
- }
- result.chainId = chainId;
- } else {
- let chainId = value.networkId;
- // geth-etc returns chainId
- if (chainId == null && result.v == null) {
- chainId = value.chainId;
- }
- if (isHexString(chainId)) {
- chainId = BigNumber.from(chainId).toNumber();
- }
- if (typeof(chainId) !== "number" && result.v != null) {
- chainId = (result.v - 35) / 2;
- if (chainId < 0) { chainId = 0; }
- chainId = parseInt(chainId);
- }
- if (typeof(chainId) !== "number") { chainId = 0; }
- result.chainId = chainId;
- }
- */
- // 0x0000... should actually be null
- if (result.blockHash && getBigInt(result.blockHash) === BN_0) {
- result.blockHash = null;
- }
- return result;
- }
- const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
- /**
- * A **NetworkPlugin** provides additional functionality on a [[Network]].
- */
- class NetworkPlugin {
- /**
- * The name of the plugin.
- *
- * It is recommended to use reverse-domain-notation, which permits
- * unique names with a known authority as well as hierarchal entries.
- */
- name;
- /**
- * Creates a new **NetworkPlugin**.
- */
- constructor(name) {
- defineProperties(this, { name });
- }
- /**
- * Creates a copy of this plugin.
- */
- clone() {
- return new NetworkPlugin(this.name);
- }
- }
- /**
- * A **GasCostPlugin** allows a network to provide alternative values when
- * computing the intrinsic gas required for a transaction.
- */
- class GasCostPlugin extends NetworkPlugin {
- /**
- * The block number to treat these values as valid from.
- *
- * This allows a hardfork to have updated values included as well as
- * mulutiple hardforks to be supported.
- */
- effectiveBlock;
- /**
- * The transactions base fee.
- */
- txBase;
- /**
- * The fee for creating a new account.
- */
- txCreate;
- /**
- * The fee per zero-byte in the data.
- */
- txDataZero;
- /**
- * The fee per non-zero-byte in the data.
- */
- txDataNonzero;
- /**
- * The fee per storage key in the [[link-eip-2930]] access list.
- */
- txAccessListStorageKey;
- /**
- * The fee per address in the [[link-eip-2930]] access list.
- */
- txAccessListAddress;
- /**
- * Creates a new GasCostPlugin from %%effectiveBlock%% until the
- * latest block or another GasCostPlugin supercedes that block number,
- * with the associated %%costs%%.
- */
- constructor(effectiveBlock, costs) {
- if (effectiveBlock == null) {
- effectiveBlock = 0;
- }
- super(`org.ethers.network.plugins.GasCost#${(effectiveBlock || 0)}`);
- const props = { effectiveBlock };
- function set(name, nullish) {
- let value = (costs || {})[name];
- if (value == null) {
- value = nullish;
- }
- assertArgument(typeof (value) === "number", `invalud value for ${name}`, "costs", costs);
- props[name] = value;
- }
- set("txBase", 21000);
- set("txCreate", 32000);
- set("txDataZero", 4);
- set("txDataNonzero", 16);
- set("txAccessListStorageKey", 1900);
- set("txAccessListAddress", 2400);
- defineProperties(this, props);
- }
- clone() {
- return new GasCostPlugin(this.effectiveBlock, this);
- }
- }
- /**
- * An **EnsPlugin** allows a [[Network]] to specify the ENS Registry
- * Contract address and the target network to use when using that
- * contract.
- *
- * Various testnets have their own instance of the contract to use, but
- * in general, the mainnet instance supports multi-chain addresses and
- * should be used.
- */
- class EnsPlugin extends NetworkPlugin {
- /**
- * The ENS Registrty Contract address.
- */
- address;
- /**
- * The chain ID that the ENS contract lives on.
- */
- targetNetwork;
- /**
- * Creates a new **EnsPlugin** connected to %%address%% on the
- * %%targetNetwork%%. The default ENS address and mainnet is used
- * if unspecified.
- */
- constructor(address, targetNetwork) {
- super("org.ethers.plugins.network.Ens");
- defineProperties(this, {
- address: (address || EnsAddress),
- targetNetwork: ((targetNetwork == null) ? 1 : targetNetwork)
- });
- }
- clone() {
- return new EnsPlugin(this.address, this.targetNetwork);
- }
- }
- /**
- * A **FeeDataNetworkPlugin** allows a network to provide and alternate
- * means to specify its fee data.
- *
- * For example, a network which does not support [[link-eip-1559]] may
- * choose to use a Gas Station site to approximate the gas price.
- */
- class FeeDataNetworkPlugin extends NetworkPlugin {
- #feeDataFunc;
- /**
- * The fee data function provided to the constructor.
- */
- get feeDataFunc() {
- return this.#feeDataFunc;
- }
- /**
- * Creates a new **FeeDataNetworkPlugin**.
- */
- constructor(feeDataFunc) {
- super("org.ethers.plugins.network.FeeData");
- this.#feeDataFunc = feeDataFunc;
- }
- /**
- * Resolves to the fee data.
- */
- async getFeeData(provider) {
- return await this.#feeDataFunc(provider);
- }
- clone() {
- return new FeeDataNetworkPlugin(this.#feeDataFunc);
- }
- }
- class FetchUrlFeeDataNetworkPlugin extends NetworkPlugin {
- #url;
- #processFunc;
- /**
- * The URL to initialize the FetchRequest with in %%processFunc%%.
- */
- get url() { return this.#url; }
- /**
- * The callback to use when computing the FeeData.
- */
- get processFunc() { return this.#processFunc; }
- /**
- * Creates a new **FetchUrlFeeDataNetworkPlugin** which will
- * be used when computing the fee data for the network.
- */
- constructor(url, processFunc) {
- super("org.ethers.plugins.network.FetchUrlFeeDataPlugin");
- this.#url = url;
- this.#processFunc = processFunc;
- }
- // We are immutable, so we can serve as our own clone
- clone() { return this; }
- }
- /*
- export class CustomBlockNetworkPlugin extends NetworkPlugin {
- readonly #blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>;
- readonly #blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>;
- constructor(blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>, blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>) {
- super("org.ethers.network-plugins.custom-block");
- this.#blockFunc = blockFunc;
- this.#blockWithTxsFunc = blockWithTxsFunc;
- }
- async getBlock(provider: Provider, block: BlockParams<string>): Promise<Block<string>> {
- return await this.#blockFunc(provider, block);
- }
- async getBlockions(provider: Provider, block: BlockParams<TransactionResponseParams>): Promise<Block<TransactionResponse>> {
- return await this.#blockWithTxsFunc(provider, block);
- }
- clone(): CustomBlockNetworkPlugin {
- return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc);
- }
- }
- */
- /**
- * A **Network** encapsulates the various properties required to
- * interact with a specific chain.
- *
- * @_subsection: api/providers:Networks [networks]
- */
- /* * * *
- // Networks which operation against an L2 can use this plugin to
- // specify how to access L1, for the purpose of resolving ENS,
- // for example.
- export class LayerOneConnectionPlugin extends NetworkPlugin {
- readonly provider!: Provider;
- // @TODO: Rename to ChainAccess and allow for connecting to any chain
- constructor(provider: Provider) {
- super("org.ethers.plugins.layer-one-connection");
- defineProperties<LayerOneConnectionPlugin>(this, { provider });
- }
- clone(): LayerOneConnectionPlugin {
- return new LayerOneConnectionPlugin(this.provider);
- }
- }
- */
- const Networks = new Map();
- /**
- * A **Network** provides access to a chain's properties and allows
- * for plug-ins to extend functionality.
- */
- class Network {
- #name;
- #chainId;
- #plugins;
- /**
- * Creates a new **Network** for %%name%% and %%chainId%%.
- */
- constructor(name, chainId) {
- this.#name = name;
- this.#chainId = getBigInt(chainId);
- this.#plugins = new Map();
- }
- /**
- * Returns a JSON-compatible representation of a Network.
- */
- toJSON() {
- return { name: this.name, chainId: String(this.chainId) };
- }
- /**
- * The network common name.
- *
- * This is the canonical name, as networks migh have multiple
- * names.
- */
- get name() { return this.#name; }
- set name(value) { this.#name = value; }
- /**
- * The network chain ID.
- */
- get chainId() { return this.#chainId; }
- set chainId(value) { this.#chainId = getBigInt(value, "chainId"); }
- /**
- * Returns true if %%other%% matches this network. Any chain ID
- * must match, and if no chain ID is present, the name must match.
- *
- * This method does not currently check for additional properties,
- * such as ENS address or plug-in compatibility.
- */
- matches(other) {
- if (other == null) {
- return false;
- }
- if (typeof (other) === "string") {
- try {
- return (this.chainId === getBigInt(other));
- }
- catch (error) { }
- return (this.name === other);
- }
- if (typeof (other) === "number" || typeof (other) === "bigint") {
- try {
- return (this.chainId === getBigInt(other));
- }
- catch (error) { }
- return false;
- }
- if (typeof (other) === "object") {
- if (other.chainId != null) {
- try {
- return (this.chainId === getBigInt(other.chainId));
- }
- catch (error) { }
- return false;
- }
- if (other.name != null) {
- return (this.name === other.name);
- }
- return false;
- }
- return false;
- }
- /**
- * Returns the list of plugins currently attached to this Network.
- */
- get plugins() {
- return Array.from(this.#plugins.values());
- }
- /**
- * Attach a new %%plugin%% to this Network. The network name
- * must be unique, excluding any fragment.
- */
- attachPlugin(plugin) {
- if (this.#plugins.get(plugin.name)) {
- throw new Error(`cannot replace existing plugin: ${plugin.name} `);
- }
- this.#plugins.set(plugin.name, plugin.clone());
- return this;
- }
- /**
- * Return the plugin, if any, matching %%name%% exactly. Plugins
- * with fragments will not be returned unless %%name%% includes
- * a fragment.
- */
- getPlugin(name) {
- return (this.#plugins.get(name)) || null;
- }
- /**
- * Gets a list of all plugins that match %%name%%, with otr without
- * a fragment.
- */
- getPlugins(basename) {
- return (this.plugins.filter((p) => (p.name.split("#")[0] === basename)));
- }
- /**
- * Create a copy of this Network.
- */
- clone() {
- const clone = new Network(this.name, this.chainId);
- this.plugins.forEach((plugin) => {
- clone.attachPlugin(plugin.clone());
- });
- return clone;
- }
- /**
- * Compute the intrinsic gas required for a transaction.
- *
- * A GasCostPlugin can be attached to override the default
- * values.
- */
- computeIntrinsicGas(tx) {
- const costs = this.getPlugin("org.ethers.plugins.network.GasCost") || (new GasCostPlugin());
- let gas = costs.txBase;
- if (tx.to == null) {
- gas += costs.txCreate;
- }
- if (tx.data) {
- for (let i = 2; i < tx.data.length; i += 2) {
- if (tx.data.substring(i, i + 2) === "00") {
- gas += costs.txDataZero;
- }
- else {
- gas += costs.txDataNonzero;
- }
- }
- }
- if (tx.accessList) {
- const accessList = accessListify(tx.accessList);
- for (const addr in accessList) {
- gas += costs.txAccessListAddress + costs.txAccessListStorageKey * accessList[addr].storageKeys.length;
- }
- }
- return gas;
- }
- /**
- * Returns a new Network for the %%network%% name or chainId.
- */
- static from(network) {
- injectCommonNetworks();
- // Default network
- if (network == null) {
- return Network.from("mainnet");
- }
- // Canonical name or chain ID
- if (typeof (network) === "number") {
- network = BigInt(network);
- }
- if (typeof (network) === "string" || typeof (network) === "bigint") {
- const networkFunc = Networks.get(network);
- if (networkFunc) {
- return networkFunc();
- }
- if (typeof (network) === "bigint") {
- return new Network("unknown", network);
- }
- assertArgument(false, "unknown network", "network", network);
- }
- // Clonable with network-like abilities
- if (typeof (network.clone) === "function") {
- const clone = network.clone();
- //if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") {
- //}
- return clone;
- }
- // Networkish
- if (typeof (network) === "object") {
- assertArgument(typeof (network.name) === "string" && typeof (network.chainId) === "number", "invalid network object name or chainId", "network", network);
- const custom = new Network((network.name), (network.chainId));
- if (network.ensAddress || network.ensNetwork != null) {
- custom.attachPlugin(new EnsPlugin(network.ensAddress, network.ensNetwork));
- }
- //if ((<any>network).layerOneConnection) {
- // custom.attachPlugin(new LayerOneConnectionPlugin((<any>network).layerOneConnection));
- //}
- return custom;
- }
- assertArgument(false, "invalid network", "network", network);
- }
- /**
- * Register %%nameOrChainId%% with a function which returns
- * an instance of a Network representing that chain.
- */
- static register(nameOrChainId, networkFunc) {
- if (typeof (nameOrChainId) === "number") {
- nameOrChainId = BigInt(nameOrChainId);
- }
- const existing = Networks.get(nameOrChainId);
- if (existing) {
- assertArgument(false, `conflicting network for ${JSON.stringify(existing.name)}`, "nameOrChainId", nameOrChainId);
- }
- Networks.set(nameOrChainId, networkFunc);
- }
- }
- // We don't want to bring in formatUnits because it is backed by
- // FixedNumber and we want to keep Networks tiny. The values
- // included by the Gas Stations are also IEEE 754 with lots of
- // rounding issues and exceed the strict checks formatUnits has.
- function parseUnits(_value, decimals) {
- const value = String(_value);
- if (!value.match(/^[0-9.]+$/)) {
- throw new Error(`invalid gwei value: ${_value}`);
- }
- // Break into [ whole, fraction ]
- const comps = value.split(".");
- if (comps.length === 1) {
- comps.push("");
- }
- // More than 1 decimal point or too many fractional positions
- if (comps.length !== 2) {
- throw new Error(`invalid gwei value: ${_value}`);
- }
- // Pad the fraction to 9 decimalplaces
- while (comps[1].length < decimals) {
- comps[1] += "0";
- }
- // Too many decimals and some non-zero ending, take the ceiling
- if (comps[1].length > 9) {
- let frac = BigInt(comps[1].substring(0, 9));
- if (!comps[1].substring(9).match(/^0+$/)) {
- frac++;
- }
- comps[1] = frac.toString();
- }
- return BigInt(comps[0] + comps[1]);
- }
- // Used by Polygon to use a gas station for fee data
- function getGasStationPlugin(url) {
- return new FetchUrlFeeDataNetworkPlugin(url, async (fetchFeeData, provider, request) => {
- // Prevent Cloudflare from blocking our request in node.js
- request.setHeader("User-Agent", "ethers");
- let response;
- try {
- const [_response, _feeData] = await Promise.all([
- request.send(), fetchFeeData()
- ]);
- response = _response;
- const payload = response.bodyJson.standard;
- const feeData = {
- gasPrice: _feeData.gasPrice,
- maxFeePerGas: parseUnits(payload.maxFee, 9),
- maxPriorityFeePerGas: parseUnits(payload.maxPriorityFee, 9),
- };
- return feeData;
- }
- catch (error) {
- assert(false, `error encountered with polygon gas station (${JSON.stringify(request.url)})`, "SERVER_ERROR", { request, response, error });
- }
- });
- }
- // See: https://chainlist.org
- let injected = false;
- function injectCommonNetworks() {
- if (injected) {
- return;
- }
- injected = true;
- /// Register popular Ethereum networks
- function registerEth(name, chainId, options) {
- const func = function () {
- const network = new Network(name, chainId);
- // We use 0 to disable ENS
- if (options.ensNetwork != null) {
- network.attachPlugin(new EnsPlugin(null, options.ensNetwork));
- }
- network.attachPlugin(new GasCostPlugin());
- (options.plugins || []).forEach((plugin) => {
- network.attachPlugin(plugin);
- });
- return network;
- };
- // Register the network by name and chain ID
- Network.register(name, func);
- Network.register(chainId, func);
- if (options.altNames) {
- options.altNames.forEach((name) => {
- Network.register(name, func);
- });
- }
- }
- registerEth("mainnet", 1, { ensNetwork: 1, altNames: ["homestead"] });
- registerEth("ropsten", 3, { ensNetwork: 3 });
- registerEth("rinkeby", 4, { ensNetwork: 4 });
- registerEth("goerli", 5, { ensNetwork: 5 });
- registerEth("kovan", 42, { ensNetwork: 42 });
- registerEth("sepolia", 11155111, { ensNetwork: 11155111 });
- registerEth("holesky", 17000, { ensNetwork: 17000 });
- registerEth("classic", 61, {});
- registerEth("classicKotti", 6, {});
- registerEth("arbitrum", 42161, {
- ensNetwork: 1,
- });
- registerEth("arbitrum-goerli", 421613, {});
- registerEth("arbitrum-sepolia", 421614, {});
- registerEth("base", 8453, { ensNetwork: 1 });
- registerEth("base-goerli", 84531, {});
- registerEth("base-sepolia", 84532, {});
- registerEth("bnb", 56, { ensNetwork: 1 });
- registerEth("bnbt", 97, {});
- registerEth("linea", 59144, { ensNetwork: 1 });
- registerEth("linea-goerli", 59140, {});
- registerEth("linea-sepolia", 59141, {});
- registerEth("matic", 137, {
- ensNetwork: 1,
- plugins: [
- getGasStationPlugin("https:/\/gasstation.polygon.technology/v2")
- ]
- });
- registerEth("matic-amoy", 80002, {});
- registerEth("matic-mumbai", 80001, {
- altNames: ["maticMumbai", "maticmum"],
- plugins: [
- getGasStationPlugin("https:/\/gasstation-testnet.polygon.technology/v2")
- ]
- });
- registerEth("optimism", 10, {
- ensNetwork: 1,
- plugins: []
- });
- registerEth("optimism-goerli", 420, {});
- registerEth("optimism-sepolia", 11155420, {});
- registerEth("xdai", 100, { ensNetwork: 1 });
- }
- function copy$2(obj) {
- return JSON.parse(JSON.stringify(obj));
- }
- // @TODO: refactor this
- /**
- * A **PollingBlockSubscriber** polls at a regular interval for a change
- * in the block number.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class PollingBlockSubscriber {
- #provider;
- #poller;
- #interval;
- // The most recent block we have scanned for events. The value -2
- // indicates we still need to fetch an initial block number
- #blockNumber;
- /**
- * Create a new **PollingBlockSubscriber** attached to %%provider%%.
- */
- constructor(provider) {
- this.#provider = provider;
- this.#poller = null;
- this.#interval = 4000;
- this.#blockNumber = -2;
- }
- /**
- * The polling interval.
- */
- get pollingInterval() { return this.#interval; }
- set pollingInterval(value) { this.#interval = value; }
- async #poll() {
- try {
- const blockNumber = await this.#provider.getBlockNumber();
- // Bootstrap poll to setup our initial block number
- if (this.#blockNumber === -2) {
- this.#blockNumber = blockNumber;
- return;
- }
- // @TODO: Put a cap on the maximum number of events per loop?
- if (blockNumber !== this.#blockNumber) {
- for (let b = this.#blockNumber + 1; b <= blockNumber; b++) {
- // We have been stopped
- if (this.#poller == null) {
- return;
- }
- await this.#provider.emit("block", b);
- }
- this.#blockNumber = blockNumber;
- }
- }
- catch (error) {
- // @TODO: Minor bump, add an "error" event to let subscribers
- // know things went awry.
- //console.log(error);
- }
- // We have been stopped
- if (this.#poller == null) {
- return;
- }
- this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
- }
- start() {
- if (this.#poller) {
- return;
- }
- this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
- this.#poll();
- }
- stop() {
- if (!this.#poller) {
- return;
- }
- this.#provider._clearTimeout(this.#poller);
- this.#poller = null;
- }
- pause(dropWhilePaused) {
- this.stop();
- if (dropWhilePaused) {
- this.#blockNumber = -2;
- }
- }
- resume() {
- this.start();
- }
- }
- /**
- * An **OnBlockSubscriber** can be sub-classed, with a [[_poll]]
- * implmentation which will be called on every new block.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class OnBlockSubscriber {
- #provider;
- #poll;
- #running;
- /**
- * Create a new **OnBlockSubscriber** attached to %%provider%%.
- */
- constructor(provider) {
- this.#provider = provider;
- this.#running = false;
- this.#poll = (blockNumber) => {
- this._poll(blockNumber, this.#provider);
- };
- }
- /**
- * Called on every new block.
- */
- async _poll(blockNumber, provider) {
- throw new Error("sub-classes must override this");
- }
- start() {
- if (this.#running) {
- return;
- }
- this.#running = true;
- this.#poll(-2);
- this.#provider.on("block", this.#poll);
- }
- stop() {
- if (!this.#running) {
- return;
- }
- this.#running = false;
- this.#provider.off("block", this.#poll);
- }
- pause(dropWhilePaused) { this.stop(); }
- resume() { this.start(); }
- }
- class PollingBlockTagSubscriber extends OnBlockSubscriber {
- #tag;
- #lastBlock;
- constructor(provider, tag) {
- super(provider);
- this.#tag = tag;
- this.#lastBlock = -2;
- }
- pause(dropWhilePaused) {
- if (dropWhilePaused) {
- this.#lastBlock = -2;
- }
- super.pause(dropWhilePaused);
- }
- async _poll(blockNumber, provider) {
- const block = await provider.getBlock(this.#tag);
- if (block == null) {
- return;
- }
- if (this.#lastBlock === -2) {
- this.#lastBlock = block.number;
- }
- else if (block.number > this.#lastBlock) {
- provider.emit(this.#tag, block.number);
- this.#lastBlock = block.number;
- }
- }
- }
- /**
- * @_ignore:
- *
- * @_docloc: api/providers/abstract-provider
- */
- class PollingOrphanSubscriber extends OnBlockSubscriber {
- #filter;
- constructor(provider, filter) {
- super(provider);
- this.#filter = copy$2(filter);
- }
- async _poll(blockNumber, provider) {
- throw new Error("@TODO");
- }
- }
- /**
- * A **PollingTransactionSubscriber** will poll for a given transaction
- * hash for its receipt.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class PollingTransactionSubscriber extends OnBlockSubscriber {
- #hash;
- /**
- * Create a new **PollingTransactionSubscriber** attached to
- * %%provider%%, listening for %%hash%%.
- */
- constructor(provider, hash) {
- super(provider);
- this.#hash = hash;
- }
- async _poll(blockNumber, provider) {
- const tx = await provider.getTransactionReceipt(this.#hash);
- if (tx) {
- provider.emit(this.#hash, tx);
- }
- }
- }
- /**
- * A **PollingEventSubscriber** will poll for a given filter for its logs.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class PollingEventSubscriber {
- #provider;
- #filter;
- #poller;
- #running;
- // The most recent block we have scanned for events. The value -2
- // indicates we still need to fetch an initial block number
- #blockNumber;
- /**
- * Create a new **PollingTransactionSubscriber** attached to
- * %%provider%%, listening for %%filter%%.
- */
- constructor(provider, filter) {
- this.#provider = provider;
- this.#filter = copy$2(filter);
- this.#poller = this.#poll.bind(this);
- this.#running = false;
- this.#blockNumber = -2;
- }
- async #poll(blockNumber) {
- // The initial block hasn't been determined yet
- if (this.#blockNumber === -2) {
- return;
- }
- const filter = copy$2(this.#filter);
- filter.fromBlock = this.#blockNumber + 1;
- filter.toBlock = blockNumber;
- const logs = await this.#provider.getLogs(filter);
- // No logs could just mean the node has not indexed them yet,
- // so we keep a sliding window of 60 blocks to keep scanning
- if (logs.length === 0) {
- if (this.#blockNumber < blockNumber - 60) {
- this.#blockNumber = blockNumber - 60;
- }
- return;
- }
- for (const log of logs) {
- this.#provider.emit(this.#filter, log);
- // Only advance the block number when logs were found to
- // account for networks (like BNB and Polygon) which may
- // sacrifice event consistency for block event speed
- this.#blockNumber = log.blockNumber;
- }
- }
- start() {
- if (this.#running) {
- return;
- }
- this.#running = true;
- if (this.#blockNumber === -2) {
- this.#provider.getBlockNumber().then((blockNumber) => {
- this.#blockNumber = blockNumber;
- });
- }
- this.#provider.on("block", this.#poller);
- }
- stop() {
- if (!this.#running) {
- return;
- }
- this.#running = false;
- this.#provider.off("block", this.#poller);
- }
- pause(dropWhilePaused) {
- this.stop();
- if (dropWhilePaused) {
- this.#blockNumber = -2;
- }
- }
- resume() {
- this.start();
- }
- }
- /**
- * The available providers should suffice for most developers purposes,
- * but the [[AbstractProvider]] class has many features which enable
- * sub-classing it for specific purposes.
- *
- * @_section: api/providers/abstract-provider: Subclassing Provider [abstract-provider]
- */
- // @TODO
- // Event coalescence
- // When we register an event with an async value (e.g. address is a Signer
- // or ENS name), we need to add it immeidately for the Event API, but also
- // need time to resolve the address. Upon resolving the address, we need to
- // migrate the listener to the static event. We also need to maintain a map
- // of Signer/ENS name to address so we can sync respond to listenerCount.
- // Constants
- const BN_2$1 = BigInt(2);
- const MAX_CCIP_REDIRECTS = 10;
- function isPromise$1(value) {
- return (value && typeof (value.then) === "function");
- }
- function getTag(prefix, value) {
- return prefix + ":" + JSON.stringify(value, (k, v) => {
- if (v == null) {
- return "null";
- }
- if (typeof (v) === "bigint") {
- return `bigint:${v.toString()}`;
- }
- if (typeof (v) === "string") {
- return v.toLowerCase();
- }
- // Sort object keys
- if (typeof (v) === "object" && !Array.isArray(v)) {
- const keys = Object.keys(v);
- keys.sort();
- return keys.reduce((accum, key) => {
- accum[key] = v[key];
- return accum;
- }, {});
- }
- return v;
- });
- }
- /**
- * An **UnmanagedSubscriber** is useful for events which do not require
- * any additional management, such as ``"debug"`` which only requires
- * emit in synchronous event loop triggered calls.
- */
- class UnmanagedSubscriber {
- /**
- * The name fof the event.
- */
- name;
- /**
- * Create a new UnmanagedSubscriber with %%name%%.
- */
- constructor(name) { defineProperties(this, { name }); }
- start() { }
- stop() { }
- pause(dropWhilePaused) { }
- resume() { }
- }
- function copy$1(value) {
- return JSON.parse(JSON.stringify(value));
- }
- function concisify(items) {
- items = Array.from((new Set(items)).values());
- items.sort();
- return items;
- }
- async function getSubscription(_event, provider) {
- if (_event == null) {
- throw new Error("invalid event");
- }
- // Normalize topic array info an EventFilter
- if (Array.isArray(_event)) {
- _event = { topics: _event };
- }
- if (typeof (_event) === "string") {
- switch (_event) {
- case "block":
- case "debug":
- case "error":
- case "finalized":
- case "network":
- case "pending":
- case "safe": {
- return { type: _event, tag: _event };
- }
- }
- }
- if (isHexString(_event, 32)) {
- const hash = _event.toLowerCase();
- return { type: "transaction", tag: getTag("tx", { hash }), hash };
- }
- if (_event.orphan) {
- const event = _event;
- // @TODO: Should lowercase and whatnot things here instead of copy...
- return { type: "orphan", tag: getTag("orphan", event), filter: copy$1(event) };
- }
- if ((_event.address || _event.topics)) {
- const event = _event;
- const filter = {
- topics: ((event.topics || []).map((t) => {
- if (t == null) {
- return null;
- }
- if (Array.isArray(t)) {
- return concisify(t.map((t) => t.toLowerCase()));
- }
- return t.toLowerCase();
- }))
- };
- if (event.address) {
- const addresses = [];
- const promises = [];
- const addAddress = (addr) => {
- if (isHexString(addr)) {
- addresses.push(addr);
- }
- else {
- promises.push((async () => {
- addresses.push(await resolveAddress(addr, provider));
- })());
- }
- };
- if (Array.isArray(event.address)) {
- event.address.forEach(addAddress);
- }
- else {
- addAddress(event.address);
- }
- if (promises.length) {
- await Promise.all(promises);
- }
- filter.address = concisify(addresses.map((a) => a.toLowerCase()));
- }
- return { filter, tag: getTag("event", filter), type: "event" };
- }
- assertArgument(false, "unknown ProviderEvent", "event", _event);
- }
- function getTime$1() { return (new Date()).getTime(); }
- const defaultOptions$1 = {
- cacheTimeout: 250,
- pollingInterval: 4000
- };
- /**
- * An **AbstractProvider** provides a base class for other sub-classes to
- * implement the [[Provider]] API by normalizing input arguments and
- * formatting output results as well as tracking events for consistent
- * behaviour on an eventually-consistent network.
- */
- class AbstractProvider {
- #subs;
- #plugins;
- // null=unpaused, true=paused+dropWhilePaused, false=paused
- #pausedState;
- #destroyed;
- #networkPromise;
- #anyNetwork;
- #performCache;
- // The most recent block number if running an event or -1 if no "block" event
- #lastBlockNumber;
- #nextTimer;
- #timers;
- #disableCcipRead;
- #options;
- /**
- * Create a new **AbstractProvider** connected to %%network%%, or
- * use the various network detection capabilities to discover the
- * [[Network]] if necessary.
- */
- constructor(_network, options) {
- this.#options = Object.assign({}, defaultOptions$1, options || {});
- if (_network === "any") {
- this.#anyNetwork = true;
- this.#networkPromise = null;
- }
- else if (_network) {
- const network = Network.from(_network);
- this.#anyNetwork = false;
- this.#networkPromise = Promise.resolve(network);
- setTimeout(() => { this.emit("network", network, null); }, 0);
- }
- else {
- this.#anyNetwork = false;
- this.#networkPromise = null;
- }
- this.#lastBlockNumber = -1;
- this.#performCache = new Map();
- this.#subs = new Map();
- this.#plugins = new Map();
- this.#pausedState = null;
- this.#destroyed = false;
- this.#nextTimer = 1;
- this.#timers = new Map();
- this.#disableCcipRead = false;
- }
- get pollingInterval() { return this.#options.pollingInterval; }
- /**
- * Returns ``this``, to allow an **AbstractProvider** to implement
- * the [[ContractRunner]] interface.
- */
- get provider() { return this; }
- /**
- * Returns all the registered plug-ins.
- */
- get plugins() {
- return Array.from(this.#plugins.values());
- }
- /**
- * Attach a new plug-in.
- */
- attachPlugin(plugin) {
- if (this.#plugins.get(plugin.name)) {
- throw new Error(`cannot replace existing plugin: ${plugin.name} `);
- }
- this.#plugins.set(plugin.name, plugin.connect(this));
- return this;
- }
- /**
- * Get a plugin by name.
- */
- getPlugin(name) {
- return (this.#plugins.get(name)) || null;
- }
- /**
- * Prevent any CCIP-read operation, regardless of whether requested
- * in a [[call]] using ``enableCcipRead``.
- */
- get disableCcipRead() { return this.#disableCcipRead; }
- set disableCcipRead(value) { this.#disableCcipRead = !!value; }
- // Shares multiple identical requests made during the same 250ms
- async #perform(req) {
- const timeout = this.#options.cacheTimeout;
- // Caching disabled
- if (timeout < 0) {
- return await this._perform(req);
- }
- // Create a tag
- const tag = getTag(req.method, req);
- let perform = this.#performCache.get(tag);
- if (!perform) {
- perform = this._perform(req);
- this.#performCache.set(tag, perform);
- setTimeout(() => {
- if (this.#performCache.get(tag) === perform) {
- this.#performCache.delete(tag);
- }
- }, timeout);
- }
- return await perform;
- }
- /**
- * Resolves to the data for executing the CCIP-read operations.
- */
- async ccipReadFetch(tx, calldata, urls) {
- if (this.disableCcipRead || urls.length === 0 || tx.to == null) {
- return null;
- }
- const sender = tx.to.toLowerCase();
- const data = calldata.toLowerCase();
- const errorMessages = [];
- for (let i = 0; i < urls.length; i++) {
- const url = urls[i];
- // URL expansion
- const href = url.replace("{sender}", sender).replace("{data}", data);
- // If no {data} is present, use POST; otherwise GET
- //const json: string | null = (url.indexOf("{data}") >= 0) ? null: JSON.stringify({ data, sender });
- //const result = await fetchJson({ url: href, errorPassThrough: true }, json, (value, response) => {
- // value.status = response.statusCode;
- // return value;
- //});
- const request = new FetchRequest(href);
- if (url.indexOf("{data}") === -1) {
- request.body = { data, sender };
- }
- this.emit("debug", { action: "sendCcipReadFetchRequest", request, index: i, urls });
- let errorMessage = "unknown error";
- // Fetch the resource...
- let resp;
- try {
- resp = await request.send();
- }
- catch (error) {
- // ...low-level fetch error (missing host, bad SSL, etc.),
- // so try next URL
- errorMessages.push(error.message);
- this.emit("debug", { action: "receiveCcipReadFetchError", request, result: { error } });
- continue;
- }
- try {
- const result = resp.bodyJson;
- if (result.data) {
- this.emit("debug", { action: "receiveCcipReadFetchResult", request, result });
- return result.data;
- }
- if (result.message) {
- errorMessage = result.message;
- }
- this.emit("debug", { action: "receiveCcipReadFetchError", request, result });
- }
- catch (error) { }
- // 4xx indicates the result is not present; stop
- assert(resp.statusCode < 400 || resp.statusCode >= 500, `response not found during CCIP fetch: ${errorMessage}`, "OFFCHAIN_FAULT", { reason: "404_MISSING_RESOURCE", transaction: tx, info: { url, errorMessage } });
- // 5xx indicates server issue; try the next url
- errorMessages.push(errorMessage);
- }
- assert(false, `error encountered during CCIP fetch: ${errorMessages.map((m) => JSON.stringify(m)).join(", ")}`, "OFFCHAIN_FAULT", {
- reason: "500_SERVER_ERROR",
- transaction: tx, info: { urls, errorMessages }
- });
- }
- /**
- * Provides the opportunity for a sub-class to wrap a block before
- * returning it, to add additional properties or an alternate
- * sub-class of [[Block]].
- */
- _wrapBlock(value, network) {
- return new Block(formatBlock(value), this);
- }
- /**
- * Provides the opportunity for a sub-class to wrap a log before
- * returning it, to add additional properties or an alternate
- * sub-class of [[Log]].
- */
- _wrapLog(value, network) {
- return new Log(formatLog(value), this);
- }
- /**
- * Provides the opportunity for a sub-class to wrap a transaction
- * receipt before returning it, to add additional properties or an
- * alternate sub-class of [[TransactionReceipt]].
- */
- _wrapTransactionReceipt(value, network) {
- return new TransactionReceipt(formatTransactionReceipt(value), this);
- }
- /**
- * Provides the opportunity for a sub-class to wrap a transaction
- * response before returning it, to add additional properties or an
- * alternate sub-class of [[TransactionResponse]].
- */
- _wrapTransactionResponse(tx, network) {
- return new TransactionResponse(formatTransactionResponse(tx), this);
- }
- /**
- * Resolves to the Network, forcing a network detection using whatever
- * technique the sub-class requires.
- *
- * Sub-classes **must** override this.
- */
- _detectNetwork() {
- assert(false, "sub-classes must implement this", "UNSUPPORTED_OPERATION", {
- operation: "_detectNetwork"
- });
- }
- /**
- * Sub-classes should use this to perform all built-in operations. All
- * methods sanitizes and normalizes the values passed into this.
- *
- * Sub-classes **must** override this.
- */
- async _perform(req) {
- assert(false, `unsupported method: ${req.method}`, "UNSUPPORTED_OPERATION", {
- operation: req.method,
- info: req
- });
- }
- // State
- async getBlockNumber() {
- const blockNumber = getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
- if (this.#lastBlockNumber >= 0) {
- this.#lastBlockNumber = blockNumber;
- }
- return blockNumber;
- }
- /**
- * Returns or resolves to the address for %%address%%, resolving ENS
- * names and [[Addressable]] objects and returning if already an
- * address.
- */
- _getAddress(address) {
- return resolveAddress(address, this);
- }
- /**
- * Returns or resolves to a valid block tag for %%blockTag%%, resolving
- * negative values and returning if already a valid block tag.
- */
- _getBlockTag(blockTag) {
- if (blockTag == null) {
- return "latest";
- }
- switch (blockTag) {
- case "earliest":
- return "0x0";
- case "finalized":
- case "latest":
- case "pending":
- case "safe":
- return blockTag;
- }
- if (isHexString(blockTag)) {
- if (isHexString(blockTag, 32)) {
- return blockTag;
- }
- return toQuantity(blockTag);
- }
- if (typeof (blockTag) === "bigint") {
- blockTag = getNumber(blockTag, "blockTag");
- }
- if (typeof (blockTag) === "number") {
- if (blockTag >= 0) {
- return toQuantity(blockTag);
- }
- if (this.#lastBlockNumber >= 0) {
- return toQuantity(this.#lastBlockNumber + blockTag);
- }
- return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
- }
- assertArgument(false, "invalid blockTag", "blockTag", blockTag);
- }
- /**
- * Returns or resolves to a filter for %%filter%%, resolving any ENS
- * names or [[Addressable]] object and returning if already a valid
- * filter.
- */
- _getFilter(filter) {
- // Create a canonical representation of the topics
- const topics = (filter.topics || []).map((t) => {
- if (t == null) {
- return null;
- }
- if (Array.isArray(t)) {
- return concisify(t.map((t) => t.toLowerCase()));
- }
- return t.toLowerCase();
- });
- const blockHash = ("blockHash" in filter) ? filter.blockHash : undefined;
- const resolve = (_address, fromBlock, toBlock) => {
- let address = undefined;
- switch (_address.length) {
- case 0: break;
- case 1:
- address = _address[0];
- break;
- default:
- _address.sort();
- address = _address;
- }
- if (blockHash) {
- if (fromBlock != null || toBlock != null) {
- throw new Error("invalid filter");
- }
- }
- const filter = {};
- if (address) {
- filter.address = address;
- }
- if (topics.length) {
- filter.topics = topics;
- }
- if (fromBlock) {
- filter.fromBlock = fromBlock;
- }
- if (toBlock) {
- filter.toBlock = toBlock;
- }
- if (blockHash) {
- filter.blockHash = blockHash;
- }
- return filter;
- };
- // Addresses could be async (ENS names or Addressables)
- let address = [];
- if (filter.address) {
- if (Array.isArray(filter.address)) {
- for (const addr of filter.address) {
- address.push(this._getAddress(addr));
- }
- }
- else {
- address.push(this._getAddress(filter.address));
- }
- }
- let fromBlock = undefined;
- if ("fromBlock" in filter) {
- fromBlock = this._getBlockTag(filter.fromBlock);
- }
- let toBlock = undefined;
- if ("toBlock" in filter) {
- toBlock = this._getBlockTag(filter.toBlock);
- }
- if (address.filter((a) => (typeof (a) !== "string")).length ||
- (fromBlock != null && typeof (fromBlock) !== "string") ||
- (toBlock != null && typeof (toBlock) !== "string")) {
- return Promise.all([Promise.all(address), fromBlock, toBlock]).then((result) => {
- return resolve(result[0], result[1], result[2]);
- });
- }
- return resolve(address, fromBlock, toBlock);
- }
- /**
- * Returns or resolves to a transaction for %%request%%, resolving
- * any ENS names or [[Addressable]] and returning if already a valid
- * transaction.
- */
- _getTransactionRequest(_request) {
- const request = copyRequest(_request);
- const promises = [];
- ["to", "from"].forEach((key) => {
- if (request[key] == null) {
- return;
- }
- const addr = resolveAddress(request[key], this);
- if (isPromise$1(addr)) {
- promises.push((async function () { request[key] = await addr; })());
- }
- else {
- request[key] = addr;
- }
- });
- if (request.blockTag != null) {
- const blockTag = this._getBlockTag(request.blockTag);
- if (isPromise$1(blockTag)) {
- promises.push((async function () { request.blockTag = await blockTag; })());
- }
- else {
- request.blockTag = blockTag;
- }
- }
- if (promises.length) {
- return (async function () {
- await Promise.all(promises);
- return request;
- })();
- }
- return request;
- }
- async getNetwork() {
- // No explicit network was set and this is our first time
- if (this.#networkPromise == null) {
- // Detect the current network (shared with all calls)
- const detectNetwork = (async () => {
- try {
- const network = await this._detectNetwork();
- this.emit("network", network, null);
- return network;
- }
- catch (error) {
- if (this.#networkPromise === detectNetwork) {
- this.#networkPromise = null;
- }
- throw error;
- }
- })();
- this.#networkPromise = detectNetwork;
- return (await detectNetwork).clone();
- }
- const networkPromise = this.#networkPromise;
- const [expected, actual] = await Promise.all([
- networkPromise,
- this._detectNetwork() // The actual connected network
- ]);
- if (expected.chainId !== actual.chainId) {
- if (this.#anyNetwork) {
- // The "any" network can change, so notify listeners
- this.emit("network", actual, expected);
- // Update the network if something else hasn't already changed it
- if (this.#networkPromise === networkPromise) {
- this.#networkPromise = Promise.resolve(actual);
- }
- }
- else {
- // Otherwise, we do not allow changes to the underlying network
- assert(false, `network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {
- event: "changed"
- });
- }
- }
- return expected.clone();
- }
- async getFeeData() {
- const network = await this.getNetwork();
- const getFeeDataFunc = async () => {
- const { _block, gasPrice, priorityFee } = await resolveProperties({
- _block: this.#getBlock("latest", false),
- gasPrice: ((async () => {
- try {
- const value = await this.#perform({ method: "getGasPrice" });
- return getBigInt(value, "%response");
- }
- catch (error) { }
- return null;
- })()),
- priorityFee: ((async () => {
- try {
- const value = await this.#perform({ method: "getPriorityFee" });
- return getBigInt(value, "%response");
- }
- catch (error) { }
- return null;
- })())
- });
- let maxFeePerGas = null;
- let maxPriorityFeePerGas = null;
- // These are the recommended EIP-1559 heuristics for fee data
- const block = this._wrapBlock(_block, network);
- if (block && block.baseFeePerGas) {
- maxPriorityFeePerGas = (priorityFee != null) ? priorityFee : BigInt("1000000000");
- maxFeePerGas = (block.baseFeePerGas * BN_2$1) + maxPriorityFeePerGas;
- }
- return new FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);
- };
- // Check for a FeeDataNetWorkPlugin
- const plugin = network.getPlugin("org.ethers.plugins.network.FetchUrlFeeDataPlugin");
- if (plugin) {
- const req = new FetchRequest(plugin.url);
- const feeData = await plugin.processFunc(getFeeDataFunc, this, req);
- return new FeeData(feeData.gasPrice, feeData.maxFeePerGas, feeData.maxPriorityFeePerGas);
- }
- return await getFeeDataFunc();
- }
- async estimateGas(_tx) {
- let tx = this._getTransactionRequest(_tx);
- if (isPromise$1(tx)) {
- tx = await tx;
- }
- return getBigInt(await this.#perform({
- method: "estimateGas", transaction: tx
- }), "%response");
- }
- async #call(tx, blockTag, attempt) {
- assert(attempt < MAX_CCIP_REDIRECTS, "CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
- reason: "TOO_MANY_REDIRECTS",
- transaction: Object.assign({}, tx, { blockTag, enableCcipRead: true })
- });
- // This came in as a PerformActionTransaction, so to/from are safe; we can cast
- const transaction = copyRequest(tx);
- try {
- return hexlify(await this._perform({ method: "call", transaction, blockTag }));
- }
- catch (error) {
- // CCIP Read OffchainLookup
- if (!this.disableCcipRead && isCallException(error) && error.data && attempt >= 0 && blockTag === "latest" && transaction.to != null && dataSlice(error.data, 0, 4) === "0x556f1830") {
- const data = error.data;
- const txSender = await resolveAddress(transaction.to, this);
- // Parse the CCIP Read Arguments
- let ccipArgs;
- try {
- ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
- }
- catch (error) {
- assert(false, error.message, "OFFCHAIN_FAULT", {
- reason: "BAD_DATA", transaction, info: { data }
- });
- }
- // Check the sender of the OffchainLookup matches the transaction
- assert(ccipArgs.sender.toLowerCase() === txSender.toLowerCase(), "CCIP Read sender mismatch", "CALL_EXCEPTION", {
- action: "call",
- data,
- reason: "OffchainLookup",
- transaction: transaction,
- invocation: null,
- revert: {
- signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
- name: "OffchainLookup",
- args: ccipArgs.errorArgs
- }
- });
- const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
- assert(ccipResult != null, "CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
- reason: "FETCH_FAILED", transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
- });
- const tx = {
- to: txSender,
- data: concat([ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])])
- };
- this.emit("debug", { action: "sendCcipReadCall", transaction: tx });
- try {
- const result = await this.#call(tx, blockTag, attempt + 1);
- this.emit("debug", { action: "receiveCcipReadCallResult", transaction: Object.assign({}, tx), result });
- return result;
- }
- catch (error) {
- this.emit("debug", { action: "receiveCcipReadCallError", transaction: Object.assign({}, tx), error });
- throw error;
- }
- }
- throw error;
- }
- }
- async #checkNetwork(promise) {
- const { value } = await resolveProperties({
- network: this.getNetwork(),
- value: promise
- });
- return value;
- }
- async call(_tx) {
- const { tx, blockTag } = await resolveProperties({
- tx: this._getTransactionRequest(_tx),
- blockTag: this._getBlockTag(_tx.blockTag)
- });
- return await this.#checkNetwork(this.#call(tx, blockTag, _tx.enableCcipRead ? 0 : -1));
- }
- // Account
- async #getAccountValue(request, _address, _blockTag) {
- let address = this._getAddress(_address);
- let blockTag = this._getBlockTag(_blockTag);
- if (typeof (address) !== "string" || typeof (blockTag) !== "string") {
- [address, blockTag] = await Promise.all([address, blockTag]);
- }
- return await this.#checkNetwork(this.#perform(Object.assign(request, { address, blockTag })));
- }
- async getBalance(address, blockTag) {
- return getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
- }
- async getTransactionCount(address, blockTag) {
- return getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
- }
- async getCode(address, blockTag) {
- return hexlify(await this.#getAccountValue({ method: "getCode" }, address, blockTag));
- }
- async getStorage(address, _position, blockTag) {
- const position = getBigInt(_position, "position");
- return hexlify(await this.#getAccountValue({ method: "getStorage", position }, address, blockTag));
- }
- // Write
- async broadcastTransaction(signedTx) {
- const { blockNumber, hash, network } = await resolveProperties({
- blockNumber: this.getBlockNumber(),
- hash: this._perform({
- method: "broadcastTransaction",
- signedTransaction: signedTx
- }),
- network: this.getNetwork()
- });
- const tx = Transaction.from(signedTx);
- if (tx.hash !== hash) {
- throw new Error("@TODO: the returned hash did not match");
- }
- return this._wrapTransactionResponse(tx, network).replaceableTransaction(blockNumber);
- }
- async #getBlock(block, includeTransactions) {
- // @TODO: Add CustomBlockPlugin check
- if (isHexString(block, 32)) {
- return await this.#perform({
- method: "getBlock", blockHash: block, includeTransactions
- });
- }
- let blockTag = this._getBlockTag(block);
- if (typeof (blockTag) !== "string") {
- blockTag = await blockTag;
- }
- return await this.#perform({
- method: "getBlock", blockTag, includeTransactions
- });
- }
- // Queries
- async getBlock(block, prefetchTxs) {
- const { network, params } = await resolveProperties({
- network: this.getNetwork(),
- params: this.#getBlock(block, !!prefetchTxs)
- });
- if (params == null) {
- return null;
- }
- return this._wrapBlock(params, network);
- }
- async getTransaction(hash) {
- const { network, params } = await resolveProperties({
- network: this.getNetwork(),
- params: this.#perform({ method: "getTransaction", hash })
- });
- if (params == null) {
- return null;
- }
- return this._wrapTransactionResponse(params, network);
- }
- async getTransactionReceipt(hash) {
- const { network, params } = await resolveProperties({
- network: this.getNetwork(),
- params: this.#perform({ method: "getTransactionReceipt", hash })
- });
- if (params == null) {
- return null;
- }
- // Some backends did not backfill the effectiveGasPrice into old transactions
- // in the receipt, so we look it up manually and inject it.
- if (params.gasPrice == null && params.effectiveGasPrice == null) {
- const tx = await this.#perform({ method: "getTransaction", hash });
- if (tx == null) {
- throw new Error("report this; could not find tx or effectiveGasPrice");
- }
- params.effectiveGasPrice = tx.gasPrice;
- }
- return this._wrapTransactionReceipt(params, network);
- }
- async getTransactionResult(hash) {
- const { result } = await resolveProperties({
- network: this.getNetwork(),
- result: this.#perform({ method: "getTransactionResult", hash })
- });
- if (result == null) {
- return null;
- }
- return hexlify(result);
- }
- // Bloom-filter Queries
- async getLogs(_filter) {
- let filter = this._getFilter(_filter);
- if (isPromise$1(filter)) {
- filter = await filter;
- }
- const { network, params } = await resolveProperties({
- network: this.getNetwork(),
- params: this.#perform({ method: "getLogs", filter })
- });
- return params.map((p) => this._wrapLog(p, network));
- }
- // ENS
- _getProvider(chainId) {
- assert(false, "provider cannot connect to target network", "UNSUPPORTED_OPERATION", {
- operation: "_getProvider()"
- });
- }
- async getResolver(name) {
- return await EnsResolver.fromName(this, name);
- }
- async getAvatar(name) {
- const resolver = await this.getResolver(name);
- if (resolver) {
- return await resolver.getAvatar();
- }
- return null;
- }
- async resolveName(name) {
- const resolver = await this.getResolver(name);
- if (resolver) {
- return await resolver.getAddress();
- }
- return null;
- }
- async lookupAddress(address) {
- address = getAddress(address);
- const node = namehash(address.substring(2).toLowerCase() + ".addr.reverse");
- try {
- const ensAddr = await EnsResolver.getEnsAddress(this);
- const ensContract = new Contract(ensAddr, [
- "function resolver(bytes32) view returns (address)"
- ], this);
- const resolver = await ensContract.resolver(node);
- if (resolver == null || resolver === ZeroAddress) {
- return null;
- }
- const resolverContract = new Contract(resolver, [
- "function name(bytes32) view returns (string)"
- ], this);
- const name = await resolverContract.name(node);
- // Failed forward resolution
- const check = await this.resolveName(name);
- if (check !== address) {
- return null;
- }
- return name;
- }
- catch (error) {
- // No data was returned from the resolver
- if (isError(error, "BAD_DATA") && error.value === "0x") {
- return null;
- }
- // Something reerted
- if (isError(error, "CALL_EXCEPTION")) {
- return null;
- }
- throw error;
- }
- return null;
- }
- async waitForTransaction(hash, _confirms, timeout) {
- const confirms = (_confirms != null) ? _confirms : 1;
- if (confirms === 0) {
- return this.getTransactionReceipt(hash);
- }
- return new Promise(async (resolve, reject) => {
- let timer = null;
- const listener = (async (blockNumber) => {
- try {
- const receipt = await this.getTransactionReceipt(hash);
- if (receipt != null) {
- if (blockNumber - receipt.blockNumber + 1 >= confirms) {
- resolve(receipt);
- //this.off("block", listener);
- if (timer) {
- clearTimeout(timer);
- timer = null;
- }
- return;
- }
- }
- }
- catch (error) {
- console.log("EEE", error);
- }
- this.once("block", listener);
- });
- if (timeout != null) {
- timer = setTimeout(() => {
- if (timer == null) {
- return;
- }
- timer = null;
- this.off("block", listener);
- reject(makeError("timeout", "TIMEOUT", { reason: "timeout" }));
- }, timeout);
- }
- listener(await this.getBlockNumber());
- });
- }
- async waitForBlock(blockTag) {
- assert(false, "not implemented yet", "NOT_IMPLEMENTED", {
- operation: "waitForBlock"
- });
- }
- /**
- * Clear a timer created using the [[_setTimeout]] method.
- */
- _clearTimeout(timerId) {
- const timer = this.#timers.get(timerId);
- if (!timer) {
- return;
- }
- if (timer.timer) {
- clearTimeout(timer.timer);
- }
- this.#timers.delete(timerId);
- }
- /**
- * Create a timer that will execute %%func%% after at least %%timeout%%
- * (in ms). If %%timeout%% is unspecified, then %%func%% will execute
- * in the next event loop.
- *
- * [Pausing](AbstractProvider-paused) the provider will pause any
- * associated timers.
- */
- _setTimeout(_func, timeout) {
- if (timeout == null) {
- timeout = 0;
- }
- const timerId = this.#nextTimer++;
- const func = () => {
- this.#timers.delete(timerId);
- _func();
- };
- if (this.paused) {
- this.#timers.set(timerId, { timer: null, func, time: timeout });
- }
- else {
- const timer = setTimeout(func, timeout);
- this.#timers.set(timerId, { timer, func, time: getTime$1() });
- }
- return timerId;
- }
- /**
- * Perform %%func%% on each subscriber.
- */
- _forEachSubscriber(func) {
- for (const sub of this.#subs.values()) {
- func(sub.subscriber);
- }
- }
- /**
- * Sub-classes may override this to customize subscription
- * implementations.
- */
- _getSubscriber(sub) {
- switch (sub.type) {
- case "debug":
- case "error":
- case "network":
- return new UnmanagedSubscriber(sub.type);
- case "block": {
- const subscriber = new PollingBlockSubscriber(this);
- subscriber.pollingInterval = this.pollingInterval;
- return subscriber;
- }
- case "safe":
- case "finalized":
- return new PollingBlockTagSubscriber(this, sub.type);
- case "event":
- return new PollingEventSubscriber(this, sub.filter);
- case "transaction":
- return new PollingTransactionSubscriber(this, sub.hash);
- case "orphan":
- return new PollingOrphanSubscriber(this, sub.filter);
- }
- throw new Error(`unsupported event: ${sub.type}`);
- }
- /**
- * If a [[Subscriber]] fails and needs to replace itself, this
- * method may be used.
- *
- * For example, this is used for providers when using the
- * ``eth_getFilterChanges`` method, which can return null if state
- * filters are not supported by the backend, allowing the Subscriber
- * to swap in a [[PollingEventSubscriber]].
- */
- _recoverSubscriber(oldSub, newSub) {
- for (const sub of this.#subs.values()) {
- if (sub.subscriber === oldSub) {
- if (sub.started) {
- sub.subscriber.stop();
- }
- sub.subscriber = newSub;
- if (sub.started) {
- newSub.start();
- }
- if (this.#pausedState != null) {
- newSub.pause(this.#pausedState);
- }
- break;
- }
- }
- }
- async #hasSub(event, emitArgs) {
- let sub = await getSubscription(event, this);
- // This is a log that is removing an existing log; we actually want
- // to emit an orphan event for the removed log
- if (sub.type === "event" && emitArgs && emitArgs.length > 0 && emitArgs[0].removed === true) {
- sub = await getSubscription({ orphan: "drop-log", log: emitArgs[0] }, this);
- }
- return this.#subs.get(sub.tag) || null;
- }
- async #getSub(event) {
- const subscription = await getSubscription(event, this);
- // Prevent tampering with our tag in any subclass' _getSubscriber
- const tag = subscription.tag;
- let sub = this.#subs.get(tag);
- if (!sub) {
- const subscriber = this._getSubscriber(subscription);
- const addressableMap = new WeakMap();
- const nameMap = new Map();
- sub = { subscriber, tag, addressableMap, nameMap, started: false, listeners: [] };
- this.#subs.set(tag, sub);
- }
- return sub;
- }
- async on(event, listener) {
- const sub = await this.#getSub(event);
- sub.listeners.push({ listener, once: false });
- if (!sub.started) {
- sub.subscriber.start();
- sub.started = true;
- if (this.#pausedState != null) {
- sub.subscriber.pause(this.#pausedState);
- }
- }
- return this;
- }
- async once(event, listener) {
- const sub = await this.#getSub(event);
- sub.listeners.push({ listener, once: true });
- if (!sub.started) {
- sub.subscriber.start();
- sub.started = true;
- if (this.#pausedState != null) {
- sub.subscriber.pause(this.#pausedState);
- }
- }
- return this;
- }
- async emit(event, ...args) {
- const sub = await this.#hasSub(event, args);
- // If there is not subscription or if a recent emit removed
- // the last of them (which also deleted the sub) do nothing
- if (!sub || sub.listeners.length === 0) {
- return false;
- }
- const count = sub.listeners.length;
- sub.listeners = sub.listeners.filter(({ listener, once }) => {
- const payload = new EventPayload(this, (once ? null : listener), event);
- try {
- listener.call(this, ...args, payload);
- }
- catch (error) { }
- return !once;
- });
- if (sub.listeners.length === 0) {
- if (sub.started) {
- sub.subscriber.stop();
- }
- this.#subs.delete(sub.tag);
- }
- return (count > 0);
- }
- async listenerCount(event) {
- if (event) {
- const sub = await this.#hasSub(event);
- if (!sub) {
- return 0;
- }
- return sub.listeners.length;
- }
- let total = 0;
- for (const { listeners } of this.#subs.values()) {
- total += listeners.length;
- }
- return total;
- }
- async listeners(event) {
- if (event) {
- const sub = await this.#hasSub(event);
- if (!sub) {
- return [];
- }
- return sub.listeners.map(({ listener }) => listener);
- }
- let result = [];
- for (const { listeners } of this.#subs.values()) {
- result = result.concat(listeners.map(({ listener }) => listener));
- }
- return result;
- }
- async off(event, listener) {
- const sub = await this.#hasSub(event);
- if (!sub) {
- return this;
- }
- if (listener) {
- const index = sub.listeners.map(({ listener }) => listener).indexOf(listener);
- if (index >= 0) {
- sub.listeners.splice(index, 1);
- }
- }
- if (!listener || sub.listeners.length === 0) {
- if (sub.started) {
- sub.subscriber.stop();
- }
- this.#subs.delete(sub.tag);
- }
- return this;
- }
- async removeAllListeners(event) {
- if (event) {
- const { tag, started, subscriber } = await this.#getSub(event);
- if (started) {
- subscriber.stop();
- }
- this.#subs.delete(tag);
- }
- else {
- for (const [tag, { started, subscriber }] of this.#subs) {
- if (started) {
- subscriber.stop();
- }
- this.#subs.delete(tag);
- }
- }
- return this;
- }
- // Alias for "on"
- async addListener(event, listener) {
- return await this.on(event, listener);
- }
- // Alias for "off"
- async removeListener(event, listener) {
- return this.off(event, listener);
- }
- /**
- * If this provider has been destroyed using the [[destroy]] method.
- *
- * Once destroyed, all resources are reclaimed, internal event loops
- * and timers are cleaned up and no further requests may be sent to
- * the provider.
- */
- get destroyed() {
- return this.#destroyed;
- }
- /**
- * Sub-classes may use this to shutdown any sockets or release their
- * resources and reject any pending requests.
- *
- * Sub-classes **must** call ``super.destroy()``.
- */
- destroy() {
- // Stop all listeners
- this.removeAllListeners();
- // Shut down all tiemrs
- for (const timerId of this.#timers.keys()) {
- this._clearTimeout(timerId);
- }
- this.#destroyed = true;
- }
- /**
- * Whether the provider is currently paused.
- *
- * A paused provider will not emit any events, and generally should
- * not make any requests to the network, but that is up to sub-classes
- * to manage.
- *
- * Setting ``paused = true`` is identical to calling ``.pause(false)``,
- * which will buffer any events that occur while paused until the
- * provider is unpaused.
- */
- get paused() { return (this.#pausedState != null); }
- set paused(pause) {
- if (!!pause === this.paused) {
- return;
- }
- if (this.paused) {
- this.resume();
- }
- else {
- this.pause(false);
- }
- }
- /**
- * Pause the provider. If %%dropWhilePaused%%, any events that occur
- * while paused are dropped, otherwise all events will be emitted once
- * the provider is unpaused.
- */
- pause(dropWhilePaused) {
- this.#lastBlockNumber = -1;
- if (this.#pausedState != null) {
- if (this.#pausedState == !!dropWhilePaused) {
- return;
- }
- assert(false, "cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {
- operation: "pause"
- });
- }
- this._forEachSubscriber((s) => s.pause(dropWhilePaused));
- this.#pausedState = !!dropWhilePaused;
- for (const timer of this.#timers.values()) {
- // Clear the timer
- if (timer.timer) {
- clearTimeout(timer.timer);
- }
- // Remaining time needed for when we become unpaused
- timer.time = getTime$1() - timer.time;
- }
- }
- /**
- * Resume the provider.
- */
- resume() {
- if (this.#pausedState == null) {
- return;
- }
- this._forEachSubscriber((s) => s.resume());
- this.#pausedState = null;
- for (const timer of this.#timers.values()) {
- // Remaining time when we were paused
- let timeout = timer.time;
- if (timeout < 0) {
- timeout = 0;
- }
- // Start time (in cause paused, so we con compute remaininf time)
- timer.time = getTime$1();
- // Start the timer
- setTimeout(timer.func, timeout);
- }
- }
- }
- function _parseString(result, start) {
- try {
- const bytes = _parseBytes(result, start);
- if (bytes) {
- return toUtf8String(bytes);
- }
- }
- catch (error) { }
- return null;
- }
- function _parseBytes(result, start) {
- if (result === "0x") {
- return null;
- }
- try {
- const offset = getNumber(dataSlice(result, start, start + 32));
- const length = getNumber(dataSlice(result, offset, offset + 32));
- return dataSlice(result, offset + 32, offset + 32 + length);
- }
- catch (error) { }
- return null;
- }
- function numPad(value) {
- const result = toBeArray(value);
- if (result.length > 32) {
- throw new Error("internal; should not happen");
- }
- const padded = new Uint8Array(32);
- padded.set(result, 32 - result.length);
- return padded;
- }
- function bytesPad(value) {
- if ((value.length % 32) === 0) {
- return value;
- }
- const result = new Uint8Array(Math.ceil(value.length / 32) * 32);
- result.set(value);
- return result;
- }
- const empty = new Uint8Array([]);
- // ABI Encodes a series of (bytes, bytes, ...)
- function encodeBytes(datas) {
- const result = [];
- let byteCount = 0;
- // Add place-holders for pointers as we add items
- for (let i = 0; i < datas.length; i++) {
- result.push(empty);
- byteCount += 32;
- }
- for (let i = 0; i < datas.length; i++) {
- const data = getBytes(datas[i]);
- // Update the bytes offset
- result[i] = numPad(byteCount);
- // The length and padded value of data
- result.push(numPad(data.length));
- result.push(bytesPad(data));
- byteCount += 32 + Math.ceil(data.length / 32) * 32;
- }
- return concat(result);
- }
- const zeros = "0x0000000000000000000000000000000000000000000000000000000000000000";
- function parseOffchainLookup(data) {
- const result = {
- sender: "", urls: [], calldata: "", selector: "", extraData: "", errorArgs: []
- };
- assert(dataLength(data) >= 5 * 32, "insufficient OffchainLookup data", "OFFCHAIN_FAULT", {
- reason: "insufficient OffchainLookup data"
- });
- const sender = dataSlice(data, 0, 32);
- assert(dataSlice(sender, 0, 12) === dataSlice(zeros, 0, 12), "corrupt OffchainLookup sender", "OFFCHAIN_FAULT", {
- reason: "corrupt OffchainLookup sender"
- });
- result.sender = dataSlice(sender, 12);
- // Read the URLs from the response
- try {
- const urls = [];
- const urlsOffset = getNumber(dataSlice(data, 32, 64));
- const urlsLength = getNumber(dataSlice(data, urlsOffset, urlsOffset + 32));
- const urlsData = dataSlice(data, urlsOffset + 32);
- for (let u = 0; u < urlsLength; u++) {
- const url = _parseString(urlsData, u * 32);
- if (url == null) {
- throw new Error("abort");
- }
- urls.push(url);
- }
- result.urls = urls;
- }
- catch (error) {
- assert(false, "corrupt OffchainLookup urls", "OFFCHAIN_FAULT", {
- reason: "corrupt OffchainLookup urls"
- });
- }
- // Get the CCIP calldata to forward
- try {
- const calldata = _parseBytes(data, 64);
- if (calldata == null) {
- throw new Error("abort");
- }
- result.calldata = calldata;
- }
- catch (error) {
- assert(false, "corrupt OffchainLookup calldata", "OFFCHAIN_FAULT", {
- reason: "corrupt OffchainLookup calldata"
- });
- }
- // Get the callbackSelector (bytes4)
- assert(dataSlice(data, 100, 128) === dataSlice(zeros, 0, 28), "corrupt OffchainLookup callbaackSelector", "OFFCHAIN_FAULT", {
- reason: "corrupt OffchainLookup callbaackSelector"
- });
- result.selector = dataSlice(data, 96, 100);
- // Get the extra data to send back to the contract as context
- try {
- const extraData = _parseBytes(data, 128);
- if (extraData == null) {
- throw new Error("abort");
- }
- result.extraData = extraData;
- }
- catch (error) {
- assert(false, "corrupt OffchainLookup extraData", "OFFCHAIN_FAULT", {
- reason: "corrupt OffchainLookup extraData"
- });
- }
- result.errorArgs = "sender,urls,calldata,selector,extraData".split(/,/).map((k) => result[k]);
- return result;
- }
- /**
- * Generally the [[Wallet]] and [[JsonRpcSigner]] and their sub-classes
- * are sufficent for most developers, but this is provided to
- * fascilitate more complex Signers.
- *
- * @_section: api/providers/abstract-signer: Subclassing Signer [abstract-signer]
- */
- function checkProvider(signer, operation) {
- if (signer.provider) {
- return signer.provider;
- }
- assert(false, "missing provider", "UNSUPPORTED_OPERATION", { operation });
- }
- async function populate(signer, tx) {
- let pop = copyRequest(tx);
- if (pop.to != null) {
- pop.to = resolveAddress(pop.to, signer);
- }
- if (pop.from != null) {
- const from = pop.from;
- pop.from = Promise.all([
- signer.getAddress(),
- resolveAddress(from, signer)
- ]).then(([address, from]) => {
- assertArgument(address.toLowerCase() === from.toLowerCase(), "transaction from mismatch", "tx.from", from);
- return address;
- });
- }
- else {
- pop.from = signer.getAddress();
- }
- return await resolveProperties(pop);
- }
- /**
- * An **AbstractSigner** includes most of teh functionality required
- * to get a [[Signer]] working as expected, but requires a few
- * Signer-specific methods be overridden.
- *
- */
- class AbstractSigner {
- /**
- * The provider this signer is connected to.
- */
- provider;
- /**
- * Creates a new Signer connected to %%provider%%.
- */
- constructor(provider) {
- defineProperties(this, { provider: (provider || null) });
- }
- async getNonce(blockTag) {
- return checkProvider(this, "getTransactionCount").getTransactionCount(await this.getAddress(), blockTag);
- }
- async populateCall(tx) {
- const pop = await populate(this, tx);
- return pop;
- }
- async populateTransaction(tx) {
- const provider = checkProvider(this, "populateTransaction");
- const pop = await populate(this, tx);
- if (pop.nonce == null) {
- pop.nonce = await this.getNonce("pending");
- }
- if (pop.gasLimit == null) {
- pop.gasLimit = await this.estimateGas(pop);
- }
- // Populate the chain ID
- const network = await (this.provider).getNetwork();
- if (pop.chainId != null) {
- const chainId = getBigInt(pop.chainId);
- assertArgument(chainId === network.chainId, "transaction chainId mismatch", "tx.chainId", tx.chainId);
- }
- else {
- pop.chainId = network.chainId;
- }
- // Do not allow mixing pre-eip-1559 and eip-1559 properties
- const hasEip1559 = (pop.maxFeePerGas != null || pop.maxPriorityFeePerGas != null);
- if (pop.gasPrice != null && (pop.type === 2 || hasEip1559)) {
- assertArgument(false, "eip-1559 transaction do not support gasPrice", "tx", tx);
- }
- else if ((pop.type === 0 || pop.type === 1) && hasEip1559) {
- assertArgument(false, "pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas", "tx", tx);
- }
- if ((pop.type === 2 || pop.type == null) && (pop.maxFeePerGas != null && pop.maxPriorityFeePerGas != null)) {
- // Fully-formed EIP-1559 transaction (skip getFeeData)
- pop.type = 2;
- }
- else if (pop.type === 0 || pop.type === 1) {
- // Explicit Legacy or EIP-2930 transaction
- // We need to get fee data to determine things
- const feeData = await provider.getFeeData();
- assert(feeData.gasPrice != null, "network does not support gasPrice", "UNSUPPORTED_OPERATION", {
- operation: "getGasPrice"
- });
- // Populate missing gasPrice
- if (pop.gasPrice == null) {
- pop.gasPrice = feeData.gasPrice;
- }
- }
- else {
- // We need to get fee data to determine things
- const feeData = await provider.getFeeData();
- if (pop.type == null) {
- // We need to auto-detect the intended type of this transaction...
- if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
- // The network supports EIP-1559!
- // Upgrade transaction from null to eip-1559
- pop.type = 2;
- if (pop.gasPrice != null) {
- // Using legacy gasPrice property on an eip-1559 network,
- // so use gasPrice as both fee properties
- const gasPrice = pop.gasPrice;
- delete pop.gasPrice;
- pop.maxFeePerGas = gasPrice;
- pop.maxPriorityFeePerGas = gasPrice;
- }
- else {
- // Populate missing fee data
- if (pop.maxFeePerGas == null) {
- pop.maxFeePerGas = feeData.maxFeePerGas;
- }
- if (pop.maxPriorityFeePerGas == null) {
- pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
- }
- }
- }
- else if (feeData.gasPrice != null) {
- // Network doesn't support EIP-1559...
- // ...but they are trying to use EIP-1559 properties
- assert(!hasEip1559, "network does not support EIP-1559", "UNSUPPORTED_OPERATION", {
- operation: "populateTransaction"
- });
- // Populate missing fee data
- if (pop.gasPrice == null) {
- pop.gasPrice = feeData.gasPrice;
- }
- // Explicitly set untyped transaction to legacy
- // @TODO: Maybe this shold allow type 1?
- pop.type = 0;
- }
- else {
- // getFeeData has failed us.
- assert(false, "failed to get consistent fee data", "UNSUPPORTED_OPERATION", {
- operation: "signer.getFeeData"
- });
- }
- }
- else if (pop.type === 2 || pop.type === 3) {
- // Explicitly using EIP-1559 or EIP-4844
- // Populate missing fee data
- if (pop.maxFeePerGas == null) {
- pop.maxFeePerGas = feeData.maxFeePerGas;
- }
- if (pop.maxPriorityFeePerGas == null) {
- pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
- }
- }
- }
- //@TOOD: Don't await all over the place; save them up for
- // the end for better batching
- return await resolveProperties(pop);
- }
- async estimateGas(tx) {
- return checkProvider(this, "estimateGas").estimateGas(await this.populateCall(tx));
- }
- async call(tx) {
- return checkProvider(this, "call").call(await this.populateCall(tx));
- }
- async resolveName(name) {
- const provider = checkProvider(this, "resolveName");
- return await provider.resolveName(name);
- }
- async sendTransaction(tx) {
- const provider = checkProvider(this, "sendTransaction");
- const pop = await this.populateTransaction(tx);
- delete pop.from;
- const txObj = Transaction.from(pop);
- return await provider.broadcastTransaction(await this.signTransaction(txObj));
- }
- }
- /**
- * A **VoidSigner** is a class deisgned to allow an address to be used
- * in any API which accepts a Signer, but for which there are no
- * credentials available to perform any actual signing.
- *
- * This for example allow impersonating an account for the purpose of
- * static calls or estimating gas, but does not allow sending transactions.
- */
- class VoidSigner extends AbstractSigner {
- /**
- * The signer address.
- */
- address;
- /**
- * Creates a new **VoidSigner** with %%address%% attached to
- * %%provider%%.
- */
- constructor(address, provider) {
- super(provider);
- defineProperties(this, { address });
- }
- async getAddress() { return this.address; }
- connect(provider) {
- return new VoidSigner(this.address, provider);
- }
- #throwUnsupported(suffix, operation) {
- assert(false, `VoidSigner cannot sign ${suffix}`, "UNSUPPORTED_OPERATION", { operation });
- }
- async signTransaction(tx) {
- this.#throwUnsupported("transactions", "signTransaction");
- }
- async signMessage(message) {
- this.#throwUnsupported("messages", "signMessage");
- }
- async signTypedData(domain, types, value) {
- this.#throwUnsupported("typed-data", "signTypedData");
- }
- }
- /**
- * There are many awesome community services that provide Ethereum
- * nodes both for developers just starting out and for large-scale
- * communities.
- *
- * @_section: api/providers/thirdparty: Community Providers [thirdparty]
- */
- // Show the throttle message only once per service
- const shown = new Set();
- /**
- * Displays a warning in tht console when the community resource is
- * being used too heavily by the app, recommending the developer
- * acquire their own credentials instead of using the community
- * credentials.
- *
- * The notification will only occur once per service.
- */
- function showThrottleMessage(service) {
- if (shown.has(service)) {
- return;
- }
- shown.add(service);
- console.log("========= NOTICE =========");
- console.log(`Request-Rate Exceeded for ${service} (this message will not be repeated)`);
- console.log("");
- console.log("The default API keys for each service are provided as a highly-throttled,");
- console.log("community resource for low-traffic projects and early prototyping.");
- console.log("");
- console.log("While your application will continue to function, we highly recommended");
- console.log("signing up for your own API keys to improve performance, increase your");
- console.log("request rate/limit and enable other perks, such as metrics and advanced APIs.");
- console.log("");
- console.log("For more details: https:/\/docs.ethers.org/api-keys/");
- console.log("==========================");
- }
- function copy(obj) {
- return JSON.parse(JSON.stringify(obj));
- }
- /**
- * Some backends support subscribing to events using a Filter ID.
- *
- * When subscribing with this technique, the node issues a unique
- * //Filter ID//. At this point the node dedicates resources to
- * the filter, so that periodic calls to follow up on the //Filter ID//
- * will receive any events since the last call.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class FilterIdSubscriber {
- #provider;
- #filterIdPromise;
- #poller;
- #running;
- #network;
- #hault;
- /**
- * Creates a new **FilterIdSubscriber** which will used [[_subscribe]]
- * and [[_emitResults]] to setup the subscription and provide the event
- * to the %%provider%%.
- */
- constructor(provider) {
- this.#provider = provider;
- this.#filterIdPromise = null;
- this.#poller = this.#poll.bind(this);
- this.#running = false;
- this.#network = null;
- this.#hault = false;
- }
- /**
- * Sub-classes **must** override this to begin the subscription.
- */
- _subscribe(provider) {
- throw new Error("subclasses must override this");
- }
- /**
- * Sub-classes **must** override this handle the events.
- */
- _emitResults(provider, result) {
- throw new Error("subclasses must override this");
- }
- /**
- * Sub-classes **must** override this handle recovery on errors.
- */
- _recover(provider) {
- throw new Error("subclasses must override this");
- }
- async #poll(blockNumber) {
- try {
- // Subscribe if necessary
- if (this.#filterIdPromise == null) {
- this.#filterIdPromise = this._subscribe(this.#provider);
- }
- // Get the Filter ID
- let filterId = null;
- try {
- filterId = await this.#filterIdPromise;
- }
- catch (error) {
- if (!isError(error, "UNSUPPORTED_OPERATION") || error.operation !== "eth_newFilter") {
- throw error;
- }
- }
- // The backend does not support Filter ID; downgrade to
- // polling
- if (filterId == null) {
- this.#filterIdPromise = null;
- this.#provider._recoverSubscriber(this, this._recover(this.#provider));
- return;
- }
- const network = await this.#provider.getNetwork();
- if (!this.#network) {
- this.#network = network;
- }
- if (this.#network.chainId !== network.chainId) {
- throw new Error("chaid changed");
- }
- if (this.#hault) {
- return;
- }
- const result = await this.#provider.send("eth_getFilterChanges", [filterId]);
- await this._emitResults(this.#provider, result);
- }
- catch (error) {
- console.log("@TODO", error);
- }
- this.#provider.once("block", this.#poller);
- }
- #teardown() {
- const filterIdPromise = this.#filterIdPromise;
- if (filterIdPromise) {
- this.#filterIdPromise = null;
- filterIdPromise.then((filterId) => {
- if (this.#provider.destroyed) {
- return;
- }
- this.#provider.send("eth_uninstallFilter", [filterId]);
- });
- }
- }
- start() {
- if (this.#running) {
- return;
- }
- this.#running = true;
- this.#poll(-2);
- }
- stop() {
- if (!this.#running) {
- return;
- }
- this.#running = false;
- this.#hault = true;
- this.#teardown();
- this.#provider.off("block", this.#poller);
- }
- pause(dropWhilePaused) {
- if (dropWhilePaused) {
- this.#teardown();
- }
- this.#provider.off("block", this.#poller);
- }
- resume() { this.start(); }
- }
- /**
- * A **FilterIdSubscriber** for receiving contract events.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class FilterIdEventSubscriber extends FilterIdSubscriber {
- #event;
- /**
- * Creates a new **FilterIdEventSubscriber** attached to %%provider%%
- * listening for %%filter%%.
- */
- constructor(provider, filter) {
- super(provider);
- this.#event = copy(filter);
- }
- _recover(provider) {
- return new PollingEventSubscriber(provider, this.#event);
- }
- async _subscribe(provider) {
- const filterId = await provider.send("eth_newFilter", [this.#event]);
- return filterId;
- }
- async _emitResults(provider, results) {
- for (const result of results) {
- provider.emit(this.#event, provider._wrapLog(result, provider._network));
- }
- }
- }
- /**
- * A **FilterIdSubscriber** for receiving pending transactions events.
- *
- * @_docloc: api/providers/abstract-provider
- */
- class FilterIdPendingSubscriber extends FilterIdSubscriber {
- async _subscribe(provider) {
- return await provider.send("eth_newPendingTransactionFilter", []);
- }
- async _emitResults(provider, results) {
- for (const result of results) {
- provider.emit("pending", result);
- }
- }
- }
- /**
- * One of the most common ways to interact with the blockchain is
- * by a node running a JSON-RPC interface which can be connected to,
- * based on the transport, using:
- *
- * - HTTP or HTTPS - [[JsonRpcProvider]]
- * - WebSocket - [[WebSocketProvider]]
- * - IPC - [[IpcSocketProvider]]
- *
- * @_section: api/providers/jsonrpc:JSON-RPC Provider [about-jsonrpcProvider]
- */
- // @TODO:
- // - Add the batching API
- // https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
- const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g);
- //const Methods = "getAddress,then".split(/,/g);
- function deepCopy(value) {
- if (value == null || Primitive.indexOf(typeof (value)) >= 0) {
- return value;
- }
- // Keep any Addressable
- if (typeof (value.getAddress) === "function") {
- return value;
- }
- if (Array.isArray(value)) {
- return (value.map(deepCopy));
- }
- if (typeof (value) === "object") {
- return Object.keys(value).reduce((accum, key) => {
- accum[key] = value[key];
- return accum;
- }, {});
- }
- throw new Error(`should not happen: ${value} (${typeof (value)})`);
- }
- function stall$3(duration) {
- return new Promise((resolve) => { setTimeout(resolve, duration); });
- }
- function getLowerCase(value) {
- if (value) {
- return value.toLowerCase();
- }
- return value;
- }
- function isPollable(value) {
- return (value && typeof (value.pollingInterval) === "number");
- }
- const defaultOptions = {
- polling: false,
- staticNetwork: null,
- batchStallTime: 10,
- batchMaxSize: (1 << 20),
- batchMaxCount: 100,
- cacheTimeout: 250,
- pollingInterval: 4000
- };
- // @TODO: Unchecked Signers
- class JsonRpcSigner extends AbstractSigner {
- address;
- constructor(provider, address) {
- super(provider);
- address = getAddress(address);
- defineProperties(this, { address });
- }
- connect(provider) {
- assert(false, "cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
- operation: "signer.connect"
- });
- }
- async getAddress() {
- return this.address;
- }
- // JSON-RPC will automatially fill in nonce, etc. so we just check from
- async populateTransaction(tx) {
- return await this.populateCall(tx);
- }
- // Returns just the hash of the transaction after sent, which is what
- // the bare JSON-RPC API does;
- async sendUncheckedTransaction(_tx) {
- const tx = deepCopy(_tx);
- const promises = [];
- // Make sure the from matches the sender
- if (tx.from) {
- const _from = tx.from;
- promises.push((async () => {
- const from = await resolveAddress(_from, this.provider);
- assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), "from address mismatch", "transaction", _tx);
- tx.from = from;
- })());
- }
- else {
- tx.from = this.address;
- }
- // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user
- // wishes to use this, it is easy to specify explicitly, otherwise
- // we look it up for them.
- if (tx.gasLimit == null) {
- promises.push((async () => {
- tx.gasLimit = await this.provider.estimateGas({ ...tx, from: this.address });
- })());
- }
- // The address may be an ENS name or Addressable
- if (tx.to != null) {
- const _to = tx.to;
- promises.push((async () => {
- tx.to = await resolveAddress(_to, this.provider);
- })());
- }
- // Wait until all of our properties are filled in
- if (promises.length) {
- await Promise.all(promises);
- }
- const hexTx = this.provider.getRpcTransaction(tx);
- return this.provider.send("eth_sendTransaction", [hexTx]);
- }
- async sendTransaction(tx) {
- // This cannot be mined any earlier than any recent block
- const blockNumber = await this.provider.getBlockNumber();
- // Send the transaction
- const hash = await this.sendUncheckedTransaction(tx);
- // Unfortunately, JSON-RPC only provides and opaque transaction hash
- // for a response, and we need the actual transaction, so we poll
- // for it; it should show up very quickly
- return await (new Promise((resolve, reject) => {
- const timeouts = [1000, 100];
- let invalids = 0;
- const checkTx = async () => {
- try {
- // Try getting the transaction
- const tx = await this.provider.getTransaction(hash);
- if (tx != null) {
- resolve(tx.replaceableTransaction(blockNumber));
- return;
- }
- }
- catch (error) {
- // If we were cancelled: stop polling.
- // If the data is bad: the node returns bad transactions
- // If the network changed: calling again will also fail
- // If unsupported: likely destroyed
- if (isError(error, "CANCELLED") || isError(error, "BAD_DATA") ||
- isError(error, "NETWORK_ERROR") || isError(error, "UNSUPPORTED_OPERATION")) {
- if (error.info == null) {
- error.info = {};
- }
- error.info.sendTransactionHash = hash;
- reject(error);
- return;
- }
- // Stop-gap for misbehaving backends; see #4513
- if (isError(error, "INVALID_ARGUMENT")) {
- invalids++;
- if (error.info == null) {
- error.info = {};
- }
- error.info.sendTransactionHash = hash;
- if (invalids > 10) {
- reject(error);
- return;
- }
- }
- // Notify anyone that cares; but we will try again, since
- // it is likely an intermittent service error
- this.provider.emit("error", makeError("failed to fetch transation after sending (will try again)", "UNKNOWN_ERROR", { error }));
- }
- // Wait another 4 seconds
- this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000);
- };
- checkTx();
- }));
- }
- async signTransaction(_tx) {
- const tx = deepCopy(_tx);
- // Make sure the from matches the sender
- if (tx.from) {
- const from = await resolveAddress(tx.from, this.provider);
- assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(), "from address mismatch", "transaction", _tx);
- tx.from = from;
- }
- else {
- tx.from = this.address;
- }
- const hexTx = this.provider.getRpcTransaction(tx);
- return await this.provider.send("eth_signTransaction", [hexTx]);
- }
- async signMessage(_message) {
- const message = ((typeof (_message) === "string") ? toUtf8Bytes(_message) : _message);
- return await this.provider.send("personal_sign", [
- hexlify(message), this.address.toLowerCase()
- ]);
- }
- async signTypedData(domain, types, _value) {
- const value = deepCopy(_value);
- // Populate any ENS names (in-place)
- const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (value) => {
- const address = await resolveAddress(value);
- assertArgument(address != null, "TypedData does not support null address", "value", value);
- return address;
- });
- return await this.provider.send("eth_signTypedData_v4", [
- this.address.toLowerCase(),
- JSON.stringify(TypedDataEncoder.getPayload(populated.domain, types, populated.value))
- ]);
- }
- async unlock(password) {
- return this.provider.send("personal_unlockAccount", [
- this.address.toLowerCase(), password, null
- ]);
- }
- // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
- async _legacySignMessage(_message) {
- const message = ((typeof (_message) === "string") ? toUtf8Bytes(_message) : _message);
- return await this.provider.send("eth_sign", [
- this.address.toLowerCase(), hexlify(message)
- ]);
- }
- }
- /**
- * The JsonRpcApiProvider is an abstract class and **MUST** be
- * sub-classed.
- *
- * It provides the base for all JSON-RPC-based Provider interaction.
- *
- * Sub-classing Notes:
- * - a sub-class MUST override _send
- * - a sub-class MUST call the `_start()` method once connected
- */
- class JsonRpcApiProvider extends AbstractProvider {
- #options;
- // The next ID to use for the JSON-RPC ID field
- #nextId;
- // Payloads are queued and triggered in batches using the drainTimer
- #payloads;
- #drainTimer;
- #notReady;
- #network;
- #pendingDetectNetwork;
- #scheduleDrain() {
- if (this.#drainTimer) {
- return;
- }
- // If we aren't using batching, no harm in sending it immediately
- const stallTime = (this._getOption("batchMaxCount") === 1) ? 0 : this._getOption("batchStallTime");
- this.#drainTimer = setTimeout(() => {
- this.#drainTimer = null;
- const payloads = this.#payloads;
- this.#payloads = [];
- while (payloads.length) {
- // Create payload batches that satisfy our batch constraints
- const batch = [(payloads.shift())];
- while (payloads.length) {
- if (batch.length === this.#options.batchMaxCount) {
- break;
- }
- batch.push((payloads.shift()));
- const bytes = JSON.stringify(batch.map((p) => p.payload));
- if (bytes.length > this.#options.batchMaxSize) {
- payloads.unshift((batch.pop()));
- break;
- }
- }
- // Process the result to each payload
- (async () => {
- const payload = ((batch.length === 1) ? batch[0].payload : batch.map((p) => p.payload));
- this.emit("debug", { action: "sendRpcPayload", payload });
- try {
- const result = await this._send(payload);
- this.emit("debug", { action: "receiveRpcResult", result });
- // Process results in batch order
- for (const { resolve, reject, payload } of batch) {
- if (this.destroyed) {
- reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: payload.method }));
- continue;
- }
- // Find the matching result
- const resp = result.filter((r) => (r.id === payload.id))[0];
- // No result; the node failed us in unexpected ways
- if (resp == null) {
- const error = makeError("missing response for request", "BAD_DATA", {
- value: result, info: { payload }
- });
- this.emit("error", error);
- reject(error);
- continue;
- }
- // The response is an error
- if ("error" in resp) {
- reject(this.getRpcError(payload, resp));
- continue;
- }
- // All good; send the result
- resolve(resp.result);
- }
- }
- catch (error) {
- this.emit("debug", { action: "receiveRpcError", error });
- for (const { reject } of batch) {
- // @TODO: augment the error with the payload
- reject(error);
- }
- }
- })();
- }
- }, stallTime);
- }
- constructor(network, options) {
- super(network, options);
- this.#nextId = 1;
- this.#options = Object.assign({}, defaultOptions, options || {});
- this.#payloads = [];
- this.#drainTimer = null;
- this.#network = null;
- this.#pendingDetectNetwork = null;
- {
- let resolve = null;
- const promise = new Promise((_resolve) => {
- resolve = _resolve;
- });
- this.#notReady = { promise, resolve };
- }
- const staticNetwork = this._getOption("staticNetwork");
- if (typeof (staticNetwork) === "boolean") {
- assertArgument(!staticNetwork || network !== "any", "staticNetwork cannot be used on special network 'any'", "options", options);
- if (staticNetwork && network != null) {
- this.#network = Network.from(network);
- }
- }
- else if (staticNetwork) {
- // Make sure any static network is compatbile with the provided netwrok
- assertArgument(network == null || staticNetwork.matches(network), "staticNetwork MUST match network object", "options", options);
- this.#network = staticNetwork;
- }
- }
- /**
- * Returns the value associated with the option %%key%%.
- *
- * Sub-classes can use this to inquire about configuration options.
- */
- _getOption(key) {
- return this.#options[key];
- }
- /**
- * Gets the [[Network]] this provider has committed to. On each call, the network
- * is detected, and if it has changed, the call will reject.
- */
- get _network() {
- assert(this.#network, "network is not available yet", "NETWORK_ERROR");
- return this.#network;
- }
- /**
- * Resolves to the non-normalized value by performing %%req%%.
- *
- * Sub-classes may override this to modify behavior of actions,
- * and should generally call ``super._perform`` as a fallback.
- */
- async _perform(req) {
- // Legacy networks do not like the type field being passed along (which
- // is fair), so we delete type if it is 0 and a non-EIP-1559 network
- if (req.method === "call" || req.method === "estimateGas") {
- let tx = req.transaction;
- if (tx && tx.type != null && getBigInt(tx.type)) {
- // If there are no EIP-1559 or newer properties, it might be pre-EIP-1559
- if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
- const feeData = await this.getFeeData();
- if (feeData.maxFeePerGas == null && feeData.maxPriorityFeePerGas == null) {
- // Network doesn't know about EIP-1559 (and hence type)
- req = Object.assign({}, req, {
- transaction: Object.assign({}, tx, { type: undefined })
- });
- }
- }
- }
- }
- const request = this.getRpcRequest(req);
- if (request != null) {
- return await this.send(request.method, request.args);
- }
- return super._perform(req);
- }
- /**
- * Sub-classes may override this; it detects the *actual* network that
- * we are **currently** connected to.
- *
- * Keep in mind that [[send]] may only be used once [[ready]], otherwise the
- * _send primitive must be used instead.
- */
- async _detectNetwork() {
- const network = this._getOption("staticNetwork");
- if (network) {
- if (network === true) {
- if (this.#network) {
- return this.#network;
- }
- }
- else {
- return network;
- }
- }
- if (this.#pendingDetectNetwork) {
- return await this.#pendingDetectNetwork;
- }
- // If we are ready, use ``send``, which enabled requests to be batched
- if (this.ready) {
- this.#pendingDetectNetwork = (async () => {
- try {
- const result = Network.from(getBigInt(await this.send("eth_chainId", [])));
- this.#pendingDetectNetwork = null;
- return result;
- }
- catch (error) {
- this.#pendingDetectNetwork = null;
- throw error;
- }
- })();
- return await this.#pendingDetectNetwork;
- }
- // We are not ready yet; use the primitive _send
- this.#pendingDetectNetwork = (async () => {
- const payload = {
- id: this.#nextId++, method: "eth_chainId", params: [], jsonrpc: "2.0"
- };
- this.emit("debug", { action: "sendRpcPayload", payload });
- let result;
- try {
- result = (await this._send(payload))[0];
- this.#pendingDetectNetwork = null;
- }
- catch (error) {
- this.#pendingDetectNetwork = null;
- this.emit("debug", { action: "receiveRpcError", error });
- throw error;
- }
- this.emit("debug", { action: "receiveRpcResult", result });
- if ("result" in result) {
- return Network.from(getBigInt(result.result));
- }
- throw this.getRpcError(payload, result);
- })();
- return await this.#pendingDetectNetwork;
- }
- /**
- * Sub-classes **MUST** call this. Until [[_start]] has been called, no calls
- * will be passed to [[_send]] from [[send]]. If it is overridden, then
- * ``super._start()`` **MUST** be called.
- *
- * Calling it multiple times is safe and has no effect.
- */
- _start() {
- if (this.#notReady == null || this.#notReady.resolve == null) {
- return;
- }
- this.#notReady.resolve();
- this.#notReady = null;
- (async () => {
- // Bootstrap the network
- while (this.#network == null && !this.destroyed) {
- try {
- this.#network = await this._detectNetwork();
- }
- catch (error) {
- if (this.destroyed) {
- break;
- }
- console.log("JsonRpcProvider failed to detect network and cannot start up; retry in 1s (perhaps the URL is wrong or the node is not started)");
- this.emit("error", makeError("failed to bootstrap network detection", "NETWORK_ERROR", { event: "initial-network-discovery", info: { error } }));
- await stall$3(1000);
- }
- }
- // Start dispatching requests
- this.#scheduleDrain();
- })();
- }
- /**
- * Resolves once the [[_start]] has been called. This can be used in
- * sub-classes to defer sending data until the connection has been
- * established.
- */
- async _waitUntilReady() {
- if (this.#notReady == null) {
- return;
- }
- return await this.#notReady.promise;
- }
- /**
- * Return a Subscriber that will manage the %%sub%%.
- *
- * Sub-classes may override this to modify the behavior of
- * subscription management.
- */
- _getSubscriber(sub) {
- // Pending Filters aren't availble via polling
- if (sub.type === "pending") {
- return new FilterIdPendingSubscriber(this);
- }
- if (sub.type === "event") {
- if (this._getOption("polling")) {
- return new PollingEventSubscriber(this, sub.filter);
- }
- return new FilterIdEventSubscriber(this, sub.filter);
- }
- // Orphaned Logs are handled automatically, by the filter, since
- // logs with removed are emitted by it
- if (sub.type === "orphan" && sub.filter.orphan === "drop-log") {
- return new UnmanagedSubscriber("orphan");
- }
- return super._getSubscriber(sub);
- }
- /**
- * Returns true only if the [[_start]] has been called.
- */
- get ready() { return this.#notReady == null; }
- /**
- * Returns %%tx%% as a normalized JSON-RPC transaction request,
- * which has all values hexlified and any numeric values converted
- * to Quantity values.
- */
- getRpcTransaction(tx) {
- const result = {};
- // JSON-RPC now requires numeric values to be "quantity" values
- ["chainId", "gasLimit", "gasPrice", "type", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "value"].forEach((key) => {
- if (tx[key] == null) {
- return;
- }
- let dstKey = key;
- if (key === "gasLimit") {
- dstKey = "gas";
- }
- result[dstKey] = toQuantity(getBigInt(tx[key], `tx.${key}`));
- });
- // Make sure addresses and data are lowercase
- ["from", "to", "data"].forEach((key) => {
- if (tx[key] == null) {
- return;
- }
- result[key] = hexlify(tx[key]);
- });
- // Normalize the access list object
- if (tx.accessList) {
- result["accessList"] = accessListify(tx.accessList);
- }
- if (tx.blobVersionedHashes) {
- // @TODO: Remove this <any> case once EIP-4844 added to prepared tx
- result["blobVersionedHashes"] = tx.blobVersionedHashes.map(h => h.toLowerCase());
- }
- // @TODO: blobs should probably also be copied over, optionally
- // accounting for the kzg property to backfill blobVersionedHashes
- // using the commitment. Or should that be left as an exercise to
- // the caller?
- return result;
- }
- /**
- * Returns the request method and arguments required to perform
- * %%req%%.
- */
- getRpcRequest(req) {
- switch (req.method) {
- case "chainId":
- return { method: "eth_chainId", args: [] };
- case "getBlockNumber":
- return { method: "eth_blockNumber", args: [] };
- case "getGasPrice":
- return { method: "eth_gasPrice", args: [] };
- case "getPriorityFee":
- return { method: "eth_maxPriorityFeePerGas", args: [] };
- case "getBalance":
- return {
- method: "eth_getBalance",
- args: [getLowerCase(req.address), req.blockTag]
- };
- case "getTransactionCount":
- return {
- method: "eth_getTransactionCount",
- args: [getLowerCase(req.address), req.blockTag]
- };
- case "getCode":
- return {
- method: "eth_getCode",
- args: [getLowerCase(req.address), req.blockTag]
- };
- case "getStorage":
- return {
- method: "eth_getStorageAt",
- args: [
- getLowerCase(req.address),
- ("0x" + req.position.toString(16)),
- req.blockTag
- ]
- };
- case "broadcastTransaction":
- return {
- method: "eth_sendRawTransaction",
- args: [req.signedTransaction]
- };
- case "getBlock":
- if ("blockTag" in req) {
- return {
- method: "eth_getBlockByNumber",
- args: [req.blockTag, !!req.includeTransactions]
- };
- }
- else if ("blockHash" in req) {
- return {
- method: "eth_getBlockByHash",
- args: [req.blockHash, !!req.includeTransactions]
- };
- }
- break;
- case "getTransaction":
- return {
- method: "eth_getTransactionByHash",
- args: [req.hash]
- };
- case "getTransactionReceipt":
- return {
- method: "eth_getTransactionReceipt",
- args: [req.hash]
- };
- case "call":
- return {
- method: "eth_call",
- args: [this.getRpcTransaction(req.transaction), req.blockTag]
- };
- case "estimateGas": {
- return {
- method: "eth_estimateGas",
- args: [this.getRpcTransaction(req.transaction)]
- };
- }
- case "getLogs":
- if (req.filter && req.filter.address != null) {
- if (Array.isArray(req.filter.address)) {
- req.filter.address = req.filter.address.map(getLowerCase);
- }
- else {
- req.filter.address = getLowerCase(req.filter.address);
- }
- }
- return { method: "eth_getLogs", args: [req.filter] };
- }
- return null;
- }
- /**
- * Returns an ethers-style Error for the given JSON-RPC error
- * %%payload%%, coalescing the various strings and error shapes
- * that different nodes return, coercing them into a machine-readable
- * standardized error.
- */
- getRpcError(payload, _error) {
- const { method } = payload;
- const { error } = _error;
- if (method === "eth_estimateGas" && error.message) {
- const msg = error.message;
- if (!msg.match(/revert/i) && msg.match(/insufficient funds/i)) {
- return makeError("insufficient funds", "INSUFFICIENT_FUNDS", {
- transaction: (payload.params[0]),
- info: { payload, error }
- });
- }
- }
- if (method === "eth_call" || method === "eth_estimateGas") {
- const result = spelunkData(error);
- const e = AbiCoder.getBuiltinCallException((method === "eth_call") ? "call" : "estimateGas", (payload.params[0]), (result ? result.data : null));
- e.info = { error, payload };
- return e;
- }
- // Only estimateGas and call can return arbitrary contract-defined text, so now we
- // we can process text safely.
- const message = JSON.stringify(spelunkMessage(error));
- if (typeof (error.message) === "string" && error.message.match(/user denied|ethers-user-denied/i)) {
- const actionMap = {
- eth_sign: "signMessage",
- personal_sign: "signMessage",
- eth_signTypedData_v4: "signTypedData",
- eth_signTransaction: "signTransaction",
- eth_sendTransaction: "sendTransaction",
- eth_requestAccounts: "requestAccess",
- wallet_requestAccounts: "requestAccess",
- };
- return makeError(`user rejected action`, "ACTION_REJECTED", {
- action: (actionMap[method] || "unknown"),
- reason: "rejected",
- info: { payload, error }
- });
- }
- if (method === "eth_sendRawTransaction" || method === "eth_sendTransaction") {
- const transaction = (payload.params[0]);
- if (message.match(/insufficient funds|base fee exceeds gas limit/i)) {
- return makeError("insufficient funds for intrinsic transaction cost", "INSUFFICIENT_FUNDS", {
- transaction, info: { error }
- });
- }
- if (message.match(/nonce/i) && message.match(/too low/i)) {
- return makeError("nonce has already been used", "NONCE_EXPIRED", { transaction, info: { error } });
- }
- // "replacement transaction underpriced"
- if (message.match(/replacement transaction/i) && message.match(/underpriced/i)) {
- return makeError("replacement fee too low", "REPLACEMENT_UNDERPRICED", { transaction, info: { error } });
- }
- if (message.match(/only replay-protected/i)) {
- return makeError("legacy pre-eip-155 transactions not supported", "UNSUPPORTED_OPERATION", {
- operation: method, info: { transaction, info: { error } }
- });
- }
- }
- let unsupported = !!message.match(/the method .* does not exist/i);
- if (!unsupported) {
- if (error && error.details && error.details.startsWith("Unauthorized method:")) {
- unsupported = true;
- }
- }
- if (unsupported) {
- return makeError("unsupported operation", "UNSUPPORTED_OPERATION", {
- operation: payload.method, info: { error, payload }
- });
- }
- return makeError("could not coalesce error", "UNKNOWN_ERROR", { error, payload });
- }
- /**
- * Requests the %%method%% with %%params%% via the JSON-RPC protocol
- * over the underlying channel. This can be used to call methods
- * on the backend that do not have a high-level API within the Provider
- * API.
- *
- * This method queues requests according to the batch constraints
- * in the options, assigns the request a unique ID.
- *
- * **Do NOT override** this method in sub-classes; instead
- * override [[_send]] or force the options values in the
- * call to the constructor to modify this method's behavior.
- */
- send(method, params) {
- // @TODO: cache chainId?? purge on switch_networks
- // We have been destroyed; no operations are supported anymore
- if (this.destroyed) {
- return Promise.reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: method }));
- }
- const id = this.#nextId++;
- const promise = new Promise((resolve, reject) => {
- this.#payloads.push({
- resolve, reject,
- payload: { method, params, id, jsonrpc: "2.0" }
- });
- });
- // If there is not a pending drainTimer, set one
- this.#scheduleDrain();
- return promise;
- }
- /**
- * Resolves to the [[Signer]] account for %%address%% managed by
- * the client.
- *
- * If the %%address%% is a number, it is used as an index in the
- * the accounts from [[listAccounts]].
- *
- * This can only be used on clients which manage accounts (such as
- * Geth with imported account or MetaMask).
- *
- * Throws if the account doesn't exist.
- */
- async getSigner(address) {
- if (address == null) {
- address = 0;
- }
- const accountsPromise = this.send("eth_accounts", []);
- // Account index
- if (typeof (address) === "number") {
- const accounts = (await accountsPromise);
- if (address >= accounts.length) {
- throw new Error("no such account");
- }
- return new JsonRpcSigner(this, accounts[address]);
- }
- const { accounts } = await resolveProperties({
- network: this.getNetwork(),
- accounts: accountsPromise
- });
- // Account address
- address = getAddress(address);
- for (const account of accounts) {
- if (getAddress(account) === address) {
- return new JsonRpcSigner(this, address);
- }
- }
- throw new Error("invalid account");
- }
- async listAccounts() {
- const accounts = await this.send("eth_accounts", []);
- return accounts.map((a) => new JsonRpcSigner(this, a));
- }
- destroy() {
- // Stop processing requests
- if (this.#drainTimer) {
- clearTimeout(this.#drainTimer);
- this.#drainTimer = null;
- }
- // Cancel all pending requests
- for (const { payload, reject } of this.#payloads) {
- reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: payload.method }));
- }
- this.#payloads = [];
- // Parent clean-up
- super.destroy();
- }
- }
- // @TODO: remove this in v7, it is not exported because this functionality
- // is exposed in the JsonRpcApiProvider by setting polling to true. It should
- // be safe to remove regardless, because it isn't reachable, but just in case.
- /**
- * @_ignore:
- */
- class JsonRpcApiPollingProvider extends JsonRpcApiProvider {
- #pollingInterval;
- constructor(network, options) {
- super(network, options);
- let pollingInterval = this._getOption("pollingInterval");
- if (pollingInterval == null) {
- pollingInterval = defaultOptions.pollingInterval;
- }
- this.#pollingInterval = pollingInterval;
- }
- _getSubscriber(sub) {
- const subscriber = super._getSubscriber(sub);
- if (isPollable(subscriber)) {
- subscriber.pollingInterval = this.#pollingInterval;
- }
- return subscriber;
- }
- /**
- * The polling interval (default: 4000 ms)
- */
- get pollingInterval() { return this.#pollingInterval; }
- set pollingInterval(value) {
- if (!Number.isInteger(value) || value < 0) {
- throw new Error("invalid interval");
- }
- this.#pollingInterval = value;
- this._forEachSubscriber((sub) => {
- if (isPollable(sub)) {
- sub.pollingInterval = this.#pollingInterval;
- }
- });
- }
- }
- /**
- * The JsonRpcProvider is one of the most common Providers,
- * which performs all operations over HTTP (or HTTPS) requests.
- *
- * Events are processed by polling the backend for the current block
- * number; when it advances, all block-base events are then checked
- * for updates.
- */
- class JsonRpcProvider extends JsonRpcApiPollingProvider {
- #connect;
- constructor(url, network, options) {
- if (url == null) {
- url = "http:/\/localhost:8545";
- }
- super(network, options);
- if (typeof (url) === "string") {
- this.#connect = new FetchRequest(url);
- }
- else {
- this.#connect = url.clone();
- }
- }
- _getConnection() {
- return this.#connect.clone();
- }
- async send(method, params) {
- // All requests are over HTTP, so we can just start handling requests
- // We do this here rather than the constructor so that we don't send any
- // requests to the network (i.e. eth_chainId) until we absolutely have to.
- await this._start();
- return await super.send(method, params);
- }
- async _send(payload) {
- // Configure a POST connection for the requested method
- const request = this._getConnection();
- request.body = JSON.stringify(payload);
- request.setHeader("content-type", "application/json");
- const response = await request.send();
- response.assertOk();
- let resp = response.bodyJson;
- if (!Array.isArray(resp)) {
- resp = [resp];
- }
- return resp;
- }
- }
- function spelunkData(value) {
- if (value == null) {
- return null;
- }
- // These *are* the droids we're looking for.
- if (typeof (value.message) === "string" && value.message.match(/revert/i) && isHexString(value.data)) {
- return { message: value.message, data: value.data };
- }
- // Spelunk further...
- if (typeof (value) === "object") {
- for (const key in value) {
- const result = spelunkData(value[key]);
- if (result) {
- return result;
- }
- }
- return null;
- }
- // Might be a JSON string we can further descend...
- if (typeof (value) === "string") {
- try {
- return spelunkData(JSON.parse(value));
- }
- catch (error) { }
- }
- return null;
- }
- function _spelunkMessage(value, result) {
- if (value == null) {
- return;
- }
- // These *are* the droids we're looking for.
- if (typeof (value.message) === "string") {
- result.push(value.message);
- }
- // Spelunk further...
- if (typeof (value) === "object") {
- for (const key in value) {
- _spelunkMessage(value[key], result);
- }
- }
- // Might be a JSON string we can further descend...
- if (typeof (value) === "string") {
- try {
- return _spelunkMessage(JSON.parse(value), result);
- }
- catch (error) { }
- }
- }
- function spelunkMessage(value) {
- const result = [];
- _spelunkMessage(value, result);
- return result;
- }
- /**
- * [[link-ankr]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Sepolia Testnet (``sepolia``)
- * - Arbitrum (``arbitrum``)
- * - Base (``base``)
- * - Base Goerlia Testnet (``base-goerli``)
- * - Base Sepolia Testnet (``base-sepolia``)
- * - BNB (``bnb``)
- * - BNB Testnet (``bnbt``)
- * - Optimism (``optimism``)
- * - Optimism Goerli Testnet (``optimism-goerli``)
- * - Optimism Sepolia Testnet (``optimism-sepolia``)
- * - Polygon (``matic``)
- * - Polygon Mumbai Testnet (``matic-mumbai``)
- *
- * @_subsection: api/providers/thirdparty:Ankr [providers-ankr]
- */
- const defaultApiKey$1 = "9f7d929b018cdffb338517efa06f58359e86ff1ffd350bc889738523659e7972";
- function getHost$5(name) {
- switch (name) {
- case "mainnet":
- return "rpc.ankr.com/eth";
- case "goerli":
- return "rpc.ankr.com/eth_goerli";
- case "sepolia":
- return "rpc.ankr.com/eth_sepolia";
- case "arbitrum":
- return "rpc.ankr.com/arbitrum";
- case "base":
- return "rpc.ankr.com/base";
- case "base-goerli":
- return "rpc.ankr.com/base_goerli";
- case "base-sepolia":
- return "rpc.ankr.com/base_sepolia";
- case "bnb":
- return "rpc.ankr.com/bsc";
- case "bnbt":
- return "rpc.ankr.com/bsc_testnet_chapel";
- case "matic":
- return "rpc.ankr.com/polygon";
- case "matic-mumbai":
- return "rpc.ankr.com/polygon_mumbai";
- case "optimism":
- return "rpc.ankr.com/optimism";
- case "optimism-goerli":
- return "rpc.ankr.com/optimism_testnet";
- case "optimism-sepolia":
- return "rpc.ankr.com/optimism_sepolia";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /**
- * The **AnkrProvider** connects to the [[link-ankr]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-ankr-signup).
- */
- class AnkrProvider extends JsonRpcProvider {
- /**
- * The API key for the Ankr connection.
- */
- apiKey;
- /**
- * Create a new **AnkrProvider**.
- *
- * By default connecting to ``mainnet`` with a highly throttled
- * API key.
- */
- constructor(_network, apiKey) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (apiKey == null) {
- apiKey = defaultApiKey$1;
- }
- // Ankr does not support filterId, so we force polling
- const options = { polling: true, staticNetwork: network };
- const request = AnkrProvider.getRequest(network, apiKey);
- super(request, network, options);
- defineProperties(this, { apiKey });
- }
- _getProvider(chainId) {
- try {
- return new AnkrProvider(chainId, this.apiKey);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- /**
- * Returns a prepared request for connecting to %%network%% with
- * %%apiKey%%.
- */
- static getRequest(network, apiKey) {
- if (apiKey == null) {
- apiKey = defaultApiKey$1;
- }
- const request = new FetchRequest(`https:/\/${getHost$5(network.name)}/${apiKey}`);
- request.allowGzip = true;
- if (apiKey === defaultApiKey$1) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("AnkrProvider");
- return true;
- };
- }
- return request;
- }
- getRpcError(payload, error) {
- if (payload.method === "eth_sendRawTransaction") {
- if (error && error.error && error.error.message === "INTERNAL_ERROR: could not replace existing tx") {
- error.error.message = "replacement transaction underpriced";
- }
- }
- return super.getRpcError(payload, error);
- }
- isCommunityResource() {
- return (this.apiKey === defaultApiKey$1);
- }
- }
- /**
- * [[link-alchemy]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Sepolia Testnet (``sepolia``)
- * - Arbitrum (``arbitrum``)
- * - Arbitrum Goerli Testnet (``arbitrum-goerli``)
- * - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
- * - Base (``base``)
- * - Base Goerlia Testnet (``base-goerli``)
- * - Base Sepolia Testnet (``base-sepolia``)
- * - Optimism (``optimism``)
- * - Optimism Goerli Testnet (``optimism-goerli``)
- * - Optimism Sepolia Testnet (``optimism-sepolia``)
- * - Polygon (``matic``)
- * - Polygon Amoy Testnet (``matic-amoy``)
- * - Polygon Mumbai Testnet (``matic-mumbai``)
- *
- * @_subsection: api/providers/thirdparty:Alchemy [providers-alchemy]
- */
- const defaultApiKey = "_gg7wSSi0KMBsdKnGVfHDueq6xMB9EkC";
- function getHost$4(name) {
- switch (name) {
- case "mainnet":
- return "eth-mainnet.alchemyapi.io";
- case "goerli":
- return "eth-goerli.g.alchemy.com";
- case "sepolia":
- return "eth-sepolia.g.alchemy.com";
- case "arbitrum":
- return "arb-mainnet.g.alchemy.com";
- case "arbitrum-goerli":
- return "arb-goerli.g.alchemy.com";
- case "arbitrum-sepolia":
- return "arb-sepolia.g.alchemy.com";
- case "base":
- return "base-mainnet.g.alchemy.com";
- case "base-goerli":
- return "base-goerli.g.alchemy.com";
- case "base-sepolia":
- return "base-sepolia.g.alchemy.com";
- case "matic":
- return "polygon-mainnet.g.alchemy.com";
- case "matic-amoy":
- return "polygon-amoy.g.alchemy.com";
- case "matic-mumbai":
- return "polygon-mumbai.g.alchemy.com";
- case "optimism":
- return "opt-mainnet.g.alchemy.com";
- case "optimism-goerli":
- return "opt-goerli.g.alchemy.com";
- case "optimism-sepolia":
- return "opt-sepolia.g.alchemy.com";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /**
- * The **AlchemyProvider** connects to the [[link-alchemy]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-alchemy-signup).
- *
- * @_docloc: api/providers/thirdparty
- */
- class AlchemyProvider extends JsonRpcProvider {
- apiKey;
- constructor(_network, apiKey) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (apiKey == null) {
- apiKey = defaultApiKey;
- }
- const request = AlchemyProvider.getRequest(network, apiKey);
- super(request, network, { staticNetwork: network });
- defineProperties(this, { apiKey });
- }
- _getProvider(chainId) {
- try {
- return new AlchemyProvider(chainId, this.apiKey);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- async _perform(req) {
- // https://docs.alchemy.com/reference/trace-transaction
- if (req.method === "getTransactionResult") {
- const { trace, tx } = await resolveProperties({
- trace: this.send("trace_transaction", [req.hash]),
- tx: this.getTransaction(req.hash)
- });
- if (trace == null || tx == null) {
- return null;
- }
- let data;
- let error = false;
- try {
- data = trace[0].result.output;
- error = (trace[0].error === "Reverted");
- }
- catch (error) { }
- if (data) {
- assert(!error, "an error occurred during transaction executions", "CALL_EXCEPTION", {
- action: "getTransactionResult",
- data,
- reason: null,
- transaction: tx,
- invocation: null,
- revert: null // @TODO
- });
- return data;
- }
- assert(false, "could not parse trace result", "BAD_DATA", { value: trace });
- }
- return await super._perform(req);
- }
- isCommunityResource() {
- return (this.apiKey === defaultApiKey);
- }
- static getRequest(network, apiKey) {
- if (apiKey == null) {
- apiKey = defaultApiKey;
- }
- const request = new FetchRequest(`https:/\/${getHost$4(network.name)}/v2/${apiKey}`);
- request.allowGzip = true;
- if (apiKey === defaultApiKey) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("alchemy");
- return true;
- };
- }
- return request;
- }
- }
- /**
- * [[link-chainstack]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Arbitrum (``arbitrum``)
- * - BNB Smart Chain Mainnet (``bnb``)
- * - Polygon (``matic``)
- *
- * @_subsection: api/providers/thirdparty:Chainstack [providers-chainstack]
- */
- function getApiKey(name) {
- switch (name) {
- case "mainnet": return "39f1d67cedf8b7831010a665328c9197";
- case "arbitrum": return "0550c209db33c3abf4cc927e1e18cea1";
- case "bnb": return "98b5a77e531614387366f6fc5da097f8";
- case "matic": return "cd9d4d70377471aa7c142ec4a4205249";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- function getHost$3(name) {
- switch (name) {
- case "mainnet":
- return "ethereum-mainnet.core.chainstack.com";
- case "arbitrum":
- return "arbitrum-mainnet.core.chainstack.com";
- case "bnb":
- return "bsc-mainnet.core.chainstack.com";
- case "matic":
- return "polygon-mainnet.core.chainstack.com";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /**
- * The **ChainstackProvider** connects to the [[link-chainstack]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-chainstack).
- */
- class ChainstackProvider extends JsonRpcProvider {
- /**
- * The API key for the Chainstack connection.
- */
- apiKey;
- /**
- * Creates a new **ChainstackProvider**.
- */
- constructor(_network, apiKey) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (apiKey == null) {
- apiKey = getApiKey(network.name);
- }
- const request = ChainstackProvider.getRequest(network, apiKey);
- super(request, network, { staticNetwork: network });
- defineProperties(this, { apiKey });
- }
- _getProvider(chainId) {
- try {
- return new ChainstackProvider(chainId, this.apiKey);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- isCommunityResource() {
- return (this.apiKey === getApiKey(this._network.name));
- }
- /**
- * Returns a prepared request for connecting to %%network%%
- * with %%apiKey%% and %%projectSecret%%.
- */
- static getRequest(network, apiKey) {
- if (apiKey == null) {
- apiKey = getApiKey(network.name);
- }
- const request = new FetchRequest(`https:/\/${getHost$3(network.name)}/${apiKey}`);
- request.allowGzip = true;
- if (apiKey === getApiKey(network.name)) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("ChainstackProvider");
- return true;
- };
- }
- return request;
- }
- }
- /**
- * About Cloudflare
- *
- * @_subsection: api/providers/thirdparty:Cloudflare [providers-cloudflare]
- */
- /**
- * About Cloudflare...
- */
- class CloudflareProvider extends JsonRpcProvider {
- constructor(_network) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- assertArgument(network.name === "mainnet", "unsupported network", "network", _network);
- super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
- }
- }
- /**
- * [[link-etherscan]] provides a third-party service for connecting to
- * various blockchains over a combination of JSON-RPC and custom API
- * endpoints.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Sepolia Testnet (``sepolia``)
- * - Holesky Testnet (``holesky``)
- * - Arbitrum (``arbitrum``)
- * - Arbitrum Goerli Testnet (``arbitrum-goerli``)
- * - Base (``base``)
- * - Base Sepolia Testnet (``base-sepolia``)
- * - BNB Smart Chain Mainnet (``bnb``)
- * - BNB Smart Chain Testnet (``bnbt``)
- * - Optimism (``optimism``)
- * - Optimism Goerli Testnet (``optimism-goerli``)
- * - Polygon (``matic``)
- * - Polygon Mumbai Testnet (``matic-mumbai``)
- * - Polygon Amoy Testnet (``matic-amoy``)
- *
- * @_subsection api/providers/thirdparty:Etherscan [providers-etherscan]
- */
- const THROTTLE = 2000;
- function isPromise(value) {
- return (value && typeof (value.then) === "function");
- }
- const EtherscanPluginId = "org.ethers.plugins.provider.Etherscan";
- /**
- * A Network can include an **EtherscanPlugin** to provide
- * a custom base URL.
- *
- * @_docloc: api/providers/thirdparty:Etherscan
- */
- class EtherscanPlugin extends NetworkPlugin {
- /**
- * The Etherscan API base URL.
- */
- baseUrl;
- /**
- * Creates a new **EtherscanProvider** which will use
- * %%baseUrl%%.
- */
- constructor(baseUrl) {
- super(EtherscanPluginId);
- defineProperties(this, { baseUrl });
- }
- clone() {
- return new EtherscanPlugin(this.baseUrl);
- }
- }
- const skipKeys = ["enableCcipRead"];
- let nextId = 1;
- /**
- * The **EtherscanBaseProvider** is the super-class of
- * [[EtherscanProvider]], which should generally be used instead.
- *
- * Since the **EtherscanProvider** includes additional code for
- * [[Contract]] access, in //rare cases// that contracts are not
- * used, this class can reduce code size.
- *
- * @_docloc: api/providers/thirdparty:Etherscan
- */
- class EtherscanProvider extends AbstractProvider {
- /**
- * The connected network.
- */
- network;
- /**
- * The API key or null if using the community provided bandwidth.
- */
- apiKey;
- #plugin;
- /**
- * Creates a new **EtherscanBaseProvider**.
- */
- constructor(_network, _apiKey) {
- const apiKey = (_apiKey != null) ? _apiKey : null;
- super();
- const network = Network.from(_network);
- this.#plugin = network.getPlugin(EtherscanPluginId);
- defineProperties(this, { apiKey, network });
- // Test that the network is supported by Etherscan
- this.getBaseUrl();
- }
- /**
- * Returns the base URL.
- *
- * If an [[EtherscanPlugin]] is configured on the
- * [[EtherscanBaseProvider_network]], returns the plugin's
- * baseUrl.
- */
- getBaseUrl() {
- if (this.#plugin) {
- return this.#plugin.baseUrl;
- }
- switch (this.network.name) {
- case "mainnet":
- return "https:/\/api.etherscan.io";
- case "goerli":
- return "https:/\/api-goerli.etherscan.io";
- case "sepolia":
- return "https:/\/api-sepolia.etherscan.io";
- case "holesky":
- return "https:/\/api-holesky.etherscan.io";
- case "arbitrum":
- return "https:/\/api.arbiscan.io";
- case "arbitrum-goerli":
- return "https:/\/api-goerli.arbiscan.io";
- case "base":
- return "https:/\/api.basescan.org";
- case "base-sepolia":
- return "https:/\/api-sepolia.basescan.org";
- case "bnb":
- return "https:/\/api.bscscan.com";
- case "bnbt":
- return "https:/\/api-testnet.bscscan.com";
- case "matic":
- return "https:/\/api.polygonscan.com";
- case "matic-amoy":
- return "https:/\/api-amoy.polygonscan.com";
- case "matic-mumbai":
- return "https:/\/api-testnet.polygonscan.com";
- case "optimism":
- return "https:/\/api-optimistic.etherscan.io";
- case "optimism-goerli":
- return "https:/\/api-goerli-optimistic.etherscan.io";
- }
- assertArgument(false, "unsupported network", "network", this.network);
- }
- /**
- * Returns the URL for the %%module%% and %%params%%.
- */
- getUrl(module, params) {
- const query = Object.keys(params).reduce((accum, key) => {
- const value = params[key];
- if (value != null) {
- accum += `&${key}=${value}`;
- }
- return accum;
- }, "");
- const apiKey = ((this.apiKey) ? `&apikey=${this.apiKey}` : "");
- return `${this.getBaseUrl()}/api?module=${module}${query}${apiKey}`;
- }
- /**
- * Returns the URL for using POST requests.
- */
- getPostUrl() {
- return `${this.getBaseUrl()}/api`;
- }
- /**
- * Returns the parameters for using POST requests.
- */
- getPostData(module, params) {
- params.module = module;
- params.apikey = this.apiKey;
- return params;
- }
- async detectNetwork() {
- return this.network;
- }
- /**
- * Resolves to the result of calling %%module%% with %%params%%.
- *
- * If %%post%%, the request is made as a POST request.
- */
- async fetch(module, params, post) {
- const id = nextId++;
- const url = (post ? this.getPostUrl() : this.getUrl(module, params));
- const payload = (post ? this.getPostData(module, params) : null);
- this.emit("debug", { action: "sendRequest", id, url, payload: payload });
- const request = new FetchRequest(url);
- request.setThrottleParams({ slotInterval: 1000 });
- request.retryFunc = (req, resp, attempt) => {
- if (this.isCommunityResource()) {
- showThrottleMessage("Etherscan");
- }
- return Promise.resolve(true);
- };
- request.processFunc = async (request, response) => {
- const result = response.hasBody() ? JSON.parse(toUtf8String(response.body)) : {};
- const throttle = ((typeof (result.result) === "string") ? result.result : "").toLowerCase().indexOf("rate limit") >= 0;
- if (module === "proxy") {
- // This JSON response indicates we are being throttled
- if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
- this.emit("debug", { action: "receiveError", id, reason: "proxy-NOTOK", error: result });
- response.throwThrottleError(result.result, THROTTLE);
- }
- }
- else {
- if (throttle) {
- this.emit("debug", { action: "receiveError", id, reason: "null result", error: result.result });
- response.throwThrottleError(result.result, THROTTLE);
- }
- }
- return response;
- };
- if (payload) {
- request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
- request.body = Object.keys(payload).map((k) => `${k}=${payload[k]}`).join("&");
- }
- const response = await request.send();
- try {
- response.assertOk();
- }
- catch (error) {
- this.emit("debug", { action: "receiveError", id, error, reason: "assertOk" });
- assert(false, "response error", "SERVER_ERROR", { request, response });
- }
- if (!response.hasBody()) {
- this.emit("debug", { action: "receiveError", id, error: "missing body", reason: "null body" });
- assert(false, "missing response", "SERVER_ERROR", { request, response });
- }
- const result = JSON.parse(toUtf8String(response.body));
- if (module === "proxy") {
- if (result.jsonrpc != "2.0") {
- this.emit("debug", { action: "receiveError", id, result, reason: "invalid JSON-RPC" });
- assert(false, "invalid JSON-RPC response (missing jsonrpc='2.0')", "SERVER_ERROR", { request, response, info: { result } });
- }
- if (result.error) {
- this.emit("debug", { action: "receiveError", id, result, reason: "JSON-RPC error" });
- assert(false, "error response", "SERVER_ERROR", { request, response, info: { result } });
- }
- this.emit("debug", { action: "receiveRequest", id, result });
- return result.result;
- }
- else {
- // getLogs, getHistory have weird success responses
- if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
- this.emit("debug", { action: "receiveRequest", id, result });
- return result.result;
- }
- if (result.status != 1 || (typeof (result.message) === "string" && !result.message.match(/^OK/))) {
- this.emit("debug", { action: "receiveError", id, result });
- assert(false, "error response", "SERVER_ERROR", { request, response, info: { result } });
- }
- this.emit("debug", { action: "receiveRequest", id, result });
- return result.result;
- }
- }
- /**
- * Returns %%transaction%% normalized for the Etherscan API.
- */
- _getTransactionPostData(transaction) {
- const result = {};
- for (let key in transaction) {
- if (skipKeys.indexOf(key) >= 0) {
- continue;
- }
- if (transaction[key] == null) {
- continue;
- }
- let value = transaction[key];
- if (key === "type" && value === 0) {
- continue;
- }
- if (key === "blockTag" && value === "latest") {
- continue;
- }
- // Quantity-types require no leading zero, unless 0
- if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
- value = toQuantity(value);
- }
- else if (key === "accessList") {
- value = "[" + accessListify(value).map((set) => {
- return `{address:"${set.address}",storageKeys:["${set.storageKeys.join('","')}"]}`;
- }).join(",") + "]";
- }
- else if (key === "blobVersionedHashes") {
- if (value.length === 0) {
- continue;
- }
- // @TODO: update this once the API supports blobs
- assert(false, "Etherscan API does not support blobVersionedHashes", "UNSUPPORTED_OPERATION", {
- operation: "_getTransactionPostData",
- info: { transaction }
- });
- }
- else {
- value = hexlify(value);
- }
- result[key] = value;
- }
- return result;
- }
- /**
- * Throws the normalized Etherscan error.
- */
- _checkError(req, error, transaction) {
- // Pull any message out if, possible
- let message = "";
- if (isError(error, "SERVER_ERROR")) {
- // Check for an error emitted by a proxy call
- try {
- message = error.info.result.error.message;
- }
- catch (e) { }
- if (!message) {
- try {
- message = error.info.message;
- }
- catch (e) { }
- }
- }
- if (req.method === "estimateGas") {
- if (!message.match(/revert/i) && message.match(/insufficient funds/i)) {
- assert(false, "insufficient funds", "INSUFFICIENT_FUNDS", {
- transaction: req.transaction
- });
- }
- }
- if (req.method === "call" || req.method === "estimateGas") {
- if (message.match(/execution reverted/i)) {
- let data = "";
- try {
- data = error.info.result.error.data;
- }
- catch (error) { }
- const e = AbiCoder.getBuiltinCallException(req.method, req.transaction, data);
- e.info = { request: req, error };
- throw e;
- }
- }
- if (message) {
- if (req.method === "broadcastTransaction") {
- const transaction = Transaction.from(req.signedTransaction);
- if (message.match(/replacement/i) && message.match(/underpriced/i)) {
- assert(false, "replacement fee too low", "REPLACEMENT_UNDERPRICED", {
- transaction
- });
- }
- if (message.match(/insufficient funds/)) {
- assert(false, "insufficient funds for intrinsic transaction cost", "INSUFFICIENT_FUNDS", {
- transaction
- });
- }
- if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
- assert(false, "nonce has already been used", "NONCE_EXPIRED", {
- transaction
- });
- }
- }
- }
- // Something we could not process
- throw error;
- }
- async _detectNetwork() {
- return this.network;
- }
- async _perform(req) {
- switch (req.method) {
- case "chainId":
- return this.network.chainId;
- case "getBlockNumber":
- return this.fetch("proxy", { action: "eth_blockNumber" });
- case "getGasPrice":
- return this.fetch("proxy", { action: "eth_gasPrice" });
- case "getPriorityFee":
- // This is temporary until Etherscan completes support
- if (this.network.name === "mainnet") {
- return "1000000000";
- }
- else if (this.network.name === "optimism") {
- return "1000000";
- }
- else {
- throw new Error("fallback onto the AbstractProvider default");
- }
- /* Working with Etherscan to get this added:
- try {
- const test = await this.fetch("proxy", {
- action: "eth_maxPriorityFeePerGas"
- });
- console.log(test);
- return test;
- } catch (e) {
- console.log("DEBUG", e);
- throw e;
- }
- */
- /* This might be safe; but due to rounding neither myself
- or Etherscan are necessarily comfortable with this. :)
- try {
- const result = await this.fetch("gastracker", { action: "gasoracle" });
- console.log(result);
- const gasPrice = parseUnits(result.SafeGasPrice, "gwei");
- const baseFee = parseUnits(result.suggestBaseFee, "gwei");
- const priorityFee = gasPrice - baseFee;
- if (priorityFee < 0) { throw new Error("negative priority fee; defer to abstract provider default"); }
- return priorityFee;
- } catch (error) {
- console.log("DEBUG", error);
- throw error;
- }
- */
- case "getBalance":
- // Returns base-10 result
- return this.fetch("account", {
- action: "balance",
- address: req.address,
- tag: req.blockTag
- });
- case "getTransactionCount":
- return this.fetch("proxy", {
- action: "eth_getTransactionCount",
- address: req.address,
- tag: req.blockTag
- });
- case "getCode":
- return this.fetch("proxy", {
- action: "eth_getCode",
- address: req.address,
- tag: req.blockTag
- });
- case "getStorage":
- return this.fetch("proxy", {
- action: "eth_getStorageAt",
- address: req.address,
- position: req.position,
- tag: req.blockTag
- });
- case "broadcastTransaction":
- return this.fetch("proxy", {
- action: "eth_sendRawTransaction",
- hex: req.signedTransaction
- }, true).catch((error) => {
- return this._checkError(req, error, req.signedTransaction);
- });
- case "getBlock":
- if ("blockTag" in req) {
- return this.fetch("proxy", {
- action: "eth_getBlockByNumber",
- tag: req.blockTag,
- boolean: (req.includeTransactions ? "true" : "false")
- });
- }
- assert(false, "getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
- operation: "getBlock(blockHash)"
- });
- case "getTransaction":
- return this.fetch("proxy", {
- action: "eth_getTransactionByHash",
- txhash: req.hash
- });
- case "getTransactionReceipt":
- return this.fetch("proxy", {
- action: "eth_getTransactionReceipt",
- txhash: req.hash
- });
- case "call": {
- if (req.blockTag !== "latest") {
- throw new Error("EtherscanProvider does not support blockTag for call");
- }
- const postData = this._getTransactionPostData(req.transaction);
- postData.module = "proxy";
- postData.action = "eth_call";
- try {
- return await this.fetch("proxy", postData, true);
- }
- catch (error) {
- return this._checkError(req, error, req.transaction);
- }
- }
- case "estimateGas": {
- const postData = this._getTransactionPostData(req.transaction);
- postData.module = "proxy";
- postData.action = "eth_estimateGas";
- try {
- return await this.fetch("proxy", postData, true);
- }
- catch (error) {
- return this._checkError(req, error, req.transaction);
- }
- }
- }
- return super._perform(req);
- }
- async getNetwork() {
- return this.network;
- }
- /**
- * Resolves to the current price of ether.
- *
- * This returns ``0`` on any network other than ``mainnet``.
- */
- async getEtherPrice() {
- if (this.network.name !== "mainnet") {
- return 0.0;
- }
- return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
- }
- /**
- * Resolves to a [Contract]] for %%address%%, using the
- * Etherscan API to retreive the Contract ABI.
- */
- async getContract(_address) {
- let address = this._getAddress(_address);
- if (isPromise(address)) {
- address = await address;
- }
- try {
- const resp = await this.fetch("contract", {
- action: "getabi", address
- });
- const abi = JSON.parse(resp);
- return new Contract(address, abi, this);
- }
- catch (error) {
- return null;
- }
- }
- isCommunityResource() {
- return (this.apiKey == null);
- }
- }
- function getGlobal() {
- if (typeof self !== 'undefined') {
- return self;
- }
- if (typeof window !== 'undefined') {
- return window;
- }
- if (typeof global !== 'undefined') {
- return global;
- }
- throw new Error('unable to locate global object');
- }
- const _WebSocket = getGlobal().WebSocket;
- /**
- * Generic long-lived socket provider.
- *
- * Sub-classing notes
- * - a sub-class MUST call the `_start()` method once connected
- * - a sub-class MUST override the `_write(string)` method
- * - a sub-class MUST call `_processMessage(string)` for each message
- *
- * @_subsection: api/providers/abstract-provider:Socket Providers [about-socketProvider]
- */
- /**
- * A **SocketSubscriber** uses a socket transport to handle events and
- * should use [[_emit]] to manage the events.
- */
- class SocketSubscriber {
- #provider;
- #filter;
- /**
- * The filter.
- */
- get filter() { return JSON.parse(this.#filter); }
- #filterId;
- #paused;
- #emitPromise;
- /**
- * Creates a new **SocketSubscriber** attached to %%provider%% listening
- * to %%filter%%.
- */
- constructor(provider, filter) {
- this.#provider = provider;
- this.#filter = JSON.stringify(filter);
- this.#filterId = null;
- this.#paused = null;
- this.#emitPromise = null;
- }
- start() {
- this.#filterId = this.#provider.send("eth_subscribe", this.filter).then((filterId) => {
- this.#provider._register(filterId, this);
- return filterId;
- });
- }
- stop() {
- (this.#filterId).then((filterId) => {
- if (this.#provider.destroyed) {
- return;
- }
- this.#provider.send("eth_unsubscribe", [filterId]);
- });
- this.#filterId = null;
- }
- // @TODO: pause should trap the current blockNumber, unsub, and on resume use getLogs
- // and resume
- pause(dropWhilePaused) {
- assert(dropWhilePaused, "preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", { operation: "pause(false)" });
- this.#paused = !!dropWhilePaused;
- }
- resume() {
- this.#paused = null;
- }
- /**
- * @_ignore:
- */
- _handleMessage(message) {
- if (this.#filterId == null) {
- return;
- }
- if (this.#paused === null) {
- let emitPromise = this.#emitPromise;
- if (emitPromise == null) {
- emitPromise = this._emit(this.#provider, message);
- }
- else {
- emitPromise = emitPromise.then(async () => {
- await this._emit(this.#provider, message);
- });
- }
- this.#emitPromise = emitPromise.then(() => {
- if (this.#emitPromise === emitPromise) {
- this.#emitPromise = null;
- }
- });
- }
- }
- /**
- * Sub-classes **must** override this to emit the events on the
- * provider.
- */
- async _emit(provider, message) {
- throw new Error("sub-classes must implemente this; _emit");
- }
- }
- /**
- * A **SocketBlockSubscriber** listens for ``newHeads`` events and emits
- * ``"block"`` events.
- */
- class SocketBlockSubscriber extends SocketSubscriber {
- /**
- * @_ignore:
- */
- constructor(provider) {
- super(provider, ["newHeads"]);
- }
- async _emit(provider, message) {
- provider.emit("block", parseInt(message.number));
- }
- }
- /**
- * A **SocketPendingSubscriber** listens for pending transacitons and emits
- * ``"pending"`` events.
- */
- class SocketPendingSubscriber extends SocketSubscriber {
- /**
- * @_ignore:
- */
- constructor(provider) {
- super(provider, ["newPendingTransactions"]);
- }
- async _emit(provider, message) {
- provider.emit("pending", message);
- }
- }
- /**
- * A **SocketEventSubscriber** listens for event logs.
- */
- class SocketEventSubscriber extends SocketSubscriber {
- #logFilter;
- /**
- * The filter.
- */
- get logFilter() { return JSON.parse(this.#logFilter); }
- /**
- * @_ignore:
- */
- constructor(provider, filter) {
- super(provider, ["logs", filter]);
- this.#logFilter = JSON.stringify(filter);
- }
- async _emit(provider, message) {
- provider.emit(this.logFilter, provider._wrapLog(message, provider._network));
- }
- }
- /**
- * A **SocketProvider** is backed by a long-lived connection over a
- * socket, which can subscribe and receive real-time messages over
- * its communication channel.
- */
- class SocketProvider extends JsonRpcApiProvider {
- #callbacks;
- // Maps each filterId to its subscriber
- #subs;
- // If any events come in before a subscriber has finished
- // registering, queue them
- #pending;
- /**
- * Creates a new **SocketProvider** connected to %%network%%.
- *
- * If unspecified, the network will be discovered.
- */
- constructor(network, _options) {
- // Copy the options
- const options = Object.assign({}, (_options != null) ? _options : {});
- // Support for batches is generally not supported for
- // connection-base providers; if this changes in the future
- // the _send should be updated to reflect this
- assertArgument(options.batchMaxCount == null || options.batchMaxCount === 1, "sockets-based providers do not support batches", "options.batchMaxCount", _options);
- options.batchMaxCount = 1;
- // Socket-based Providers (generally) cannot change their network,
- // since they have a long-lived connection; but let people override
- // this if they have just cause.
- if (options.staticNetwork == null) {
- options.staticNetwork = true;
- }
- super(network, options);
- this.#callbacks = new Map();
- this.#subs = new Map();
- this.#pending = new Map();
- }
- // This value is only valid after _start has been called
- /*
- get _network(): Network {
- if (this.#network == null) {
- throw new Error("this shouldn't happen");
- }
- return this.#network.clone();
- }
- */
- _getSubscriber(sub) {
- switch (sub.type) {
- case "close":
- return new UnmanagedSubscriber("close");
- case "block":
- return new SocketBlockSubscriber(this);
- case "pending":
- return new SocketPendingSubscriber(this);
- case "event":
- return new SocketEventSubscriber(this, sub.filter);
- case "orphan":
- // Handled auto-matically within AbstractProvider
- // when the log.removed = true
- if (sub.filter.orphan === "drop-log") {
- return new UnmanagedSubscriber("drop-log");
- }
- }
- return super._getSubscriber(sub);
- }
- /**
- * Register a new subscriber. This is used internalled by Subscribers
- * and generally is unecessary unless extending capabilities.
- */
- _register(filterId, subscriber) {
- this.#subs.set(filterId, subscriber);
- const pending = this.#pending.get(filterId);
- if (pending) {
- for (const message of pending) {
- subscriber._handleMessage(message);
- }
- this.#pending.delete(filterId);
- }
- }
- async _send(payload) {
- // WebSocket provider doesn't accept batches
- assertArgument(!Array.isArray(payload), "WebSocket does not support batch send", "payload", payload);
- // @TODO: stringify payloads here and store to prevent mutations
- // Prepare a promise to respond to
- const promise = new Promise((resolve, reject) => {
- this.#callbacks.set(payload.id, { payload, resolve, reject });
- });
- // Wait until the socket is connected before writing to it
- await this._waitUntilReady();
- // Write the request to the socket
- await this._write(JSON.stringify(payload));
- return [await promise];
- }
- // Sub-classes must call this once they are connected
- /*
- async _start(): Promise<void> {
- if (this.#ready) { return; }
- for (const { payload } of this.#callbacks.values()) {
- await this._write(JSON.stringify(payload));
- }
- this.#ready = (async function() {
- await super._start();
- })();
- }
- */
- /**
- * Sub-classes **must** call this with messages received over their
- * transport to be processed and dispatched.
- */
- async _processMessage(message) {
- const result = (JSON.parse(message));
- if (result && typeof (result) === "object" && "id" in result) {
- const callback = this.#callbacks.get(result.id);
- if (callback == null) {
- this.emit("error", makeError("received result for unknown id", "UNKNOWN_ERROR", {
- reasonCode: "UNKNOWN_ID",
- result
- }));
- return;
- }
- this.#callbacks.delete(result.id);
- callback.resolve(result);
- }
- else if (result && result.method === "eth_subscription") {
- const filterId = result.params.subscription;
- const subscriber = this.#subs.get(filterId);
- if (subscriber) {
- subscriber._handleMessage(result.params.result);
- }
- else {
- let pending = this.#pending.get(filterId);
- if (pending == null) {
- pending = [];
- this.#pending.set(filterId, pending);
- }
- pending.push(result.params.result);
- }
- }
- else {
- this.emit("error", makeError("received unexpected message", "UNKNOWN_ERROR", {
- reasonCode: "UNEXPECTED_MESSAGE",
- result
- }));
- return;
- }
- }
- /**
- * Sub-classes **must** override this to send %%message%% over their
- * transport.
- */
- async _write(message) {
- throw new Error("sub-classes must override this");
- }
- }
- /**
- * A JSON-RPC provider which is backed by a WebSocket.
- *
- * WebSockets are often preferred because they retain a live connection
- * to a server, which permits more instant access to events.
- *
- * However, this incurs higher server infrasturture costs, so additional
- * resources may be required to host your own WebSocket nodes and many
- * third-party services charge additional fees for WebSocket endpoints.
- */
- class WebSocketProvider extends SocketProvider {
- #connect;
- #websocket;
- get websocket() {
- if (this.#websocket == null) {
- throw new Error("websocket closed");
- }
- return this.#websocket;
- }
- constructor(url, network, options) {
- super(network, options);
- if (typeof (url) === "string") {
- this.#connect = () => { return new _WebSocket(url); };
- this.#websocket = this.#connect();
- }
- else if (typeof (url) === "function") {
- this.#connect = url;
- this.#websocket = url();
- }
- else {
- this.#connect = null;
- this.#websocket = url;
- }
- this.websocket.onopen = async () => {
- try {
- await this._start();
- this.resume();
- }
- catch (error) {
- console.log("failed to start WebsocketProvider", error);
- // @TODO: now what? Attempt reconnect?
- }
- };
- this.websocket.onmessage = (message) => {
- this._processMessage(message.data);
- };
- /*
- this.websocket.onclose = (event) => {
- // @TODO: What event.code should we reconnect on?
- const reconnect = false;
- if (reconnect) {
- this.pause(true);
- if (this.#connect) {
- this.#websocket = this.#connect();
- this.#websocket.onopen = ...
- // @TODO: this requires the super class to rebroadcast; move it there
- }
- this._reconnect();
- }
- };
- */
- }
- async _write(message) {
- this.websocket.send(message);
- }
- async destroy() {
- if (this.#websocket != null) {
- this.#websocket.close();
- this.#websocket = null;
- }
- super.destroy();
- }
- }
- /**
- * [[link-infura]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Sepolia Testnet (``sepolia``)
- * - Arbitrum (``arbitrum``)
- * - Arbitrum Goerli Testnet (``arbitrum-goerli``)
- * - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
- * - Base (``base``)
- * - Base Goerlia Testnet (``base-goerli``)
- * - Base Sepolia Testnet (``base-sepolia``)
- * - BNB Smart Chain Mainnet (``bnb``)
- * - BNB Smart Chain Testnet (``bnbt``)
- * - Linea (``linea``)
- * - Linea Goerli Testnet (``linea-goerli``)
- * - Linea Sepolia Testnet (``linea-sepolia``)
- * - Optimism (``optimism``)
- * - Optimism Goerli Testnet (``optimism-goerli``)
- * - Optimism Sepolia Testnet (``optimism-sepolia``)
- * - Polygon (``matic``)
- * - Polygon Amoy Testnet (``matic-amoy``)
- * - Polygon Mumbai Testnet (``matic-mumbai``)
- *
- * @_subsection: api/providers/thirdparty:INFURA [providers-infura]
- */
- const defaultProjectId = "84842078b09946638c03157f83405213";
- function getHost$2(name) {
- switch (name) {
- case "mainnet":
- return "mainnet.infura.io";
- case "goerli":
- return "goerli.infura.io";
- case "sepolia":
- return "sepolia.infura.io";
- case "arbitrum":
- return "arbitrum-mainnet.infura.io";
- case "arbitrum-goerli":
- return "arbitrum-goerli.infura.io";
- case "arbitrum-sepolia":
- return "arbitrum-sepolia.infura.io";
- case "base":
- return "base-mainnet.infura.io";
- case "base-goerlia":
- return "base-goerli.infura.io";
- case "base-sepolia":
- return "base-sepolia.infura.io";
- case "bnb":
- return "bnbsmartchain-mainnet.infura.io";
- case "bnbt":
- return "bnbsmartchain-testnet.infura.io";
- case "linea":
- return "linea-mainnet.infura.io";
- case "linea-goerli":
- return "linea-goerli.infura.io";
- case "linea-sepolia":
- return "linea-sepolia.infura.io";
- case "matic":
- return "polygon-mainnet.infura.io";
- case "matic-amoy":
- return "polygon-amoy.infura.io";
- case "matic-mumbai":
- return "polygon-mumbai.infura.io";
- case "optimism":
- return "optimism-mainnet.infura.io";
- case "optimism-goerli":
- return "optimism-goerli.infura.io";
- case "optimism-sepolia":
- return "optimism-sepolia.infura.io";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /**
- * The **InfuraWebSocketProvider** connects to the [[link-infura]]
- * WebSocket end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-infura-signup).
- */
- class InfuraWebSocketProvider extends WebSocketProvider {
- /**
- * The Project ID for the INFURA connection.
- */
- projectId;
- /**
- * The Project Secret.
- *
- * If null, no authenticated requests are made. This should not
- * be used outside of private contexts.
- */
- projectSecret;
- /**
- * Creates a new **InfuraWebSocketProvider**.
- */
- constructor(network, projectId) {
- const provider = new InfuraProvider(network, projectId);
- const req = provider._getConnection();
- assert(!req.credentials, "INFURA WebSocket project secrets unsupported", "UNSUPPORTED_OPERATION", { operation: "InfuraProvider.getWebSocketProvider()" });
- const url = req.url.replace(/^http/i, "ws").replace("/v3/", "/ws/v3/");
- super(url, provider._network);
- defineProperties(this, {
- projectId: provider.projectId,
- projectSecret: provider.projectSecret
- });
- }
- isCommunityResource() {
- return (this.projectId === defaultProjectId);
- }
- }
- /**
- * The **InfuraProvider** connects to the [[link-infura]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-infura-signup).
- */
- class InfuraProvider extends JsonRpcProvider {
- /**
- * The Project ID for the INFURA connection.
- */
- projectId;
- /**
- * The Project Secret.
- *
- * If null, no authenticated requests are made. This should not
- * be used outside of private contexts.
- */
- projectSecret;
- /**
- * Creates a new **InfuraProvider**.
- */
- constructor(_network, projectId, projectSecret) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (projectId == null) {
- projectId = defaultProjectId;
- }
- if (projectSecret == null) {
- projectSecret = null;
- }
- const request = InfuraProvider.getRequest(network, projectId, projectSecret);
- super(request, network, { staticNetwork: network });
- defineProperties(this, { projectId, projectSecret });
- }
- _getProvider(chainId) {
- try {
- return new InfuraProvider(chainId, this.projectId, this.projectSecret);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- isCommunityResource() {
- return (this.projectId === defaultProjectId);
- }
- /**
- * Creates a new **InfuraWebSocketProvider**.
- */
- static getWebSocketProvider(network, projectId) {
- return new InfuraWebSocketProvider(network, projectId);
- }
- /**
- * Returns a prepared request for connecting to %%network%%
- * with %%projectId%% and %%projectSecret%%.
- */
- static getRequest(network, projectId, projectSecret) {
- if (projectId == null) {
- projectId = defaultProjectId;
- }
- if (projectSecret == null) {
- projectSecret = null;
- }
- const request = new FetchRequest(`https:/\/${getHost$2(network.name)}/v3/${projectId}`);
- request.allowGzip = true;
- if (projectSecret) {
- request.setCredentials("", projectSecret);
- }
- if (projectId === defaultProjectId) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("InfuraProvider");
- return true;
- };
- }
- return request;
- }
- }
- /**
- * [[link-quicknode]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Sepolia Testnet (``sepolia``)
- * - Holesky Testnet (``holesky``)
- * - Arbitrum (``arbitrum``)
- * - Arbitrum Goerli Testnet (``arbitrum-goerli``)
- * - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
- * - Base Mainnet (``base``);
- * - Base Goerli Testnet (``base-goerli``);
- * - Base Sepolia Testnet (``base-sepolia``);
- * - BNB Smart Chain Mainnet (``bnb``)
- * - BNB Smart Chain Testnet (``bnbt``)
- * - Optimism (``optimism``)
- * - Optimism Goerli Testnet (``optimism-goerli``)
- * - Optimism Sepolia Testnet (``optimism-sepolia``)
- * - Polygon (``matic``)
- * - Polygon Mumbai Testnet (``matic-mumbai``)
- *
- * @_subsection: api/providers/thirdparty:QuickNode [providers-quicknode]
- */
- const defaultToken = "919b412a057b5e9c9b6dce193c5a60242d6efadb";
- function getHost$1(name) {
- switch (name) {
- case "mainnet":
- return "ethers.quiknode.pro";
- case "goerli":
- return "ethers.ethereum-goerli.quiknode.pro";
- case "sepolia":
- return "ethers.ethereum-sepolia.quiknode.pro";
- case "holesky":
- return "ethers.ethereum-holesky.quiknode.pro";
- case "arbitrum":
- return "ethers.arbitrum-mainnet.quiknode.pro";
- case "arbitrum-goerli":
- return "ethers.arbitrum-goerli.quiknode.pro";
- case "arbitrum-sepolia":
- return "ethers.arbitrum-sepolia.quiknode.pro";
- case "base":
- return "ethers.base-mainnet.quiknode.pro";
- case "base-goerli":
- return "ethers.base-goerli.quiknode.pro";
- case "base-spolia":
- return "ethers.base-sepolia.quiknode.pro";
- case "bnb":
- return "ethers.bsc.quiknode.pro";
- case "bnbt":
- return "ethers.bsc-testnet.quiknode.pro";
- case "matic":
- return "ethers.matic.quiknode.pro";
- case "matic-mumbai":
- return "ethers.matic-testnet.quiknode.pro";
- case "optimism":
- return "ethers.optimism.quiknode.pro";
- case "optimism-goerli":
- return "ethers.optimism-goerli.quiknode.pro";
- case "optimism-sepolia":
- return "ethers.optimism-sepolia.quiknode.pro";
- case "xdai":
- return "ethers.xdai.quiknode.pro";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /*
- @TODO:
- These networks are not currently present in the Network
- default included networks. Research them and ensure they
- are EVM compatible and work with ethers
- http://ethers.matic-amoy.quiknode.pro
- http://ethers.avalanche-mainnet.quiknode.pro
- http://ethers.avalanche-testnet.quiknode.pro
- http://ethers.blast-sepolia.quiknode.pro
- http://ethers.celo-mainnet.quiknode.pro
- http://ethers.fantom.quiknode.pro
- http://ethers.imx-demo.quiknode.pro
- http://ethers.imx-mainnet.quiknode.pro
- http://ethers.imx-testnet.quiknode.pro
- http://ethers.near-mainnet.quiknode.pro
- http://ethers.near-testnet.quiknode.pro
- http://ethers.nova-mainnet.quiknode.pro
- http://ethers.scroll-mainnet.quiknode.pro
- http://ethers.scroll-testnet.quiknode.pro
- http://ethers.tron-mainnet.quiknode.pro
- http://ethers.zkevm-mainnet.quiknode.pro
- http://ethers.zkevm-testnet.quiknode.pro
- http://ethers.zksync-mainnet.quiknode.pro
- http://ethers.zksync-testnet.quiknode.pro
- */
- /**
- * The **QuickNodeProvider** connects to the [[link-quicknode]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API token is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-quicknode).
- */
- class QuickNodeProvider extends JsonRpcProvider {
- /**
- * The API token.
- */
- token;
- /**
- * Creates a new **QuickNodeProvider**.
- */
- constructor(_network, token) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (token == null) {
- token = defaultToken;
- }
- const request = QuickNodeProvider.getRequest(network, token);
- super(request, network, { staticNetwork: network });
- defineProperties(this, { token });
- }
- _getProvider(chainId) {
- try {
- return new QuickNodeProvider(chainId, this.token);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- isCommunityResource() {
- return (this.token === defaultToken);
- }
- /**
- * Returns a new request prepared for %%network%% and the
- * %%token%%.
- */
- static getRequest(network, token) {
- if (token == null) {
- token = defaultToken;
- }
- const request = new FetchRequest(`https:/\/${getHost$1(network.name)}/${token}`);
- request.allowGzip = true;
- //if (projectSecret) { request.setCredentials("", projectSecret); }
- if (token === defaultToken) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("QuickNodeProvider");
- return true;
- };
- }
- return request;
- }
- }
- /**
- * A **FallbackProvider** provides resilience, security and performance
- * in a way that is customizable and configurable.
- *
- * @_section: api/providers/fallback-provider:Fallback Provider [about-fallback-provider]
- */
- const BN_1 = BigInt("1");
- const BN_2 = BigInt("2");
- function shuffle(array) {
- for (let i = array.length - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- const tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- }
- function stall$2(duration) {
- return new Promise((resolve) => { setTimeout(resolve, duration); });
- }
- function getTime() { return (new Date()).getTime(); }
- function stringify(value) {
- return JSON.stringify(value, (key, value) => {
- if (typeof (value) === "bigint") {
- return { type: "bigint", value: value.toString() };
- }
- return value;
- });
- }
- const defaultConfig = { stallTimeout: 400, priority: 1, weight: 1 };
- const defaultState = {
- blockNumber: -2, requests: 0, lateResponses: 0, errorResponses: 0,
- outOfSync: -1, unsupportedEvents: 0, rollingDuration: 0, score: 0,
- _network: null, _updateNumber: null, _totalTime: 0,
- _lastFatalError: null, _lastFatalErrorTimestamp: 0
- };
- async function waitForSync(config, blockNumber) {
- while (config.blockNumber < 0 || config.blockNumber < blockNumber) {
- if (!config._updateNumber) {
- config._updateNumber = (async () => {
- try {
- const blockNumber = await config.provider.getBlockNumber();
- if (blockNumber > config.blockNumber) {
- config.blockNumber = blockNumber;
- }
- }
- catch (error) {
- config.blockNumber = -2;
- config._lastFatalError = error;
- config._lastFatalErrorTimestamp = getTime();
- }
- config._updateNumber = null;
- })();
- }
- await config._updateNumber;
- config.outOfSync++;
- if (config._lastFatalError) {
- break;
- }
- }
- }
- function _normalize(value) {
- if (value == null) {
- return "null";
- }
- if (Array.isArray(value)) {
- return "[" + (value.map(_normalize)).join(",") + "]";
- }
- if (typeof (value) === "object" && typeof (value.toJSON) === "function") {
- return _normalize(value.toJSON());
- }
- switch (typeof (value)) {
- case "boolean":
- case "symbol":
- return value.toString();
- case "bigint":
- case "number":
- return BigInt(value).toString();
- case "string":
- return JSON.stringify(value);
- case "object": {
- const keys = Object.keys(value);
- keys.sort();
- return "{" + keys.map((k) => `${JSON.stringify(k)}:${_normalize(value[k])}`).join(",") + "}";
- }
- }
- console.log("Could not serialize", value);
- throw new Error("Hmm...");
- }
- function normalizeResult(value) {
- if ("error" in value) {
- const error = value.error;
- return { tag: _normalize(error), value: error };
- }
- const result = value.result;
- return { tag: _normalize(result), value: result };
- }
- // This strategy picks the highest weight result, as long as the weight is
- // equal to or greater than quorum
- function checkQuorum(quorum, results) {
- const tally = new Map();
- for (const { value, tag, weight } of results) {
- const t = tally.get(tag) || { value, weight: 0 };
- t.weight += weight;
- tally.set(tag, t);
- }
- let best = null;
- for (const r of tally.values()) {
- if (r.weight >= quorum && (!best || r.weight > best.weight)) {
- best = r;
- }
- }
- if (best) {
- return best.value;
- }
- return undefined;
- }
- function getMedian(quorum, results) {
- let resultWeight = 0;
- const errorMap = new Map();
- let bestError = null;
- const values = [];
- for (const { value, tag, weight } of results) {
- if (value instanceof Error) {
- const e = errorMap.get(tag) || { value, weight: 0 };
- e.weight += weight;
- errorMap.set(tag, e);
- if (bestError == null || e.weight > bestError.weight) {
- bestError = e;
- }
- }
- else {
- values.push(BigInt(value));
- resultWeight += weight;
- }
- }
- if (resultWeight < quorum) {
- // We have quorum for an error
- if (bestError && bestError.weight >= quorum) {
- return bestError.value;
- }
- // We do not have quorum for a result
- return undefined;
- }
- // Get the sorted values
- values.sort((a, b) => ((a < b) ? -1 : (b > a) ? 1 : 0));
- const mid = Math.floor(values.length / 2);
- // Odd-length; take the middle value
- if (values.length % 2) {
- return values[mid];
- }
- // Even length; take the ceiling of the mean of the center two values
- return (values[mid - 1] + values[mid] + BN_1) / BN_2;
- }
- function getAnyResult(quorum, results) {
- // If any value or error meets quorum, that is our preferred result
- const result = checkQuorum(quorum, results);
- if (result !== undefined) {
- return result;
- }
- // Otherwise, do we have any result?
- for (const r of results) {
- if (r.value) {
- return r.value;
- }
- }
- // Nope!
- return undefined;
- }
- function getFuzzyMode(quorum, results) {
- if (quorum === 1) {
- return getNumber(getMedian(quorum, results), "%internal");
- }
- const tally = new Map();
- const add = (result, weight) => {
- const t = tally.get(result) || { result, weight: 0 };
- t.weight += weight;
- tally.set(result, t);
- };
- for (const { weight, value } of results) {
- const r = getNumber(value);
- add(r - 1, weight);
- add(r, weight);
- add(r + 1, weight);
- }
- let bestWeight = 0;
- let bestResult = undefined;
- for (const { weight, result } of tally.values()) {
- // Use this result, if this result meets quorum and has either:
- // - a better weight
- // - or equal weight, but the result is larger
- if (weight >= quorum && (weight > bestWeight || (bestResult != null && weight === bestWeight && result > bestResult))) {
- bestWeight = weight;
- bestResult = result;
- }
- }
- return bestResult;
- }
- /**
- * A **FallbackProvider** manages several [[Providers]] providing
- * resilience by switching between slow or misbehaving nodes, security
- * by requiring multiple backends to aggree and performance by allowing
- * faster backends to respond earlier.
- *
- */
- class FallbackProvider extends AbstractProvider {
- /**
- * The number of backends that must agree on a value before it is
- * accpeted.
- */
- quorum;
- /**
- * @_ignore:
- */
- eventQuorum;
- /**
- * @_ignore:
- */
- eventWorkers;
- #configs;
- #height;
- #initialSyncPromise;
- /**
- * Creates a new **FallbackProvider** with %%providers%% connected to
- * %%network%%.
- *
- * If a [[Provider]] is included in %%providers%%, defaults are used
- * for the configuration.
- */
- constructor(providers, network, options) {
- super(network, options);
- this.#configs = providers.map((p) => {
- if (p instanceof AbstractProvider) {
- return Object.assign({ provider: p }, defaultConfig, defaultState);
- }
- else {
- return Object.assign({}, defaultConfig, p, defaultState);
- }
- });
- this.#height = -2;
- this.#initialSyncPromise = null;
- if (options && options.quorum != null) {
- this.quorum = options.quorum;
- }
- else {
- this.quorum = Math.ceil(this.#configs.reduce((accum, config) => {
- accum += config.weight;
- return accum;
- }, 0) / 2);
- }
- this.eventQuorum = 1;
- this.eventWorkers = 1;
- assertArgument(this.quorum <= this.#configs.reduce((a, c) => (a + c.weight), 0), "quorum exceed provider weight", "quorum", this.quorum);
- }
- get providerConfigs() {
- return this.#configs.map((c) => {
- const result = Object.assign({}, c);
- for (const key in result) {
- if (key[0] === "_") {
- delete result[key];
- }
- }
- return result;
- });
- }
- async _detectNetwork() {
- return Network.from(getBigInt(await this._perform({ method: "chainId" })));
- }
- // @TODO: Add support to select providers to be the event subscriber
- //_getSubscriber(sub: Subscription): Subscriber {
- // throw new Error("@TODO");
- //}
- /**
- * Transforms a %%req%% into the correct method call on %%provider%%.
- */
- async _translatePerform(provider, req) {
- switch (req.method) {
- case "broadcastTransaction":
- return await provider.broadcastTransaction(req.signedTransaction);
- case "call":
- return await provider.call(Object.assign({}, req.transaction, { blockTag: req.blockTag }));
- case "chainId":
- return (await provider.getNetwork()).chainId;
- case "estimateGas":
- return await provider.estimateGas(req.transaction);
- case "getBalance":
- return await provider.getBalance(req.address, req.blockTag);
- case "getBlock": {
- const block = ("blockHash" in req) ? req.blockHash : req.blockTag;
- return await provider.getBlock(block, req.includeTransactions);
- }
- case "getBlockNumber":
- return await provider.getBlockNumber();
- case "getCode":
- return await provider.getCode(req.address, req.blockTag);
- case "getGasPrice":
- return (await provider.getFeeData()).gasPrice;
- case "getPriorityFee":
- return (await provider.getFeeData()).maxPriorityFeePerGas;
- case "getLogs":
- return await provider.getLogs(req.filter);
- case "getStorage":
- return await provider.getStorage(req.address, req.position, req.blockTag);
- case "getTransaction":
- return await provider.getTransaction(req.hash);
- case "getTransactionCount":
- return await provider.getTransactionCount(req.address, req.blockTag);
- case "getTransactionReceipt":
- return await provider.getTransactionReceipt(req.hash);
- case "getTransactionResult":
- return await provider.getTransactionResult(req.hash);
- }
- }
- // Grab the next (random) config that is not already part of
- // the running set
- #getNextConfig(running) {
- // @TODO: Maybe do a check here to favour (heavily) providers that
- // do not require waitForSync and disfavour providers that
- // seem down-ish or are behaving slowly
- const configs = Array.from(running).map((r) => r.config);
- // Shuffle the states, sorted by priority
- const allConfigs = this.#configs.slice();
- shuffle(allConfigs);
- allConfigs.sort((a, b) => (a.priority - b.priority));
- for (const config of allConfigs) {
- if (config._lastFatalError) {
- continue;
- }
- if (configs.indexOf(config) === -1) {
- return config;
- }
- }
- return null;
- }
- // Adds a new runner (if available) to running.
- #addRunner(running, req) {
- const config = this.#getNextConfig(running);
- // No runners available
- if (config == null) {
- return null;
- }
- // Create a new runner
- const runner = {
- config, result: null, didBump: false,
- perform: null, staller: null
- };
- const now = getTime();
- // Start performing this operation
- runner.perform = (async () => {
- try {
- config.requests++;
- const result = await this._translatePerform(config.provider, req);
- runner.result = { result };
- }
- catch (error) {
- config.errorResponses++;
- runner.result = { error };
- }
- const dt = (getTime() - now);
- config._totalTime += dt;
- config.rollingDuration = 0.95 * config.rollingDuration + 0.05 * dt;
- runner.perform = null;
- })();
- // Start a staller; when this times out, it's time to force
- // kicking off another runner because we are taking too long
- runner.staller = (async () => {
- await stall$2(config.stallTimeout);
- runner.staller = null;
- })();
- running.add(runner);
- return runner;
- }
- // Initializes the blockNumber and network for each runner and
- // blocks until initialized
- async #initialSync() {
- let initialSync = this.#initialSyncPromise;
- if (!initialSync) {
- const promises = [];
- this.#configs.forEach((config) => {
- promises.push((async () => {
- await waitForSync(config, 0);
- if (!config._lastFatalError) {
- config._network = await config.provider.getNetwork();
- }
- })());
- });
- this.#initialSyncPromise = initialSync = (async () => {
- // Wait for all providers to have a block number and network
- await Promise.all(promises);
- // Check all the networks match
- let chainId = null;
- for (const config of this.#configs) {
- if (config._lastFatalError) {
- continue;
- }
- const network = (config._network);
- if (chainId == null) {
- chainId = network.chainId;
- }
- else if (network.chainId !== chainId) {
- assert(false, "cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
- operation: "new FallbackProvider"
- });
- }
- }
- })();
- }
- await initialSync;
- }
- async #checkQuorum(running, req) {
- // Get all the result objects
- const results = [];
- for (const runner of running) {
- if (runner.result != null) {
- const { tag, value } = normalizeResult(runner.result);
- results.push({ tag, value, weight: runner.config.weight });
- }
- }
- // Are there enough results to event meet quorum?
- if (results.reduce((a, r) => (a + r.weight), 0) < this.quorum) {
- return undefined;
- }
- switch (req.method) {
- case "getBlockNumber": {
- // We need to get the bootstrap block height
- if (this.#height === -2) {
- this.#height = Math.ceil(getNumber(getMedian(this.quorum, this.#configs.filter((c) => (!c._lastFatalError)).map((c) => ({
- value: c.blockNumber,
- tag: getNumber(c.blockNumber).toString(),
- weight: c.weight
- })))));
- }
- // Find the mode across all the providers, allowing for
- // a little drift between block heights
- const mode = getFuzzyMode(this.quorum, results);
- if (mode === undefined) {
- return undefined;
- }
- if (mode > this.#height) {
- this.#height = mode;
- }
- return this.#height;
- }
- case "getGasPrice":
- case "getPriorityFee":
- case "estimateGas":
- return getMedian(this.quorum, results);
- case "getBlock":
- // Pending blocks are in the mempool and already
- // quite untrustworthy; just grab anything
- if ("blockTag" in req && req.blockTag === "pending") {
- return getAnyResult(this.quorum, results);
- }
- return checkQuorum(this.quorum, results);
- case "call":
- case "chainId":
- case "getBalance":
- case "getTransactionCount":
- case "getCode":
- case "getStorage":
- case "getTransaction":
- case "getTransactionReceipt":
- case "getLogs":
- return checkQuorum(this.quorum, results);
- case "broadcastTransaction":
- return getAnyResult(this.quorum, results);
- }
- assert(false, "unsupported method", "UNSUPPORTED_OPERATION", {
- operation: `_perform(${stringify(req.method)})`
- });
- }
- async #waitForQuorum(running, req) {
- if (running.size === 0) {
- throw new Error("no runners?!");
- }
- // Any promises that are interesting to watch for; an expired stall
- // or a successful perform
- const interesting = [];
- let newRunners = 0;
- for (const runner of running) {
- // No responses, yet; keep an eye on it
- if (runner.perform) {
- interesting.push(runner.perform);
- }
- // Still stalling...
- if (runner.staller) {
- interesting.push(runner.staller);
- continue;
- }
- // This runner has already triggered another runner
- if (runner.didBump) {
- continue;
- }
- // Got a response (result or error) or stalled; kick off another runner
- runner.didBump = true;
- newRunners++;
- }
- // Check if we have reached quorum on a result (or error)
- const value = await this.#checkQuorum(running, req);
- if (value !== undefined) {
- if (value instanceof Error) {
- throw value;
- }
- return value;
- }
- // Add any new runners, because a staller timed out or a result
- // or error response came in.
- for (let i = 0; i < newRunners; i++) {
- this.#addRunner(running, req);
- }
- // All providers have returned, and we have no result
- assert(interesting.length > 0, "quorum not met", "SERVER_ERROR", {
- request: "%sub-requests",
- info: { request: req, results: Array.from(running).map((r) => stringify(r.result)) }
- });
- // Wait for someone to either complete its perform or stall out
- await Promise.race(interesting);
- // This is recursive, but at worst case the depth is 2x the
- // number of providers (each has a perform and a staller)
- return await this.#waitForQuorum(running, req);
- }
- async _perform(req) {
- // Broadcasting a transaction is rare (ish) and already incurs
- // a cost on the user, so spamming is safe-ish. Just send it to
- // every backend.
- if (req.method === "broadcastTransaction") {
- // Once any broadcast provides a positive result, use it. No
- // need to wait for anyone else
- const results = this.#configs.map((c) => null);
- const broadcasts = this.#configs.map(async ({ provider, weight }, index) => {
- try {
- const result = await provider._perform(req);
- results[index] = Object.assign(normalizeResult({ result }), { weight });
- }
- catch (error) {
- results[index] = Object.assign(normalizeResult({ error }), { weight });
- }
- });
- // As each promise finishes...
- while (true) {
- // Check for a valid broadcast result
- const done = results.filter((r) => (r != null));
- for (const { value } of done) {
- if (!(value instanceof Error)) {
- return value;
- }
- }
- // Check for a legit broadcast error (one which we cannot
- // recover from; some nodes may return the following red
- // herring events:
- // - alredy seend (UNKNOWN_ERROR)
- // - NONCE_EXPIRED
- // - REPLACEMENT_UNDERPRICED
- const result = checkQuorum(this.quorum, results.filter((r) => (r != null)));
- if (isError(result, "INSUFFICIENT_FUNDS")) {
- throw result;
- }
- // Kick off the next provider (if any)
- const waiting = broadcasts.filter((b, i) => (results[i] == null));
- if (waiting.length === 0) {
- break;
- }
- await Promise.race(waiting);
- }
- // Use standard quorum results; any result was returned above,
- // so this will find any error that met quorum if any
- const result = getAnyResult(this.quorum, results);
- assert(result !== undefined, "problem multi-broadcasting", "SERVER_ERROR", {
- request: "%sub-requests",
- info: { request: req, results: results.map(stringify) }
- });
- if (result instanceof Error) {
- throw result;
- }
- return result;
- }
- await this.#initialSync();
- // Bootstrap enough runners to meet quorum
- const running = new Set();
- let inflightQuorum = 0;
- while (true) {
- const runner = this.#addRunner(running, req);
- if (runner == null) {
- break;
- }
- inflightQuorum += runner.config.weight;
- if (inflightQuorum >= this.quorum) {
- break;
- }
- }
- const result = await this.#waitForQuorum(running, req);
- // Track requests sent to a provider that are still
- // outstanding after quorum has been otherwise found
- for (const runner of running) {
- if (runner.perform && runner.result == null) {
- runner.config.lateResponses++;
- }
- }
- return result;
- }
- async destroy() {
- for (const { provider } of this.#configs) {
- provider.destroy();
- }
- super.destroy();
- }
- }
- function isWebSocketLike(value) {
- return (value && typeof (value.send) === "function" &&
- typeof (value.close) === "function");
- }
- const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goerli matic-mumbai bnbt".split(" ");
- /**
- * Returns a default provider for %%network%%.
- *
- * If %%network%% is a [[WebSocketLike]] or string that begins with
- * ``"ws:"`` or ``"wss:"``, a [[WebSocketProvider]] is returned backed
- * by that WebSocket or URL.
- *
- * If %%network%% is a string that begins with ``"HTTP:"`` or ``"HTTPS:"``,
- * a [[JsonRpcProvider]] is returned connected to that URL.
- *
- * Otherwise, a default provider is created backed by well-known public
- * Web3 backends (such as [[link-infura]]) using community-provided API
- * keys.
- *
- * The %%options%% allows specifying custom API keys per backend (setting
- * an API key to ``"-"`` will omit that provider) and ``options.exclusive``
- * can be set to either a backend name or and array of backend names, which
- * will whitelist **only** those backends.
- *
- * Current backend strings supported are:
- * - ``"alchemy"``
- * - ``"ankr"``
- * - ``"cloudflare"``
- * - ``"chainstack"``
- * - ``"etherscan"``
- * - ``"infura"``
- * - ``"publicPolygon"``
- * - ``"quicknode"``
- *
- * @example:
- * // Connect to a local Geth node
- * provider = getDefaultProvider("http://localhost:8545/");
- *
- * // Connect to Ethereum mainnet with any current and future
- * // third-party services available
- * provider = getDefaultProvider("mainnet");
- *
- * // Connect to Polygon, but only allow Etherscan and
- * // INFURA and use "MY_API_KEY" in calls to Etherscan.
- * provider = getDefaultProvider("matic", {
- * etherscan: "MY_API_KEY",
- * exclusive: [ "etherscan", "infura" ]
- * });
- */
- function getDefaultProvider(network, options) {
- if (options == null) {
- options = {};
- }
- const allowService = (name) => {
- if (options[name] === "-") {
- return false;
- }
- if (typeof (options.exclusive) === "string") {
- return (name === options.exclusive);
- }
- if (Array.isArray(options.exclusive)) {
- return (options.exclusive.indexOf(name) !== -1);
- }
- return true;
- };
- if (typeof (network) === "string" && network.match(/^https?:/)) {
- return new JsonRpcProvider(network);
- }
- if (typeof (network) === "string" && network.match(/^wss?:/) || isWebSocketLike(network)) {
- return new WebSocketProvider(network);
- }
- // Get the network and name, if possible
- let staticNetwork = null;
- try {
- staticNetwork = Network.from(network);
- }
- catch (error) { }
- const providers = [];
- if (allowService("publicPolygon") && staticNetwork) {
- if (staticNetwork.name === "matic") {
- providers.push(new JsonRpcProvider("https:/\/polygon-rpc.com/", staticNetwork, { staticNetwork }));
- }
- else if (staticNetwork.name === "matic-amoy") {
- providers.push(new JsonRpcProvider("https:/\/rpc-amoy.polygon.technology/", staticNetwork, { staticNetwork }));
- }
- }
- if (allowService("alchemy")) {
- try {
- providers.push(new AlchemyProvider(network, options.alchemy));
- }
- catch (error) { }
- }
- if (allowService("ankr") && options.ankr != null) {
- try {
- providers.push(new AnkrProvider(network, options.ankr));
- }
- catch (error) { }
- }
- if (allowService("chainstack")) {
- try {
- providers.push(new ChainstackProvider(network, options.chainstack));
- }
- catch (error) { }
- }
- if (allowService("cloudflare")) {
- try {
- providers.push(new CloudflareProvider(network));
- }
- catch (error) { }
- }
- if (allowService("etherscan")) {
- try {
- providers.push(new EtherscanProvider(network, options.etherscan));
- }
- catch (error) { }
- }
- if (allowService("infura")) {
- try {
- let projectId = options.infura;
- let projectSecret = undefined;
- if (typeof (projectId) === "object") {
- projectSecret = projectId.projectSecret;
- projectId = projectId.projectId;
- }
- providers.push(new InfuraProvider(network, projectId, projectSecret));
- }
- catch (error) { }
- }
- /*
- if (options.pocket !== "-") {
- try {
- let appId = options.pocket;
- let secretKey: undefined | string = undefined;
- let loadBalancer: undefined | boolean = undefined;
- if (typeof(appId) === "object") {
- loadBalancer = !!appId.loadBalancer;
- secretKey = appId.secretKey;
- appId = appId.appId;
- }
- providers.push(new PocketProvider(network, appId, secretKey, loadBalancer));
- } catch (error) { console.log(error); }
- }
- */
- if (allowService("quicknode")) {
- try {
- let token = options.quicknode;
- providers.push(new QuickNodeProvider(network, token));
- }
- catch (error) { }
- }
- assert(providers.length, "unsupported default network", "UNSUPPORTED_OPERATION", {
- operation: "getDefaultProvider"
- });
- // No need for a FallbackProvider
- if (providers.length === 1) {
- return providers[0];
- }
- // We use the floor because public third-party providers can be unreliable,
- // so a low number of providers with a large quorum will fail too often
- let quorum = Math.floor(providers.length / 2);
- if (quorum > 2) {
- quorum = 2;
- }
- // Testnets don't need as strong a security gaurantee and speed is
- // more useful during testing
- if (staticNetwork && Testnets.indexOf(staticNetwork.name) !== -1) {
- quorum = 1;
- }
- // Provided override qorum takes priority
- if (options && options.quorum) {
- quorum = options.quorum;
- }
- return new FallbackProvider(providers, undefined, { quorum });
- }
- /**
- * A **NonceManager** wraps another [[Signer]] and automatically manages
- * the nonce, ensuring serialized and sequential nonces are used during
- * transaction.
- */
- class NonceManager extends AbstractSigner {
- /**
- * The Signer being managed.
- */
- signer;
- #noncePromise;
- #delta;
- /**
- * Creates a new **NonceManager** to manage %%signer%%.
- */
- constructor(signer) {
- super(signer.provider);
- defineProperties(this, { signer });
- this.#noncePromise = null;
- this.#delta = 0;
- }
- async getAddress() {
- return this.signer.getAddress();
- }
- connect(provider) {
- return new NonceManager(this.signer.connect(provider));
- }
- async getNonce(blockTag) {
- if (blockTag === "pending") {
- if (this.#noncePromise == null) {
- this.#noncePromise = super.getNonce("pending");
- }
- const delta = this.#delta;
- return (await this.#noncePromise) + delta;
- }
- return super.getNonce(blockTag);
- }
- /**
- * Manually increment the nonce. This may be useful when managng
- * offline transactions.
- */
- increment() {
- this.#delta++;
- }
- /**
- * Resets the nonce, causing the **NonceManager** to reload the current
- * nonce from the blockchain on the next transaction.
- */
- reset() {
- this.#delta = 0;
- this.#noncePromise = null;
- }
- async sendTransaction(tx) {
- const noncePromise = this.getNonce("pending");
- this.increment();
- tx = await this.signer.populateTransaction(tx);
- tx.nonce = await noncePromise;
- // @TODO: Maybe handle interesting/recoverable errors?
- // Like don't increment if the tx was certainly not sent
- return await this.signer.sendTransaction(tx);
- }
- signTransaction(tx) {
- return this.signer.signTransaction(tx);
- }
- signMessage(message) {
- return this.signer.signMessage(message);
- }
- signTypedData(domain, types, value) {
- return this.signer.signTypedData(domain, types, value);
- }
- }
- /**
- * A **BrowserProvider** is intended to wrap an injected provider which
- * adheres to the [[link-eip-1193]] standard, which most (if not all)
- * currently do.
- */
- class BrowserProvider extends JsonRpcApiPollingProvider {
- #request;
- /**
- * Connect to the %%ethereum%% provider, optionally forcing the
- * %%network%%.
- */
- constructor(ethereum, network, _options) {
- // Copy the options
- const options = Object.assign({}, ((_options != null) ? _options : {}), { batchMaxCount: 1 });
- assertArgument(ethereum && ethereum.request, "invalid EIP-1193 provider", "ethereum", ethereum);
- super(network, options);
- this.#request = async (method, params) => {
- const payload = { method, params };
- this.emit("debug", { action: "sendEip1193Request", payload });
- try {
- const result = await ethereum.request(payload);
- this.emit("debug", { action: "receiveEip1193Result", result });
- return result;
- }
- catch (e) {
- const error = new Error(e.message);
- error.code = e.code;
- error.data = e.data;
- error.payload = payload;
- this.emit("debug", { action: "receiveEip1193Error", error });
- throw error;
- }
- };
- }
- async send(method, params) {
- await this._start();
- return await super.send(method, params);
- }
- async _send(payload) {
- assertArgument(!Array.isArray(payload), "EIP-1193 does not support batch request", "payload", payload);
- try {
- const result = await this.#request(payload.method, payload.params || []);
- return [{ id: payload.id, result }];
- }
- catch (e) {
- return [{
- id: payload.id,
- error: { code: e.code, data: e.data, message: e.message }
- }];
- }
- }
- getRpcError(payload, error) {
- error = JSON.parse(JSON.stringify(error));
- // EIP-1193 gives us some machine-readable error codes, so rewrite
- // them into
- switch (error.error.code || -1) {
- case 4001:
- error.error.message = `ethers-user-denied: ${error.error.message}`;
- break;
- case 4200:
- error.error.message = `ethers-unsupported: ${error.error.message}`;
- break;
- }
- return super.getRpcError(payload, error);
- }
- /**
- * Resolves to ``true`` if the provider manages the %%address%%.
- */
- async hasSigner(address) {
- if (address == null) {
- address = 0;
- }
- const accounts = await this.send("eth_accounts", []);
- if (typeof (address) === "number") {
- return (accounts.length > address);
- }
- address = address.toLowerCase();
- return accounts.filter((a) => (a.toLowerCase() === address)).length !== 0;
- }
- async getSigner(address) {
- if (address == null) {
- address = 0;
- }
- if (!(await this.hasSigner(address))) {
- try {
- //const resp =
- await this.#request("eth_requestAccounts", []);
- //console.log("RESP", resp);
- }
- catch (error) {
- const payload = error.payload;
- throw this.getRpcError(payload, { id: payload.id, error });
- }
- }
- return await super.getSigner(address);
- }
- }
- /**
- * [[link-pocket]] provides a third-party service for connecting to
- * various blockchains over JSON-RPC.
- *
- * **Supported Networks**
- *
- * - Ethereum Mainnet (``mainnet``)
- * - Goerli Testnet (``goerli``)
- * - Polygon (``matic``)
- * - Arbitrum (``arbitrum``)
- *
- * @_subsection: api/providers/thirdparty:Pocket [providers-pocket]
- */
- const defaultApplicationId = "62e1ad51b37b8e00394bda3b";
- function getHost(name) {
- switch (name) {
- case "mainnet":
- return "eth-mainnet.gateway.pokt.network";
- case "goerli":
- return "eth-goerli.gateway.pokt.network";
- case "matic":
- return "poly-mainnet.gateway.pokt.network";
- case "matic-mumbai":
- return "polygon-mumbai-rpc.gateway.pokt.network";
- }
- assertArgument(false, "unsupported network", "network", name);
- }
- /**
- * The **PocketProvider** connects to the [[link-pocket]]
- * JSON-RPC end-points.
- *
- * By default, a highly-throttled API key is used, which is
- * appropriate for quick prototypes and simple scripts. To
- * gain access to an increased rate-limit, it is highly
- * recommended to [sign up here](link-pocket-signup).
- */
- class PocketProvider extends JsonRpcProvider {
- /**
- * The Application ID for the Pocket connection.
- */
- applicationId;
- /**
- * The Application Secret for making authenticated requests
- * to the Pocket connection.
- */
- applicationSecret;
- /**
- * Create a new **PocketProvider**.
- *
- * By default connecting to ``mainnet`` with a highly throttled
- * API key.
- */
- constructor(_network, applicationId, applicationSecret) {
- if (_network == null) {
- _network = "mainnet";
- }
- const network = Network.from(_network);
- if (applicationId == null) {
- applicationId = defaultApplicationId;
- }
- if (applicationSecret == null) {
- applicationSecret = null;
- }
- const options = { staticNetwork: network };
- const request = PocketProvider.getRequest(network, applicationId, applicationSecret);
- super(request, network, options);
- defineProperties(this, { applicationId, applicationSecret });
- }
- _getProvider(chainId) {
- try {
- return new PocketProvider(chainId, this.applicationId, this.applicationSecret);
- }
- catch (error) { }
- return super._getProvider(chainId);
- }
- /**
- * Returns a prepared request for connecting to %%network%% with
- * %%applicationId%%.
- */
- static getRequest(network, applicationId, applicationSecret) {
- if (applicationId == null) {
- applicationId = defaultApplicationId;
- }
- const request = new FetchRequest(`https:/\/${getHost(network.name)}/v1/lb/${applicationId}`);
- request.allowGzip = true;
- if (applicationSecret) {
- request.setCredentials("", applicationSecret);
- }
- if (applicationId === defaultApplicationId) {
- request.retryFunc = async (request, response, attempt) => {
- showThrottleMessage("PocketProvider");
- return true;
- };
- }
- return request;
- }
- isCommunityResource() {
- return (this.applicationId === defaultApplicationId);
- }
- }
- const IpcSocketProvider = undefined;
- /**
- * The **BaseWallet** is a stream-lined implementation of a
- * [[Signer]] that operates with a private key.
- *
- * It is preferred to use the [[Wallet]] class, as it offers
- * additional functionality and simplifies loading a variety
- * of JSON formats, Mnemonic Phrases, etc.
- *
- * This class may be of use for those attempting to implement
- * a minimal Signer.
- */
- class BaseWallet extends AbstractSigner {
- /**
- * The wallet address.
- */
- address;
- #signingKey;
- /**
- * Creates a new BaseWallet for %%privateKey%%, optionally
- * connected to %%provider%%.
- *
- * If %%provider%% is not specified, only offline methods can
- * be used.
- */
- constructor(privateKey, provider) {
- super(provider);
- assertArgument(privateKey && typeof (privateKey.sign) === "function", "invalid private key", "privateKey", "[ REDACTED ]");
- this.#signingKey = privateKey;
- const address = computeAddress(this.signingKey.publicKey);
- defineProperties(this, { address });
- }
- // Store private values behind getters to reduce visibility
- // in console.log
- /**
- * The [[SigningKey]] used for signing payloads.
- */
- get signingKey() { return this.#signingKey; }
- /**
- * The private key for this wallet.
- */
- get privateKey() { return this.signingKey.privateKey; }
- async getAddress() { return this.address; }
- connect(provider) {
- return new BaseWallet(this.#signingKey, provider);
- }
- async signTransaction(tx) {
- tx = copyRequest(tx);
- // Replace any Addressable or ENS name with an address
- const { to, from } = await resolveProperties({
- to: (tx.to ? resolveAddress(tx.to, this.provider) : undefined),
- from: (tx.from ? resolveAddress(tx.from, this.provider) : undefined)
- });
- if (to != null) {
- tx.to = to;
- }
- if (from != null) {
- tx.from = from;
- }
- if (tx.from != null) {
- assertArgument(getAddress((tx.from)) === this.address, "transaction from address mismatch", "tx.from", tx.from);
- delete tx.from;
- }
- // Build the transaction
- const btx = Transaction.from(tx);
- btx.signature = this.signingKey.sign(btx.unsignedHash);
- return btx.serialized;
- }
- async signMessage(message) {
- return this.signMessageSync(message);
- }
- // @TODO: Add a secialized signTx and signTyped sync that enforces
- // all parameters are known?
- /**
- * Returns the signature for %%message%% signed with this wallet.
- */
- signMessageSync(message) {
- return this.signingKey.sign(hashMessage(message)).serialized;
- }
- async signTypedData(domain, types, value) {
- // Populate any ENS names
- const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (name) => {
- // @TODO: this should use resolveName; addresses don't
- // need a provider
- assert(this.provider != null, "cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
- operation: "resolveName",
- info: { name }
- });
- const address = await this.provider.resolveName(name);
- assert(address != null, "unconfigured ENS name", "UNCONFIGURED_NAME", {
- value: name
- });
- return address;
- });
- return this.signingKey.sign(TypedDataEncoder.hash(populated.domain, types, populated.value)).serialized;
- }
- }
- const subsChrs = " !#$%&'()*+,-./<=>?@[]^_`{|}~";
- const Word = /^[a-z]*$/i;
- function unfold(words, sep) {
- let initial = 97;
- return words.reduce((accum, word) => {
- if (word === sep) {
- initial++;
- }
- else if (word.match(Word)) {
- accum.push(String.fromCharCode(initial) + word);
- }
- else {
- initial = 97;
- accum.push(word);
- }
- return accum;
- }, []);
- }
- /**
- * @_ignore
- */
- function decode(data, subs) {
- // Replace all the substitutions with their expanded form
- for (let i = subsChrs.length - 1; i >= 0; i--) {
- data = data.split(subsChrs[i]).join(subs.substring(2 * i, 2 * i + 2));
- }
- // Get all tle clumps; each suffix, first-increment and second-increment
- const clumps = [];
- const leftover = data.replace(/(:|([0-9])|([A-Z][a-z]*))/g, (all, item, semi, word) => {
- if (semi) {
- for (let i = parseInt(semi); i >= 0; i--) {
- clumps.push(";");
- }
- }
- else {
- clumps.push(item.toLowerCase());
- }
- return "";
- });
- /* c8 ignore start */
- if (leftover) {
- throw new Error(`leftovers: ${JSON.stringify(leftover)}`);
- }
- /* c8 ignore stop */
- return unfold(unfold(clumps, ";"), ":");
- }
- /**
- * @_ignore
- */
- function decodeOwl(data) {
- assertArgument(data[0] === "0", "unsupported auwl data", "data", data);
- return decode(data.substring(1 + 2 * subsChrs.length), data.substring(1, 1 + 2 * subsChrs.length));
- }
- /**
- * A Wordlist represents a collection of language-specific
- * words used to encode and devoce [[link-bip-39]] encoded data
- * by mapping words to 11-bit values and vice versa.
- */
- class Wordlist {
- locale;
- /**
- * Creates a new Wordlist instance.
- *
- * Sub-classes MUST call this if they provide their own constructor,
- * passing in the locale string of the language.
- *
- * Generally there is no need to create instances of a Wordlist,
- * since each language-specific Wordlist creates an instance and
- * there is no state kept internally, so they are safe to share.
- */
- constructor(locale) {
- defineProperties(this, { locale });
- }
- /**
- * Sub-classes may override this to provide a language-specific
- * method for spliting %%phrase%% into individual words.
- *
- * By default, %%phrase%% is split using any sequences of
- * white-space as defined by regular expressions (i.e. ``/\s+/``).
- */
- split(phrase) {
- return phrase.toLowerCase().split(/\s+/g);
- }
- /**
- * Sub-classes may override this to provider a language-specific
- * method for joining %%words%% into a phrase.
- *
- * By default, %%words%% are joined by a single space.
- */
- join(words) {
- return words.join(" ");
- }
- }
- // Use the encode-latin.js script to create the necessary
- // data files to be consumed by this class
- /**
- * An OWL format Wordlist is an encoding method that exploits
- * the general locality of alphabetically sorted words to
- * achieve a simple but effective means of compression.
- *
- * This class is generally not useful to most developers as
- * it is used mainly internally to keep Wordlists for languages
- * based on ASCII-7 small.
- *
- * If necessary, there are tools within the ``generation/`` folder
- * to create the necessary data.
- */
- class WordlistOwl extends Wordlist {
- #data;
- #checksum;
- /**
- * Creates a new Wordlist for %%locale%% using the OWL %%data%%
- * and validated against the %%checksum%%.
- */
- constructor(locale, data, checksum) {
- super(locale);
- this.#data = data;
- this.#checksum = checksum;
- this.#words = null;
- }
- /**
- * The OWL-encoded data.
- */
- get _data() { return this.#data; }
- /**
- * Decode all the words for the wordlist.
- */
- _decodeWords() {
- return decodeOwl(this.#data);
- }
- #words;
- #loadWords() {
- if (this.#words == null) {
- const words = this._decodeWords();
- // Verify the computed list matches the official list
- const checksum = id(words.join("\n") + "\n");
- /* c8 ignore start */
- if (checksum !== this.#checksum) {
- throw new Error(`BIP39 Wordlist for ${this.locale} FAILED`);
- }
- /* c8 ignore stop */
- this.#words = words;
- }
- return this.#words;
- }
- getWord(index) {
- const words = this.#loadWords();
- assertArgument(index >= 0 && index < words.length, `invalid word index: ${index}`, "index", index);
- return words[index];
- }
- getWordIndex(word) {
- return this.#loadWords().indexOf(word);
- }
- }
- const words = "0erleonalorenseinceregesticitStanvetearctssi#ch2Athck&tneLl0And#Il.yLeOutO=S|S%b/ra@SurdU'0Ce[Cid|CountCu'Hie=IdOu,-Qui*Ro[TT]T%T*[Tu$0AptDD-tD*[Ju,M.UltV<)Vi)0Rob-0FairF%dRaid0A(EEntRee0Ead0MRRp%tS!_rmBumCoholErtI&LLeyLowMo,O}PhaReadySoT Ways0A>urAz(gOngOuntU'd0Aly,Ch%Ci|G G!GryIm$K!Noun)Nu$O` Sw T&naTiqueXietyY1ArtOlogyPe?P!Pro=Ril1ChCt-EaEnaGueMMedM%MyOundR<+Re,Ri=RowTTefa@Ti,Tw%k0KPe@SaultSetSi,SumeThma0H!>OmTa{T&dT.udeTra@0Ct]D.Gu,NtTh%ToTumn0Era+OcadoOid0AkeA*AyEsomeFulKw?d0Is:ByChel%C#D+GL<)Lc#y~MbooN<aNn RRelyRga(R*lSeS-SketTt!3A^AnAutyCau'ComeEfF%eG(Ha=H(dLie=LowLtN^Nef./TrayTt Twe&Y#d3Cyc!DKeNdOlogyRdR`Tt _{AdeAmeAnketA,EakE[IndOodO[omOu'UeUrUsh_rdAtDyIlMbNeNusOkO,Rd R(gRrowSsTtomUn)XY_{etA(AndA[A=EadEezeI{Id+IefIghtIngIskOccoliOk&OnzeOomO` OwnUsh2Bb!DdyD+tFf$oIldLbLkL!tNd!Nk Rd&Rg R,SS(e[SyTt Y Zz:Bba+B(B!CtusGeKe~LmM aMpNN$N)lNdyNn#NoeNvasNy#Pab!P.$Pta(RRb#RdRgoRpetRryRtSeShS(o/!Su$TT$ogT^Teg%yTt!UghtU'Ut]Ve3Il(gL yM|NsusNturyRe$Rta(_irAlkAmp]An+AosApt Ar+A'AtEapE{Ee'EfErryE,I{&IefIldIm}yOi)Oo'R#-U{!UnkUrn0G?Nnam#Rc!Tiz&TyVil_imApArifyAwAyE<ErkEv I{I|IffImbIn-IpO{OgO'O`OudOwnUbUmpU, Ut^_^A,C#utDeFfeeIlInL!@L%LumnMb(eMeMf%tM-Mm#Mp<yNc tNdu@NfirmNg*[N}@Nsid NtrolNv()OkOlPp PyR$ReRnR*@/Tt#U^UntryUp!Ur'Us(V Yo>_{Ad!AftAmA}AshAt AwlAzyEamEd.EekEwI{etImeIspIt-OpO[Ou^OwdUci$UelUi'Umb!Un^UshYY,$2BeLtu*PPbo?dRiousRr|Rta(R=Sh]/omTe3C!:DMa+MpN)Ng R(gShUght WnY3AlBa>BrisCadeCemb CideCl(eC%a>C*a'ErF&'F(eFyG*eLayLiv M<dMi'Ni$Nti,NyP?tP&dPos.P`PutyRi=ScribeS tSignSkSpair/royTailTe@VelopVi)Vo>3AgramAlAm#dAryCeE'lEtFf G.$Gn.yLemmaNn NosaurRe@RtSag*eScov Sea'ShSmi[S%d Splay/<)V tVideV%)Zzy5Ct%Cum|G~Lph(Ma(Na>NkeyN%OrSeUb!Ve_ftAg#AmaA,-AwEamE[IftIllInkIpI=OpUmY2CkMbNeR(g/T^Ty1Arf1Nam-:G G!RlyRnR`Sily/Sy1HoOlogyOnomy0GeItUca>1F%t0G1GhtTh 2BowD E@r-Eg<tEm|Eph<tEvat%I>Se0B?kBodyBra)Er+Ot]PloyPow Pty0Ab!A@DD![D%'EmyErgyF%)Ga+G(eH<)JoyLi,OughR-hRollSu*T Ti*TryVelope1Isode0U$Uip0AA'OdeOs]R%Upt0CapeSayS&)Ta>0Ern$H-s1Id&)IlOkeOl=1A@Amp!Ce[Ch<+C.eCludeCu'Ecu>Erci'Hau,Hib.I!I,ItOt-P<dPe@Pi*Pla(Po'P*[T&dTra0EEbrow:Br-CeCultyDeIntI`~L'MeMilyMousNNcyNtasyRmSh]TT$Th TigueUltV%.e3Atu*Bru?yD $EEdElMa!N)/iv$T^V W3B Ct]EldGu*LeLmLt N$NdNeNg NishReRmR,Sc$ShTT}[X_gAmeAshAtAv%EeIghtIpOatO{O%Ow UidUshY_mCusGIlLd~owOdOtR)Re,R+tRkRtu}RumRw?dSsil/ UndX_gi!AmeEqu|EshI&dIn+OgOntO,OwnOz&U.2ElNNnyRna)RyTu*:D+tInLaxy~ yMePRa+Rba+Rd&Rl-Rm|SSpTeTh U+Ze3N $NiusN*Nt!Nu(e/u*2O,0AntFtGg!Ng RaffeRlVe_dAn)A*A[IdeImp'ObeOomOryO=OwUe_tDde[LdOdO'RillaSpelSsipV nWn_bA)A(AntApeA[Av.yEatE&IdIefItOc yOupOwUnt_rdE[IdeIltIt?N3M:B.IrLfMm M, NdPpyRb%RdRshR=,TVeWkZ?d3AdAl`ArtAvyD+hogIght~oLmetLpNRo3Dd&Gh~NtPRe/%y5BbyCkeyLdLeLiday~owMeNeyOdPeRnRr%R'Sp.$/TelUrV 5BGeM<Mb!M%Nd*dNgryNtRd!RryRtSb<d3Brid:1EOn0EaEntifyLe2N%e4LLeg$L}[0A+Ita>M&'Mu}Pa@Po'Pro=Pul'0ChCludeComeC*a'DexD-a>Do%Du,ryF<tFl-tF%mHa!H .Iti$Je@JuryMa>N Noc|PutQuiryS<eSe@SideSpi*/$lTa@T e,ToVe,V.eVol=3On0L<dOla>Sue0Em1Ory:CketGu?RZz3AlousAns~yWel9BInKeUr}yY5D+I)MpNg!Ni%Nk/:Ng?oo3EnEpT^upY3CkDD}yNdNgdomSsTT^&TeTt&Wi4EeIfeO{Ow:BBelB%Dd DyKeMpNgua+PtopR+T T(UghUndryVaWWnWsu.Y Zy3Ad AfArnA=Ctu*FtGG$G&dIsu*M#NdNg`NsOp?dSs#Tt Vel3ArB tyBr?yC&'FeFtGhtKeMbM.NkOnQuid/Tt!VeZ?d5AdAnB, C$CkG-NelyNgOpTt yUdUn+VeY$5CkyGga+Mb N?N^Xury3R-s:Ch(eDG-G}tIdIlInJ%KeMm$NNa+Nda>NgoNs]Nu$P!Rb!R^Rg(R(eRketRria+SkSs/ T^T i$ThTrixTt XimumZe3AdowAnAsu*AtCh<-D$DiaLodyLtMb M%yNt]NuRcyR+R.RryShSsa+T$Thod3Dd!DnightLk~]M-NdNimumN%Nu>Rac!Rr%S ySs/akeXXedXtu*5Bi!DelDifyMM|N.%NkeyN, N`OnR$ReRn(gSqu.oTh T]T%Unta(U'VeVie5ChFf(LeLtiplySc!SeumShroomS-/Tu$3Self/ yTh:I=MePk(Rrow/yT]Tu*3ArCkEdGati=G!@I` PhewR=/TTw%kUtr$V WsXt3CeGht5B!I'M(eeOd!Rm$R`SeTab!TeTh(gTi)VelW5C!?Mb R'T:K0EyJe@Li+Scu*S =Ta(Vious0CurE<Tob 0Or1FF Fi)T&2L1Ay0DI=Ymp-0It0CeEI#L(eLy1EnEraIn]Po'T]1An+B.Ch?dD D(?yG<I|Ig($Ph<0Tr-h0H 0Tdo%T TputTside0AlEnEr0NN 0Yg&0/ 0O}:CtDd!GeIrLa)LmNdaNelN-N` P RadeR|RkRrotRtySsT^ThTi|TrolTt nU'VeYm|3A)AnutArAs<tL-<NN$tyNcilOp!Pp Rfe@Rm.Rs#T2O}OtoRa'Ys-$0AnoCn-Ctu*E)GGe#~LotNkO} Pe/olT^Zza_)A}tA,-A>AyEa'Ed+U{UgUn+2EmEtIntL?LeLi)NdNyOlPul?Rt]S.]Ssib!/TatoTt yV tyWd W _@i)Ai'Ed-tEf Epa*Es|EttyEv|I)IdeIm?yIntI%.yIs#Iva>IzeOb!mO)[Odu)Of.OgramOje@Omo>OofOp tyOsp O>@OudOvide2Bl-Dd(g~LpL'Mpk(N^PilPpyR^a'R.yRpo'R'ShTZz!3Ramid:99Al.yAntumArt E,]I{ItIzO>:Bb.Cco#CeCkD?DioIlInI'~yMpN^NdomN+PidReTeTh V&WZ%3AdyAlAs#BelBuildC$lCei=CipeC%dCyc!Du)F!@F%mFu'G]G*tGul?Je@LaxLea'LiefLyMa(Memb M(dMo=Nd NewNtOp&PairPeatPla)P%tQui*ScueSemb!Si,Sour)Sp#'SultTi*T*atTurnUn]Ve$ViewW?d2Y`m0BBb#CeChDeD+F!GhtGidNgOtPp!SkTu$V$V 5AdA,BotBu,CketM<)OfOkieOmSeTa>UghUndU>Y$5Bb DeGLeNNwayR$:DDd!D}[FeIlLadLm#L#LtLu>MeMp!NdTisfyToshiU)Usa+VeY1A!AnA*Att E}HemeHoolI&)I[%sOrp]OutRapRe&RiptRub1AAr^As#AtC#dC*tCt]Cur.yEdEkGm|Le@~M(?Ni%N'Nt&)RiesRvi)Ss]Tt!TupV&_dowAftAllowA*EdEllEriffIeldIftI}IpIv O{OeOotOpOrtOuld O=RimpRugUff!Y0Bl(gCkDeE+GhtGnL|Lk~yLv Mil?Mp!N)NgR&/ Tua>XZe1A>Et^IIllInIrtUll0AbAmEepEnd I)IdeIghtImOg<OtOwUsh0AllArtI!OkeOo`0A{AkeApIffOw0ApCc Ci$CkDaFtL?Ldi LidLut]L=Me#eNgOnRryRtUlUndUpUr)U`0A)A*Ati$AwnEakEci$EedEllEndH eI)Id IkeInIr.L.OilOns%O#OrtOtRayReadR(gY0Ua*UeezeUir*l_b!AdiumAffA+AirsAmpAndArtA>AyEakEelEmEpE*oI{IllIngO{Oma^O}OolOryO=Ra>gyReetRikeR#gRugg!Ud|UffUmb!Y!0Bje@Bm.BwayC)[ChDd&Ff G?G+,ItMm NNnyN'tP PplyP*meReRfa)R+Rpri'RroundR=ySpe@/a(1AllowAmpApArmE?EetIftImIngIt^Ord1MbolMptomRup/em:B!Ck!GIlL|LkNkPeR+tSk/eTtooXi3A^Am~NN<tNnisNtRm/Xt_nkAtEmeEnE%yE*EyIngIsOughtReeRi=RowUmbUnd 0CketDeG LtMb MeNyPRedSsueT!5A,BaccoDayDdl EGe` I!tK&MatoM%rowNeNgueNightOlO`PP-Pp!R^RnadoRtoi'SsT$Uri,W?dW WnY_{AdeAff-Ag-A(Ansf ApAshA=lAyEatEeEndI$IbeI{Igg ImIpOphyOub!U{UeUlyUmpetU,U`Y2BeIt]Mb!NaN}lRkeyRnRt!1El=EntyI)InI,O1PeP-$:5Ly5B*lla0Ab!Awa*C!Cov D DoFairFoldHappyIf%mIqueItIv 'KnownLo{TilUsu$Veil1Da>GradeHoldOnP Set1B<Ge0A+EEdEfulE![U$0Il.y:C<tCuumGueLidL!yL=NNishP%Rious/Ult3H-!L=tNd%Ntu*NueRbRifyRs]RyS'lT <3Ab!Br<tCiousCt%yDeoEw~a+Nta+Ol(Rtu$RusSaS.Su$T$Vid5C$I)IdLc<oLumeTeYa+:GeG#ItLk~LnutNtRfa*RmRri%ShSp/eT VeY3Al`Ap#ArA'lA` BDd(gEk&dIrdLcome/T_!AtEatEelEnE*IpIsp 0DeD`FeLd~NNdowNeNgNkNn Nt ReSdomSeShT}[5LfM<Nd OdOlRdRkRldRryR`_pE{E,!I,I>Ong::Rd3Ar~ow9UUngU`:3BraRo9NeO";
- const checksum = "0x3c8acc1e7b08d8e76f9fda015ef48dc8c710a73cb7e0f77b2c18a9b5a7adde60";
- let wordlist = null;
- /**
- * The [[link-bip39-en]] for [mnemonic phrases](link-bip-39).
- *
- * @_docloc: api/wordlists
- */
- class LangEn extends WordlistOwl {
- /**
- * Creates a new instance of the English language Wordlist.
- *
- * This should be unnecessary most of the time as the exported
- * [[langEn]] should suffice.
- *
- * @_ignore:
- */
- constructor() { super("en", words, checksum); }
- /**
- * Returns a singleton instance of a ``LangEn``, creating it
- * if this is the first time being called.
- */
- static wordlist() {
- if (wordlist == null) {
- wordlist = new LangEn();
- }
- return wordlist;
- }
- }
- // Returns a byte with the MSB bits set
- function getUpperMask(bits) {
- return ((1 << bits) - 1) << (8 - bits) & 0xff;
- }
- // Returns a byte with the LSB bits set
- function getLowerMask(bits) {
- return ((1 << bits) - 1) & 0xff;
- }
- function mnemonicToEntropy(mnemonic, wordlist) {
- assertNormalize("NFKD");
- if (wordlist == null) {
- wordlist = LangEn.wordlist();
- }
- const words = wordlist.split(mnemonic);
- assertArgument((words.length % 3) === 0 && words.length >= 12 && words.length <= 24, "invalid mnemonic length", "mnemonic", "[ REDACTED ]");
- const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
- let offset = 0;
- for (let i = 0; i < words.length; i++) {
- let index = wordlist.getWordIndex(words[i].normalize("NFKD"));
- assertArgument(index >= 0, `invalid mnemonic word at index ${i}`, "mnemonic", "[ REDACTED ]");
- for (let bit = 0; bit < 11; bit++) {
- if (index & (1 << (10 - bit))) {
- entropy[offset >> 3] |= (1 << (7 - (offset % 8)));
- }
- offset++;
- }
- }
- const entropyBits = 32 * words.length / 3;
- const checksumBits = words.length / 3;
- const checksumMask = getUpperMask(checksumBits);
- const checksum = getBytes(sha256(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
- assertArgument(checksum === (entropy[entropy.length - 1] & checksumMask), "invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
- return hexlify(entropy.slice(0, entropyBits / 8));
- }
- function entropyToMnemonic(entropy, wordlist) {
- assertArgument((entropy.length % 4) === 0 && entropy.length >= 16 && entropy.length <= 32, "invalid entropy size", "entropy", "[ REDACTED ]");
- if (wordlist == null) {
- wordlist = LangEn.wordlist();
- }
- const indices = [0];
- let remainingBits = 11;
- for (let i = 0; i < entropy.length; i++) {
- // Consume the whole byte (with still more to go)
- if (remainingBits > 8) {
- indices[indices.length - 1] <<= 8;
- indices[indices.length - 1] |= entropy[i];
- remainingBits -= 8;
- // This byte will complete an 11-bit index
- }
- else {
- indices[indices.length - 1] <<= remainingBits;
- indices[indices.length - 1] |= entropy[i] >> (8 - remainingBits);
- // Start the next word
- indices.push(entropy[i] & getLowerMask(8 - remainingBits));
- remainingBits += 3;
- }
- }
- // Compute the checksum bits
- const checksumBits = entropy.length / 4;
- const checksum = parseInt(sha256(entropy).substring(2, 4), 16) & getUpperMask(checksumBits);
- // Shift the checksum into the word indices
- indices[indices.length - 1] <<= checksumBits;
- indices[indices.length - 1] |= (checksum >> (8 - checksumBits));
- return wordlist.join(indices.map((index) => wordlist.getWord(index)));
- }
- const _guard$1 = {};
- /**
- * A **Mnemonic** wraps all properties required to compute [[link-bip-39]]
- * seeds and convert between phrases and entropy.
- */
- class Mnemonic {
- /**
- * The mnemonic phrase of 12, 15, 18, 21 or 24 words.
- *
- * Use the [[wordlist]] ``split`` method to get the individual words.
- */
- phrase;
- /**
- * The password used for this mnemonic. If no password is used this
- * is the empty string (i.e. ``""``) as per the specification.
- */
- password;
- /**
- * The wordlist for this mnemonic.
- */
- wordlist;
- /**
- * The underlying entropy which the mnemonic encodes.
- */
- entropy;
- /**
- * @private
- */
- constructor(guard, entropy, phrase, password, wordlist) {
- if (password == null) {
- password = "";
- }
- if (wordlist == null) {
- wordlist = LangEn.wordlist();
- }
- assertPrivate(guard, _guard$1, "Mnemonic");
- defineProperties(this, { phrase, password, wordlist, entropy });
- }
- /**
- * Returns the seed for the mnemonic.
- */
- computeSeed() {
- const salt = toUtf8Bytes("mnemonic" + this.password, "NFKD");
- return pbkdf2(toUtf8Bytes(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
- }
- /**
- * Creates a new Mnemonic for the %%phrase%%.
- *
- * The default %%password%% is the empty string and the default
- * wordlist is the [English wordlists](LangEn).
- */
- static fromPhrase(phrase, password, wordlist) {
- // Normalize the case and space; throws if invalid
- const entropy = mnemonicToEntropy(phrase, wordlist);
- phrase = entropyToMnemonic(getBytes(entropy), wordlist);
- return new Mnemonic(_guard$1, entropy, phrase, password, wordlist);
- }
- /**
- * Create a new **Mnemonic** from the %%entropy%%.
- *
- * The default %%password%% is the empty string and the default
- * wordlist is the [English wordlists](LangEn).
- */
- static fromEntropy(_entropy, password, wordlist) {
- const entropy = getBytes(_entropy, "entropy");
- const phrase = entropyToMnemonic(entropy, wordlist);
- return new Mnemonic(_guard$1, hexlify(entropy), phrase, password, wordlist);
- }
- /**
- * Returns the phrase for %%mnemonic%%.
- */
- static entropyToPhrase(_entropy, wordlist) {
- const entropy = getBytes(_entropy, "entropy");
- return entropyToMnemonic(entropy, wordlist);
- }
- /**
- * Returns the entropy for %%phrase%%.
- */
- static phraseToEntropy(phrase, wordlist) {
- return mnemonicToEntropy(phrase, wordlist);
- }
- /**
- * Returns true if %%phrase%% is a valid [[link-bip-39]] phrase.
- *
- * This checks all the provided words belong to the %%wordlist%%,
- * that the length is valid and the checksum is correct.
- */
- static isValidMnemonic(phrase, wordlist) {
- try {
- mnemonicToEntropy(phrase, wordlist);
- return true;
- }
- catch (error) { }
- return false;
- }
- }
- /*! MIT License. Copyright 2015-2022 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
- var __classPrivateFieldGet$2 = (__$G && __$G.__classPrivateFieldGet) || function (receiver, state, kind, f) {
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
- };
- var __classPrivateFieldSet$2 = (__$G && __$G.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
- if (kind === "m") throw new TypeError("Private method is not writable");
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
- };
- var _AES_key, _AES_Kd, _AES_Ke;
- // Number of rounds by keysize
- const numberOfRounds = { 16: 10, 24: 12, 32: 14 };
- // Round constant words
- const rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91];
- // S-box and Inverse S-box (S is for Substitution)
- const S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
- const Si = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d];
- // Transformations for encryption
- const T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a];
- const T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616];
- const T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16];
- const T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c];
- // Transformations for decryption
- const T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742];
- const T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857];
- const T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8];
- const T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0];
- // Transformations for decryption key expansion
- const U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3];
- const U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697];
- const U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46];
- const U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d];
- function convertToInt32(bytes) {
- const result = [];
- for (let i = 0; i < bytes.length; i += 4) {
- result.push((bytes[i] << 24) | (bytes[i + 1] << 16) | (bytes[i + 2] << 8) | bytes[i + 3]);
- }
- return result;
- }
- class AES {
- get key() { return __classPrivateFieldGet$2(this, _AES_key, "f").slice(); }
- constructor(key) {
- _AES_key.set(this, void 0);
- _AES_Kd.set(this, void 0);
- _AES_Ke.set(this, void 0);
- if (!(this instanceof AES)) {
- throw Error('AES must be instanitated with `new`');
- }
- __classPrivateFieldSet$2(this, _AES_key, new Uint8Array(key), "f");
- const rounds = numberOfRounds[this.key.length];
- if (rounds == null) {
- throw new TypeError('invalid key size (must be 16, 24 or 32 bytes)');
- }
- // encryption round keys
- __classPrivateFieldSet$2(this, _AES_Ke, [], "f");
- // decryption round keys
- __classPrivateFieldSet$2(this, _AES_Kd, [], "f");
- for (let i = 0; i <= rounds; i++) {
- __classPrivateFieldGet$2(this, _AES_Ke, "f").push([0, 0, 0, 0]);
- __classPrivateFieldGet$2(this, _AES_Kd, "f").push([0, 0, 0, 0]);
- }
- const roundKeyCount = (rounds + 1) * 4;
- const KC = this.key.length / 4;
- // convert the key into ints
- const tk = convertToInt32(this.key);
- // copy values into round key arrays
- let index;
- for (let i = 0; i < KC; i++) {
- index = i >> 2;
- __classPrivateFieldGet$2(this, _AES_Ke, "f")[index][i % 4] = tk[i];
- __classPrivateFieldGet$2(this, _AES_Kd, "f")[rounds - index][i % 4] = tk[i];
- }
- // key expansion (fips-197 section 5.2)
- let rconpointer = 0;
- let t = KC, tt;
- while (t < roundKeyCount) {
- tt = tk[KC - 1];
- tk[0] ^= ((S[(tt >> 16) & 0xFF] << 24) ^
- (S[(tt >> 8) & 0xFF] << 16) ^
- (S[tt & 0xFF] << 8) ^
- S[(tt >> 24) & 0xFF] ^
- (rcon[rconpointer] << 24));
- rconpointer += 1;
- // key expansion (for non-256 bit)
- if (KC != 8) {
- for (let i = 1; i < KC; i++) {
- tk[i] ^= tk[i - 1];
- }
- // key expansion for 256-bit keys is "slightly different" (fips-197)
- }
- else {
- for (let i = 1; i < (KC / 2); i++) {
- tk[i] ^= tk[i - 1];
- }
- tt = tk[(KC / 2) - 1];
- tk[KC / 2] ^= (S[tt & 0xFF] ^
- (S[(tt >> 8) & 0xFF] << 8) ^
- (S[(tt >> 16) & 0xFF] << 16) ^
- (S[(tt >> 24) & 0xFF] << 24));
- for (let i = (KC / 2) + 1; i < KC; i++) {
- tk[i] ^= tk[i - 1];
- }
- }
- // copy values into round key arrays
- let i = 0, r, c;
- while (i < KC && t < roundKeyCount) {
- r = t >> 2;
- c = t % 4;
- __classPrivateFieldGet$2(this, _AES_Ke, "f")[r][c] = tk[i];
- __classPrivateFieldGet$2(this, _AES_Kd, "f")[rounds - r][c] = tk[i++];
- t++;
- }
- }
- // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
- for (let r = 1; r < rounds; r++) {
- for (let c = 0; c < 4; c++) {
- tt = __classPrivateFieldGet$2(this, _AES_Kd, "f")[r][c];
- __classPrivateFieldGet$2(this, _AES_Kd, "f")[r][c] = (U1[(tt >> 24) & 0xFF] ^
- U2[(tt >> 16) & 0xFF] ^
- U3[(tt >> 8) & 0xFF] ^
- U4[tt & 0xFF]);
- }
- }
- }
- encrypt(plaintext) {
- if (plaintext.length != 16) {
- throw new TypeError('invalid plaintext size (must be 16 bytes)');
- }
- const rounds = __classPrivateFieldGet$2(this, _AES_Ke, "f").length - 1;
- const a = [0, 0, 0, 0];
- // convert plaintext to (ints ^ key)
- let t = convertToInt32(plaintext);
- for (let i = 0; i < 4; i++) {
- t[i] ^= __classPrivateFieldGet$2(this, _AES_Ke, "f")[0][i];
- }
- // apply round transforms
- for (let r = 1; r < rounds; r++) {
- for (let i = 0; i < 4; i++) {
- a[i] = (T1[(t[i] >> 24) & 0xff] ^
- T2[(t[(i + 1) % 4] >> 16) & 0xff] ^
- T3[(t[(i + 2) % 4] >> 8) & 0xff] ^
- T4[t[(i + 3) % 4] & 0xff] ^
- __classPrivateFieldGet$2(this, _AES_Ke, "f")[r][i]);
- }
- t = a.slice();
- }
- // the last round is special
- const result = new Uint8Array(16);
- let tt = 0;
- for (let i = 0; i < 4; i++) {
- tt = __classPrivateFieldGet$2(this, _AES_Ke, "f")[rounds][i];
- result[4 * i] = (S[(t[i] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
- result[4 * i + 1] = (S[(t[(i + 1) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
- result[4 * i + 2] = (S[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
- result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
- }
- return result;
- }
- decrypt(ciphertext) {
- if (ciphertext.length != 16) {
- throw new TypeError('invalid ciphertext size (must be 16 bytes)');
- }
- const rounds = __classPrivateFieldGet$2(this, _AES_Kd, "f").length - 1;
- const a = [0, 0, 0, 0];
- // convert plaintext to (ints ^ key)
- let t = convertToInt32(ciphertext);
- for (let i = 0; i < 4; i++) {
- t[i] ^= __classPrivateFieldGet$2(this, _AES_Kd, "f")[0][i];
- }
- // apply round transforms
- for (let r = 1; r < rounds; r++) {
- for (let i = 0; i < 4; i++) {
- a[i] = (T5[(t[i] >> 24) & 0xff] ^
- T6[(t[(i + 3) % 4] >> 16) & 0xff] ^
- T7[(t[(i + 2) % 4] >> 8) & 0xff] ^
- T8[t[(i + 1) % 4] & 0xff] ^
- __classPrivateFieldGet$2(this, _AES_Kd, "f")[r][i]);
- }
- t = a.slice();
- }
- // the last round is special
- const result = new Uint8Array(16);
- let tt = 0;
- for (let i = 0; i < 4; i++) {
- tt = __classPrivateFieldGet$2(this, _AES_Kd, "f")[rounds][i];
- result[4 * i] = (Si[(t[i] >> 24) & 0xff] ^ (tt >> 24)) & 0xff;
- result[4 * i + 1] = (Si[(t[(i + 3) % 4] >> 16) & 0xff] ^ (tt >> 16)) & 0xff;
- result[4 * i + 2] = (Si[(t[(i + 2) % 4] >> 8) & 0xff] ^ (tt >> 8)) & 0xff;
- result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
- }
- return result;
- }
- }
- _AES_key = new WeakMap(), _AES_Kd = new WeakMap(), _AES_Ke = new WeakMap();
- class ModeOfOperation {
- constructor(name, key, cls) {
- if (cls && !(this instanceof cls)) {
- throw new Error(`${name} must be instantiated with "new"`);
- }
- Object.defineProperties(this, {
- aes: { enumerable: true, value: new AES(key) },
- name: { enumerable: true, value: name }
- });
- }
- }
- // Cipher Block Chaining
- var __classPrivateFieldSet$1 = (__$G && __$G.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
- if (kind === "m") throw new TypeError("Private method is not writable");
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
- };
- var __classPrivateFieldGet$1 = (__$G && __$G.__classPrivateFieldGet) || function (receiver, state, kind, f) {
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
- };
- var _CBC_iv, _CBC_lastBlock;
- class CBC extends ModeOfOperation {
- constructor(key, iv) {
- super("ECC", key, CBC);
- _CBC_iv.set(this, void 0);
- _CBC_lastBlock.set(this, void 0);
- if (iv) {
- if (iv.length % 16) {
- throw new TypeError("invalid iv size (must be 16 bytes)");
- }
- __classPrivateFieldSet$1(this, _CBC_iv, new Uint8Array(iv), "f");
- }
- else {
- __classPrivateFieldSet$1(this, _CBC_iv, new Uint8Array(16), "f");
- }
- __classPrivateFieldSet$1(this, _CBC_lastBlock, this.iv, "f");
- }
- get iv() { return new Uint8Array(__classPrivateFieldGet$1(this, _CBC_iv, "f")); }
- encrypt(plaintext) {
- if (plaintext.length % 16) {
- throw new TypeError("invalid plaintext size (must be multiple of 16 bytes)");
- }
- const ciphertext = new Uint8Array(plaintext.length);
- for (let i = 0; i < plaintext.length; i += 16) {
- for (let j = 0; j < 16; j++) {
- __classPrivateFieldGet$1(this, _CBC_lastBlock, "f")[j] ^= plaintext[i + j];
- }
- __classPrivateFieldSet$1(this, _CBC_lastBlock, this.aes.encrypt(__classPrivateFieldGet$1(this, _CBC_lastBlock, "f")), "f");
- ciphertext.set(__classPrivateFieldGet$1(this, _CBC_lastBlock, "f"), i);
- }
- return ciphertext;
- }
- decrypt(ciphertext) {
- if (ciphertext.length % 16) {
- throw new TypeError("invalid ciphertext size (must be multiple of 16 bytes)");
- }
- const plaintext = new Uint8Array(ciphertext.length);
- for (let i = 0; i < ciphertext.length; i += 16) {
- const block = this.aes.decrypt(ciphertext.subarray(i, i + 16));
- for (let j = 0; j < 16; j++) {
- plaintext[i + j] = block[j] ^ __classPrivateFieldGet$1(this, _CBC_lastBlock, "f")[j];
- __classPrivateFieldGet$1(this, _CBC_lastBlock, "f")[j] = ciphertext[i + j];
- }
- }
- return plaintext;
- }
- }
- _CBC_iv = new WeakMap(), _CBC_lastBlock = new WeakMap();
- // Counter Mode
- var __classPrivateFieldSet = (__$G && __$G.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
- if (kind === "m") throw new TypeError("Private method is not writable");
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
- };
- var __classPrivateFieldGet = (__$G && __$G.__classPrivateFieldGet) || function (receiver, state, kind, f) {
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
- };
- var _CTR_remaining, _CTR_remainingIndex, _CTR_counter;
- class CTR extends ModeOfOperation {
- constructor(key, initialValue) {
- super("CTR", key, CTR);
- // Remaining bytes for the one-time pad
- _CTR_remaining.set(this, void 0);
- _CTR_remainingIndex.set(this, void 0);
- // The current counter
- _CTR_counter.set(this, void 0);
- __classPrivateFieldSet(this, _CTR_counter, new Uint8Array(16), "f");
- __classPrivateFieldGet(this, _CTR_counter, "f").fill(0);
- __classPrivateFieldSet(this, _CTR_remaining, __classPrivateFieldGet(this, _CTR_counter, "f"), "f"); // This will be discarded immediately
- __classPrivateFieldSet(this, _CTR_remainingIndex, 16, "f");
- if (initialValue == null) {
- initialValue = 1;
- }
- if (typeof (initialValue) === "number") {
- this.setCounterValue(initialValue);
- }
- else {
- this.setCounterBytes(initialValue);
- }
- }
- get counter() { return new Uint8Array(__classPrivateFieldGet(this, _CTR_counter, "f")); }
- setCounterValue(value) {
- if (!Number.isInteger(value) || value < 0 || value > Number.MAX_SAFE_INTEGER) {
- throw new TypeError("invalid counter initial integer value");
- }
- for (let index = 15; index >= 0; --index) {
- __classPrivateFieldGet(this, _CTR_counter, "f")[index] = value % 256;
- value = Math.floor(value / 256);
- }
- }
- setCounterBytes(value) {
- if (value.length !== 16) {
- throw new TypeError("invalid counter initial Uint8Array value length");
- }
- __classPrivateFieldGet(this, _CTR_counter, "f").set(value);
- }
- increment() {
- for (let i = 15; i >= 0; i--) {
- if (__classPrivateFieldGet(this, _CTR_counter, "f")[i] === 255) {
- __classPrivateFieldGet(this, _CTR_counter, "f")[i] = 0;
- }
- else {
- __classPrivateFieldGet(this, _CTR_counter, "f")[i]++;
- break;
- }
- }
- }
- encrypt(plaintext) {
- var _a, _b;
- const crypttext = new Uint8Array(plaintext);
- for (let i = 0; i < crypttext.length; i++) {
- if (__classPrivateFieldGet(this, _CTR_remainingIndex, "f") === 16) {
- __classPrivateFieldSet(this, _CTR_remaining, this.aes.encrypt(__classPrivateFieldGet(this, _CTR_counter, "f")), "f");
- __classPrivateFieldSet(this, _CTR_remainingIndex, 0, "f");
- this.increment();
- }
- crypttext[i] ^= __classPrivateFieldGet(this, _CTR_remaining, "f")[__classPrivateFieldSet(this, _CTR_remainingIndex, (_b = __classPrivateFieldGet(this, _CTR_remainingIndex, "f"), _a = _b++, _b), "f"), _a];
- }
- return crypttext;
- }
- decrypt(ciphertext) {
- return this.encrypt(ciphertext);
- }
- }
- _CTR_remaining = new WeakMap(), _CTR_remainingIndex = new WeakMap(), _CTR_counter = new WeakMap();
- function pkcs7Strip(data) {
- if (data.length < 16) {
- throw new TypeError('PKCS#7 invalid length');
- }
- const padder = data[data.length - 1];
- if (padder > 16) {
- throw new TypeError('PKCS#7 padding byte out of range');
- }
- const length = data.length - padder;
- for (let i = 0; i < padder; i++) {
- if (data[length + i] !== padder) {
- throw new TypeError('PKCS#7 invalid padding byte');
- }
- }
- return new Uint8Array(data.subarray(0, length));
- }
- /**
- * @_ignore
- */
- function looseArrayify(hexString) {
- if (typeof (hexString) === "string" && !hexString.startsWith("0x")) {
- hexString = "0x" + hexString;
- }
- return getBytesCopy(hexString);
- }
- function zpad$1(value, length) {
- value = String(value);
- while (value.length < length) {
- value = '0' + value;
- }
- return value;
- }
- function getPassword(password) {
- if (typeof (password) === 'string') {
- return toUtf8Bytes(password, "NFKC");
- }
- return getBytesCopy(password);
- }
- function spelunk(object, _path) {
- const match = _path.match(/^([a-z0-9$_.-]*)(:([a-z]+))?(!)?$/i);
- assertArgument(match != null, "invalid path", "path", _path);
- const path = match[1];
- const type = match[3];
- const reqd = (match[4] === "!");
- let cur = object;
- for (const comp of path.toLowerCase().split('.')) {
- // Search for a child object with a case-insensitive matching key
- if (Array.isArray(cur)) {
- if (!comp.match(/^[0-9]+$/)) {
- break;
- }
- cur = cur[parseInt(comp)];
- }
- else if (typeof (cur) === "object") {
- let found = null;
- for (const key in cur) {
- if (key.toLowerCase() === comp) {
- found = cur[key];
- break;
- }
- }
- cur = found;
- }
- else {
- cur = null;
- }
- if (cur == null) {
- break;
- }
- }
- assertArgument(!reqd || cur != null, "missing required value", "path", path);
- if (type && cur != null) {
- if (type === "int") {
- if (typeof (cur) === "string" && cur.match(/^-?[0-9]+$/)) {
- return parseInt(cur);
- }
- else if (Number.isSafeInteger(cur)) {
- return cur;
- }
- }
- if (type === "number") {
- if (typeof (cur) === "string" && cur.match(/^-?[0-9.]*$/)) {
- return parseFloat(cur);
- }
- }
- if (type === "data") {
- if (typeof (cur) === "string") {
- return looseArrayify(cur);
- }
- }
- if (type === "array" && Array.isArray(cur)) {
- return cur;
- }
- if (type === typeof (cur)) {
- return cur;
- }
- assertArgument(false, `wrong type found for ${type} `, "path", path);
- }
- return cur;
- }
- /*
- export function follow(object: any, path: string): null | string {
- let currentChild = object;
- for (const comp of path.toLowerCase().split('/')) {
- // Search for a child object with a case-insensitive matching key
- let matchingChild = null;
- for (const key in currentChild) {
- if (key.toLowerCase() === comp) {
- matchingChild = currentChild[key];
- break;
- }
- }
- if (matchingChild === null) { return null; }
- currentChild = matchingChild;
- }
- return currentChild;
- }
- // "path/to/something:type!"
- export function followRequired(data: any, path: string): string {
- const value = follow(data, path);
- if (value != null) { return value; }
- return logger.throwArgumentError("invalid value", `data:${ path }`,
- JSON.stringify(data));
- }
- */
- // See: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
- /*
- export function uuidV4(randomBytes: BytesLike): string {
- const bytes = getBytes(randomBytes, "randomBytes");
- // Section: 4.1.3:
- // - time_hi_and_version[12:16] = 0b0100
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
- // Section 4.4
- // - clock_seq_hi_and_reserved[6] = 0b0
- // - clock_seq_hi_and_reserved[7] = 0b1
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
- const value = hexlify(bytes);
- return [
- value.substring(2, 10),
- value.substring(10, 14),
- value.substring(14, 18),
- value.substring(18, 22),
- value.substring(22, 34),
- ].join("-");
- }
- */
- /**
- * The JSON Wallet formats allow a simple way to store the private
- * keys needed in Ethereum along with related information and allows
- * for extensible forms of encryption.
- *
- * These utilities facilitate decrypting and encrypting the most common
- * JSON Wallet formats.
- *
- * @_subsection: api/wallet:JSON Wallets [json-wallets]
- */
- const defaultPath$1 = "m/44'/60'/0'/0/0";
- /**
- * Returns true if %%json%% is a valid JSON Keystore Wallet.
- */
- function isKeystoreJson(json) {
- try {
- const data = JSON.parse(json);
- const version = ((data.version != null) ? parseInt(data.version) : 0);
- if (version === 3) {
- return true;
- }
- }
- catch (error) { }
- return false;
- }
- function decrypt(data, key, ciphertext) {
- const cipher = spelunk(data, "crypto.cipher:string");
- if (cipher === "aes-128-ctr") {
- const iv = spelunk(data, "crypto.cipherparams.iv:data!");
- const aesCtr = new CTR(key, iv);
- return hexlify(aesCtr.decrypt(ciphertext));
- }
- assert(false, "unsupported cipher", "UNSUPPORTED_OPERATION", {
- operation: "decrypt"
- });
- }
- function getAccount(data, _key) {
- const key = getBytes(_key);
- const ciphertext = spelunk(data, "crypto.ciphertext:data!");
- const computedMAC = hexlify(keccak256(concat([key.slice(16, 32), ciphertext]))).substring(2);
- assertArgument(computedMAC === spelunk(data, "crypto.mac:string!").toLowerCase(), "incorrect password", "password", "[ REDACTED ]");
- const privateKey = decrypt(data, key.slice(0, 16), ciphertext);
- const address = computeAddress(privateKey);
- if (data.address) {
- let check = data.address.toLowerCase();
- if (!check.startsWith("0x")) {
- check = "0x" + check;
- }
- assertArgument(getAddress(check) === address, "keystore address/privateKey mismatch", "address", data.address);
- }
- const account = { address, privateKey };
- // Version 0.1 x-ethers metadata must contain an encrypted mnemonic phrase
- const version = spelunk(data, "x-ethers.version:string");
- if (version === "0.1") {
- const mnemonicKey = key.slice(32, 64);
- const mnemonicCiphertext = spelunk(data, "x-ethers.mnemonicCiphertext:data!");
- const mnemonicIv = spelunk(data, "x-ethers.mnemonicCounter:data!");
- const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
- account.mnemonic = {
- path: (spelunk(data, "x-ethers.path:string") || defaultPath$1),
- locale: (spelunk(data, "x-ethers.locale:string") || "en"),
- entropy: hexlify(getBytes(mnemonicAesCtr.decrypt(mnemonicCiphertext)))
- };
- }
- return account;
- }
- function getDecryptKdfParams(data) {
- const kdf = spelunk(data, "crypto.kdf:string");
- if (kdf && typeof (kdf) === "string") {
- if (kdf.toLowerCase() === "scrypt") {
- const salt = spelunk(data, "crypto.kdfparams.salt:data!");
- const N = spelunk(data, "crypto.kdfparams.n:int!");
- const r = spelunk(data, "crypto.kdfparams.r:int!");
- const p = spelunk(data, "crypto.kdfparams.p:int!");
- // Make sure N is a power of 2
- assertArgument(N > 0 && (N & (N - 1)) === 0, "invalid kdf.N", "kdf.N", N);
- assertArgument(r > 0 && p > 0, "invalid kdf", "kdf", kdf);
- const dkLen = spelunk(data, "crypto.kdfparams.dklen:int!");
- assertArgument(dkLen === 32, "invalid kdf.dklen", "kdf.dflen", dkLen);
- return { name: "scrypt", salt, N, r, p, dkLen: 64 };
- }
- else if (kdf.toLowerCase() === "pbkdf2") {
- const salt = spelunk(data, "crypto.kdfparams.salt:data!");
- const prf = spelunk(data, "crypto.kdfparams.prf:string!");
- const algorithm = prf.split("-").pop();
- assertArgument(algorithm === "sha256" || algorithm === "sha512", "invalid kdf.pdf", "kdf.pdf", prf);
- const count = spelunk(data, "crypto.kdfparams.c:int!");
- const dkLen = spelunk(data, "crypto.kdfparams.dklen:int!");
- assertArgument(dkLen === 32, "invalid kdf.dklen", "kdf.dklen", dkLen);
- return { name: "pbkdf2", salt, count, dkLen, algorithm };
- }
- }
- assertArgument(false, "unsupported key-derivation function", "kdf", kdf);
- }
- /**
- * Returns the account details for the JSON Keystore Wallet %%json%%
- * using %%password%%.
- *
- * It is preferred to use the [async version](decryptKeystoreJson)
- * instead, which allows a [[ProgressCallback]] to keep the user informed
- * as to the decryption status.
- *
- * This method will block the event loop (freezing all UI) until decryption
- * is complete, which can take quite some time, depending on the wallet
- * paramters and platform.
- */
- function decryptKeystoreJsonSync(json, _password) {
- const data = JSON.parse(json);
- const password = getPassword(_password);
- const params = getDecryptKdfParams(data);
- if (params.name === "pbkdf2") {
- const { salt, count, dkLen, algorithm } = params;
- const key = pbkdf2(password, salt, count, dkLen, algorithm);
- return getAccount(data, key);
- }
- assert(params.name === "scrypt", "cannot be reached", "UNKNOWN_ERROR", { params });
- const { salt, N, r, p, dkLen } = params;
- const key = scryptSync(password, salt, N, r, p, dkLen);
- return getAccount(data, key);
- }
- function stall$1(duration) {
- return new Promise((resolve) => { setTimeout(() => { resolve(); }, duration); });
- }
- /**
- * Resolves to the decrypted JSON Keystore Wallet %%json%% using the
- * %%password%%.
- *
- * If provided, %%progress%% will be called periodically during the
- * decrpytion to provide feedback, and if the function returns
- * ``false`` will halt decryption.
- *
- * The %%progressCallback%% will **always** receive ``0`` before
- * decryption begins and ``1`` when complete.
- */
- async function decryptKeystoreJson(json, _password, progress) {
- const data = JSON.parse(json);
- const password = getPassword(_password);
- const params = getDecryptKdfParams(data);
- if (params.name === "pbkdf2") {
- if (progress) {
- progress(0);
- await stall$1(0);
- }
- const { salt, count, dkLen, algorithm } = params;
- const key = pbkdf2(password, salt, count, dkLen, algorithm);
- if (progress) {
- progress(1);
- await stall$1(0);
- }
- return getAccount(data, key);
- }
- assert(params.name === "scrypt", "cannot be reached", "UNKNOWN_ERROR", { params });
- const { salt, N, r, p, dkLen } = params;
- const key = await scrypt(password, salt, N, r, p, dkLen, progress);
- return getAccount(data, key);
- }
- function getEncryptKdfParams(options) {
- // Check/generate the salt
- const salt = (options.salt != null) ? getBytes(options.salt, "options.salt") : randomBytes(32);
- // Override the scrypt password-based key derivation function parameters
- let N = (1 << 17), r = 8, p = 1;
- if (options.scrypt) {
- if (options.scrypt.N) {
- N = options.scrypt.N;
- }
- if (options.scrypt.r) {
- r = options.scrypt.r;
- }
- if (options.scrypt.p) {
- p = options.scrypt.p;
- }
- }
- assertArgument(typeof (N) === "number" && N > 0 && Number.isSafeInteger(N) && (BigInt(N) & BigInt(N - 1)) === BigInt(0), "invalid scrypt N parameter", "options.N", N);
- assertArgument(typeof (r) === "number" && r > 0 && Number.isSafeInteger(r), "invalid scrypt r parameter", "options.r", r);
- assertArgument(typeof (p) === "number" && p > 0 && Number.isSafeInteger(p), "invalid scrypt p parameter", "options.p", p);
- return { name: "scrypt", dkLen: 32, salt, N, r, p };
- }
- function _encryptKeystore(key, kdf, account, options) {
- const privateKey = getBytes(account.privateKey, "privateKey");
- // Override initialization vector
- const iv = (options.iv != null) ? getBytes(options.iv, "options.iv") : randomBytes(16);
- assertArgument(iv.length === 16, "invalid options.iv length", "options.iv", options.iv);
- // Override the uuid
- const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid") : randomBytes(16);
- assertArgument(uuidRandom.length === 16, "invalid options.uuid length", "options.uuid", options.iv);
- // This will be used to encrypt the wallet (as per Web3 secret storage)
- // - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
- // - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
- const derivedKey = key.slice(0, 16);
- const macPrefix = key.slice(16, 32);
- // Encrypt the private key
- const aesCtr = new CTR(derivedKey, iv);
- const ciphertext = getBytes(aesCtr.encrypt(privateKey));
- // Compute the message authentication code, used to check the password
- const mac = keccak256(concat([macPrefix, ciphertext]));
- // See: https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
- const data = {
- address: account.address.substring(2).toLowerCase(),
- id: uuidV4(uuidRandom),
- version: 3,
- Crypto: {
- cipher: "aes-128-ctr",
- cipherparams: {
- iv: hexlify(iv).substring(2),
- },
- ciphertext: hexlify(ciphertext).substring(2),
- kdf: "scrypt",
- kdfparams: {
- salt: hexlify(kdf.salt).substring(2),
- n: kdf.N,
- dklen: 32,
- p: kdf.p,
- r: kdf.r
- },
- mac: mac.substring(2)
- }
- };
- // If we have a mnemonic, encrypt it into the JSON wallet
- if (account.mnemonic) {
- const client = (options.client != null) ? options.client : `ethers/${version}`;
- const path = account.mnemonic.path || defaultPath$1;
- const locale = account.mnemonic.locale || "en";
- const mnemonicKey = key.slice(32, 64);
- const entropy = getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
- const mnemonicIv = randomBytes(16);
- const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
- const mnemonicCiphertext = getBytes(mnemonicAesCtr.encrypt(entropy));
- const now = new Date();
- const timestamp = (now.getUTCFullYear() + "-" +
- zpad$1(now.getUTCMonth() + 1, 2) + "-" +
- zpad$1(now.getUTCDate(), 2) + "T" +
- zpad$1(now.getUTCHours(), 2) + "-" +
- zpad$1(now.getUTCMinutes(), 2) + "-" +
- zpad$1(now.getUTCSeconds(), 2) + ".0Z");
- const gethFilename = ("UTC--" + timestamp + "--" + data.address);
- data["x-ethers"] = {
- client, gethFilename, path, locale,
- mnemonicCounter: hexlify(mnemonicIv).substring(2),
- mnemonicCiphertext: hexlify(mnemonicCiphertext).substring(2),
- version: "0.1"
- };
- }
- return JSON.stringify(data);
- }
- /**
- * Return the JSON Keystore Wallet for %%account%% encrypted with
- * %%password%%.
- *
- * The %%options%% can be used to tune the password-based key
- * derivation function parameters, explicitly set the random values
- * used. Any provided [[ProgressCallback]] is ignord.
- */
- function encryptKeystoreJsonSync(account, password, options) {
- if (options == null) {
- options = {};
- }
- const passwordBytes = getPassword(password);
- const kdf = getEncryptKdfParams(options);
- const key = scryptSync(passwordBytes, kdf.salt, kdf.N, kdf.r, kdf.p, 64);
- return _encryptKeystore(getBytes(key), kdf, account, options);
- }
- /**
- * Resolved to the JSON Keystore Wallet for %%account%% encrypted
- * with %%password%%.
- *
- * The %%options%% can be used to tune the password-based key
- * derivation function parameters, explicitly set the random values
- * used and provide a [[ProgressCallback]] to receive periodic updates
- * on the completion status..
- */
- async function encryptKeystoreJson(account, password, options) {
- if (options == null) {
- options = {};
- }
- const passwordBytes = getPassword(password);
- const kdf = getEncryptKdfParams(options);
- const key = await scrypt(passwordBytes, kdf.salt, kdf.N, kdf.r, kdf.p, 64, options.progressCallback);
- return _encryptKeystore(getBytes(key), kdf, account, options);
- }
- /**
- * Explain HD Wallets..
- *
- * @_subsection: api/wallet:HD Wallets [hd-wallets]
- */
- /**
- * The default derivation path for Ethereum HD Nodes. (i.e. ``"m/44'/60'/0'/0/0"``)
- */
- const defaultPath = "m/44'/60'/0'/0/0";
- // "Bitcoin seed"
- const MasterSecret = new Uint8Array([66, 105, 116, 99, 111, 105, 110, 32, 115, 101, 101, 100]);
- const HardenedBit = 0x80000000;
- const N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
- const Nibbles = "0123456789abcdef";
- function zpad(value, length) {
- let result = "";
- while (value) {
- result = Nibbles[value % 16] + result;
- value = Math.trunc(value / 16);
- }
- while (result.length < length * 2) {
- result = "0" + result;
- }
- return "0x" + result;
- }
- function encodeBase58Check(_value) {
- const value = getBytes(_value);
- const check = dataSlice(sha256(sha256(value)), 0, 4);
- const bytes = concat([value, check]);
- return encodeBase58(bytes);
- }
- const _guard = {};
- function ser_I(index, chainCode, publicKey, privateKey) {
- const data = new Uint8Array(37);
- if (index & HardenedBit) {
- assert(privateKey != null, "cannot derive child of neutered node", "UNSUPPORTED_OPERATION", {
- operation: "deriveChild"
- });
- // Data = 0x00 || ser_256(k_par)
- data.set(getBytes(privateKey), 1);
- }
- else {
- // Data = ser_p(point(k_par))
- data.set(getBytes(publicKey));
- }
- // Data += ser_32(i)
- for (let i = 24; i >= 0; i -= 8) {
- data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff);
- }
- const I = getBytes(computeHmac("sha512", chainCode, data));
- return { IL: I.slice(0, 32), IR: I.slice(32) };
- }
- function derivePath(node, path) {
- const components = path.split("/");
- assertArgument(components.length > 0, "invalid path", "path", path);
- if (components[0] === "m") {
- assertArgument(node.depth === 0, `cannot derive root path (i.e. path starting with "m/") for a node at non-zero depth ${node.depth}`, "path", path);
- components.shift();
- }
- let result = node;
- for (let i = 0; i < components.length; i++) {
- const component = components[i];
- if (component.match(/^[0-9]+'$/)) {
- const index = parseInt(component.substring(0, component.length - 1));
- assertArgument(index < HardenedBit, "invalid path index", `path[${i}]`, component);
- result = result.deriveChild(HardenedBit + index);
- }
- else if (component.match(/^[0-9]+$/)) {
- const index = parseInt(component);
- assertArgument(index < HardenedBit, "invalid path index", `path[${i}]`, component);
- result = result.deriveChild(index);
- }
- else {
- assertArgument(false, "invalid path component", `path[${i}]`, component);
- }
- }
- return result;
- }
- /**
- * An **HDNodeWallet** is a [[Signer]] backed by the private key derived
- * from an HD Node using the [[link-bip-32]] stantard.
- *
- * An HD Node forms a hierarchal structure with each HD Node having a
- * private key and the ability to derive child HD Nodes, defined by
- * a path indicating the index of each child.
- */
- class HDNodeWallet extends BaseWallet {
- /**
- * The compressed public key.
- */
- publicKey;
- /**
- * The fingerprint.
- *
- * A fingerprint allows quick qay to detect parent and child nodes,
- * but developers should be prepared to deal with collisions as it
- * is only 4 bytes.
- */
- fingerprint;
- /**
- * The parent fingerprint.
- */
- parentFingerprint;
- /**
- * The mnemonic used to create this HD Node, if available.
- *
- * Sources such as extended keys do not encode the mnemonic, in
- * which case this will be ``null``.
- */
- mnemonic;
- /**
- * The chaincode, which is effectively a public key used
- * to derive children.
- */
- chainCode;
- /**
- * The derivation path of this wallet.
- *
- * Since extended keys do not provide full path details, this
- * may be ``null``, if instantiated from a source that does not
- * encode it.
- */
- path;
- /**
- * The child index of this wallet. Values over ``2 *\* 31`` indicate
- * the node is hardened.
- */
- index;
- /**
- * The depth of this wallet, which is the number of components
- * in its path.
- */
- depth;
- /**
- * @private
- */
- constructor(guard, signingKey, parentFingerprint, chainCode, path, index, depth, mnemonic, provider) {
- super(signingKey, provider);
- assertPrivate(guard, _guard, "HDNodeWallet");
- defineProperties(this, { publicKey: signingKey.compressedPublicKey });
- const fingerprint = dataSlice(ripemd160(sha256(this.publicKey)), 0, 4);
- defineProperties(this, {
- parentFingerprint, fingerprint,
- chainCode, path, index, depth
- });
- defineProperties(this, { mnemonic });
- }
- connect(provider) {
- return new HDNodeWallet(_guard, this.signingKey, this.parentFingerprint, this.chainCode, this.path, this.index, this.depth, this.mnemonic, provider);
- }
- #account() {
- const account = { address: this.address, privateKey: this.privateKey };
- const m = this.mnemonic;
- if (this.path && m && m.wordlist.locale === "en" && m.password === "") {
- account.mnemonic = {
- path: this.path,
- locale: "en",
- entropy: m.entropy
- };
- }
- return account;
- }
- /**
- * Resolves to a [JSON Keystore Wallet](json-wallets) encrypted with
- * %%password%%.
- *
- * If %%progressCallback%% is specified, it will receive periodic
- * updates as the encryption process progreses.
- */
- async encrypt(password, progressCallback) {
- return await encryptKeystoreJson(this.#account(), password, { progressCallback });
- }
- /**
- * Returns a [JSON Keystore Wallet](json-wallets) encryped with
- * %%password%%.
- *
- * It is preferred to use the [async version](encrypt) instead,
- * which allows a [[ProgressCallback]] to keep the user informed.
- *
- * This method will block the event loop (freezing all UI) until
- * it is complete, which may be a non-trivial duration.
- */
- encryptSync(password) {
- return encryptKeystoreJsonSync(this.#account(), password);
- }
- /**
- * The extended key.
- *
- * This key will begin with the prefix ``xpriv`` and can be used to
- * reconstruct this HD Node to derive its children.
- */
- get extendedKey() {
- // We only support the mainnet values for now, but if anyone needs
- // testnet values, let me know. I believe current sentiment is that
- // we should always use mainnet, and use BIP-44 to derive the network
- // - Mainnet: public=0x0488B21E, private=0x0488ADE4
- // - Testnet: public=0x043587CF, private=0x04358394
- assert(this.depth < 256, "Depth too deep", "UNSUPPORTED_OPERATION", { operation: "extendedKey" });
- return encodeBase58Check(concat([
- "0x0488ADE4", zpad(this.depth, 1), this.parentFingerprint,
- zpad(this.index, 4), this.chainCode,
- concat(["0x00", this.privateKey])
- ]));
- }
- /**
- * Returns true if this wallet has a path, providing a Type Guard
- * that the path is non-null.
- */
- hasPath() { return (this.path != null); }
- /**
- * Returns a neutered HD Node, which removes the private details
- * of an HD Node.
- *
- * A neutered node has no private key, but can be used to derive
- * child addresses and other public data about the HD Node.
- */
- neuter() {
- return new HDNodeVoidWallet(_guard, this.address, this.publicKey, this.parentFingerprint, this.chainCode, this.path, this.index, this.depth, this.provider);
- }
- /**
- * Return the child for %%index%%.
- */
- deriveChild(_index) {
- const index = getNumber(_index, "index");
- assertArgument(index <= 0xffffffff, "invalid index", "index", index);
- // Base path
- let path = this.path;
- if (path) {
- path += "/" + (index & ~HardenedBit);
- if (index & HardenedBit) {
- path += "'";
- }
- }
- const { IR, IL } = ser_I(index, this.chainCode, this.publicKey, this.privateKey);
- const ki = new SigningKey(toBeHex((toBigInt(IL) + BigInt(this.privateKey)) % N, 32));
- return new HDNodeWallet(_guard, ki, this.fingerprint, hexlify(IR), path, index, this.depth + 1, this.mnemonic, this.provider);
- }
- /**
- * Return the HDNode for %%path%% from this node.
- */
- derivePath(path) {
- return derivePath(this, path);
- }
- static #fromSeed(_seed, mnemonic) {
- assertArgument(isBytesLike(_seed), "invalid seed", "seed", "[REDACTED]");
- const seed = getBytes(_seed, "seed");
- assertArgument(seed.length >= 16 && seed.length <= 64, "invalid seed", "seed", "[REDACTED]");
- const I = getBytes(computeHmac("sha512", MasterSecret, seed));
- const signingKey = new SigningKey(hexlify(I.slice(0, 32)));
- return new HDNodeWallet(_guard, signingKey, "0x00000000", hexlify(I.slice(32)), "m", 0, 0, mnemonic, null);
- }
- /**
- * Creates a new HD Node from %%extendedKey%%.
- *
- * If the %%extendedKey%% will either have a prefix or ``xpub`` or
- * ``xpriv``, returning a neutered HD Node ([[HDNodeVoidWallet]])
- * or full HD Node ([[HDNodeWallet) respectively.
- */
- static fromExtendedKey(extendedKey) {
- const bytes = toBeArray(decodeBase58(extendedKey)); // @TODO: redact
- assertArgument(bytes.length === 82 || encodeBase58Check(bytes.slice(0, 78)) === extendedKey, "invalid extended key", "extendedKey", "[ REDACTED ]");
- const depth = bytes[4];
- const parentFingerprint = hexlify(bytes.slice(5, 9));
- const index = parseInt(hexlify(bytes.slice(9, 13)).substring(2), 16);
- const chainCode = hexlify(bytes.slice(13, 45));
- const key = bytes.slice(45, 78);
- switch (hexlify(bytes.slice(0, 4))) {
- // Public Key
- case "0x0488b21e":
- case "0x043587cf": {
- const publicKey = hexlify(key);
- return new HDNodeVoidWallet(_guard, computeAddress(publicKey), publicKey, parentFingerprint, chainCode, null, index, depth, null);
- }
- // Private Key
- case "0x0488ade4":
- case "0x04358394 ":
- if (key[0] !== 0) {
- break;
- }
- return new HDNodeWallet(_guard, new SigningKey(key.slice(1)), parentFingerprint, chainCode, null, index, depth, null, null);
- }
- assertArgument(false, "invalid extended key prefix", "extendedKey", "[ REDACTED ]");
- }
- /**
- * Creates a new random HDNode.
- */
- static createRandom(password, path, wordlist) {
- if (password == null) {
- password = "";
- }
- if (path == null) {
- path = defaultPath;
- }
- if (wordlist == null) {
- wordlist = LangEn.wordlist();
- }
- const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist);
- return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
- }
- /**
- * Create an HD Node from %%mnemonic%%.
- */
- static fromMnemonic(mnemonic, path) {
- if (!path) {
- path = defaultPath;
- }
- return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
- }
- /**
- * Creates an HD Node from a mnemonic %%phrase%%.
- */
- static fromPhrase(phrase, password, path, wordlist) {
- if (password == null) {
- password = "";
- }
- if (path == null) {
- path = defaultPath;
- }
- if (wordlist == null) {
- wordlist = LangEn.wordlist();
- }
- const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist);
- return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
- }
- /**
- * Creates an HD Node from a %%seed%%.
- */
- static fromSeed(seed) {
- return HDNodeWallet.#fromSeed(seed, null);
- }
- }
- /**
- * A **HDNodeVoidWallet** cannot sign, but provides access to
- * the children nodes of a [[link-bip-32]] HD wallet addresses.
- *
- * The can be created by using an extended ``xpub`` key to
- * [[HDNodeWallet_fromExtendedKey]] or by
- * [nuetering](HDNodeWallet-neuter) a [[HDNodeWallet]].
- */
- class HDNodeVoidWallet extends VoidSigner {
- /**
- * The compressed public key.
- */
- publicKey;
- /**
- * The fingerprint.
- *
- * A fingerprint allows quick qay to detect parent and child nodes,
- * but developers should be prepared to deal with collisions as it
- * is only 4 bytes.
- */
- fingerprint;
- /**
- * The parent node fingerprint.
- */
- parentFingerprint;
- /**
- * The chaincode, which is effectively a public key used
- * to derive children.
- */
- chainCode;
- /**
- * The derivation path of this wallet.
- *
- * Since extended keys do not provider full path details, this
- * may be ``null``, if instantiated from a source that does not
- * enocde it.
- */
- path;
- /**
- * The child index of this wallet. Values over ``2 *\* 31`` indicate
- * the node is hardened.
- */
- index;
- /**
- * The depth of this wallet, which is the number of components
- * in its path.
- */
- depth;
- /**
- * @private
- */
- constructor(guard, address, publicKey, parentFingerprint, chainCode, path, index, depth, provider) {
- super(address, provider);
- assertPrivate(guard, _guard, "HDNodeVoidWallet");
- defineProperties(this, { publicKey });
- const fingerprint = dataSlice(ripemd160(sha256(publicKey)), 0, 4);
- defineProperties(this, {
- publicKey, fingerprint, parentFingerprint, chainCode, path, index, depth
- });
- }
- connect(provider) {
- return new HDNodeVoidWallet(_guard, this.address, this.publicKey, this.parentFingerprint, this.chainCode, this.path, this.index, this.depth, provider);
- }
- /**
- * The extended key.
- *
- * This key will begin with the prefix ``xpub`` and can be used to
- * reconstruct this neutered key to derive its children addresses.
- */
- get extendedKey() {
- // We only support the mainnet values for now, but if anyone needs
- // testnet values, let me know. I believe current sentiment is that
- // we should always use mainnet, and use BIP-44 to derive the network
- // - Mainnet: public=0x0488B21E, private=0x0488ADE4
- // - Testnet: public=0x043587CF, private=0x04358394
- assert(this.depth < 256, "Depth too deep", "UNSUPPORTED_OPERATION", { operation: "extendedKey" });
- return encodeBase58Check(concat([
- "0x0488B21E",
- zpad(this.depth, 1),
- this.parentFingerprint,
- zpad(this.index, 4),
- this.chainCode,
- this.publicKey,
- ]));
- }
- /**
- * Returns true if this wallet has a path, providing a Type Guard
- * that the path is non-null.
- */
- hasPath() { return (this.path != null); }
- /**
- * Return the child for %%index%%.
- */
- deriveChild(_index) {
- const index = getNumber(_index, "index");
- assertArgument(index <= 0xffffffff, "invalid index", "index", index);
- // Base path
- let path = this.path;
- if (path) {
- path += "/" + (index & ~HardenedBit);
- if (index & HardenedBit) {
- path += "'";
- }
- }
- const { IR, IL } = ser_I(index, this.chainCode, this.publicKey, null);
- const Ki = SigningKey.addPoints(IL, this.publicKey, true);
- const address = computeAddress(Ki);
- return new HDNodeVoidWallet(_guard, address, Ki, this.fingerprint, hexlify(IR), path, index, this.depth + 1, this.provider);
- }
- /**
- * Return the signer for %%path%% from this node.
- */
- derivePath(path) {
- return derivePath(this, path);
- }
- }
- /*
- export class HDNodeWalletManager {
- #root: HDNodeWallet;
- constructor(phrase: string, password?: null | string, path?: null | string, locale?: null | Wordlist) {
- if (password == null) { password = ""; }
- if (path == null) { path = "m/44'/60'/0'/0"; }
- if (locale == null) { locale = LangEn.wordlist(); }
- this.#root = HDNodeWallet.fromPhrase(phrase, password, path, locale);
- }
- getSigner(index?: number): HDNodeWallet {
- return this.#root.deriveChild((index == null) ? 0: index);
- }
- }
- */
- /**
- * Returns the [[link-bip-32]] path for the account at %%index%%.
- *
- * This is the pattern used by wallets like Ledger.
- *
- * There is also an [alternate pattern](getIndexedAccountPath) used by
- * some software.
- */
- function getAccountPath(_index) {
- const index = getNumber(_index, "index");
- assertArgument(index >= 0 && index < HardenedBit, "invalid account index", "index", index);
- return `m/44'/60'/${index}'/0/0`;
- }
- /**
- * Returns the path using an alternative pattern for deriving accounts,
- * at %%index%%.
- *
- * This derivation path uses the //index// component rather than the
- * //account// component to derive sequential accounts.
- *
- * This is the pattern used by wallets like MetaMask.
- */
- function getIndexedAccountPath(_index) {
- const index = getNumber(_index, "index");
- assertArgument(index >= 0 && index < HardenedBit, "invalid account index", "index", index);
- return `m/44'/60'/0'/0/${index}`;
- }
- /**
- * @_subsection: api/wallet:JSON Wallets [json-wallets]
- */
- /**
- * Returns true if %%json%% is a valid JSON Crowdsale wallet.
- */
- function isCrowdsaleJson(json) {
- try {
- const data = JSON.parse(json);
- if (data.encseed) {
- return true;
- }
- }
- catch (error) { }
- return false;
- }
- // See: https://github.com/ethereum/pyethsaletool
- /**
- * Before Ethereum launched, it was necessary to create a wallet
- * format for backers to use, which would be used to receive ether
- * as a reward for contributing to the project.
- *
- * The [[link-crowdsale]] format is now obsolete, but it is still
- * useful to support and the additional code is fairly trivial as
- * all the primitives required are used through core portions of
- * the library.
- */
- function decryptCrowdsaleJson(json, _password) {
- const data = JSON.parse(json);
- const password = getPassword(_password);
- // Ethereum Address
- const address = getAddress(spelunk(data, "ethaddr:string!"));
- // Encrypted Seed
- const encseed = looseArrayify(spelunk(data, "encseed:string!"));
- assertArgument(encseed && (encseed.length % 16) === 0, "invalid encseed", "json", json);
- const key = getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);
- const iv = encseed.slice(0, 16);
- const encryptedSeed = encseed.slice(16);
- // Decrypt the seed
- const aesCbc = new CBC(key, iv);
- const seed = pkcs7Strip(getBytes(aesCbc.decrypt(encryptedSeed)));
- // This wallet format is weird... Convert the binary encoded hex to a string.
- let seedHex = "";
- for (let i = 0; i < seed.length; i++) {
- seedHex += String.fromCharCode(seed[i]);
- }
- return { address, privateKey: id(seedHex) };
- }
- function stall(duration) {
- return new Promise((resolve) => { setTimeout(() => { resolve(); }, duration); });
- }
- /**
- * A **Wallet** manages a single private key which is used to sign
- * transactions, messages and other common payloads.
- *
- * This class is generally the main entry point for developers
- * that wish to use a private key directly, as it can create
- * instances from a large variety of common sources, including
- * raw private key, [[link-bip-39]] mnemonics and encrypte JSON
- * wallets.
- */
- class Wallet extends BaseWallet {
- /**
- * Create a new wallet for the private %%key%%, optionally connected
- * to %%provider%%.
- */
- constructor(key, provider) {
- if (typeof (key) === "string" && !key.startsWith("0x")) {
- key = "0x" + key;
- }
- let signingKey = (typeof (key) === "string") ? new SigningKey(key) : key;
- super(signingKey, provider);
- }
- connect(provider) {
- return new Wallet(this.signingKey, provider);
- }
- /**
- * Resolves to a [JSON Keystore Wallet](json-wallets) encrypted with
- * %%password%%.
- *
- * If %%progressCallback%% is specified, it will receive periodic
- * updates as the encryption process progreses.
- */
- async encrypt(password, progressCallback) {
- const account = { address: this.address, privateKey: this.privateKey };
- return await encryptKeystoreJson(account, password, { progressCallback });
- }
- /**
- * Returns a [JSON Keystore Wallet](json-wallets) encryped with
- * %%password%%.
- *
- * It is preferred to use the [async version](encrypt) instead,
- * which allows a [[ProgressCallback]] to keep the user informed.
- *
- * This method will block the event loop (freezing all UI) until
- * it is complete, which may be a non-trivial duration.
- */
- encryptSync(password) {
- const account = { address: this.address, privateKey: this.privateKey };
- return encryptKeystoreJsonSync(account, password);
- }
- static #fromAccount(account) {
- assertArgument(account, "invalid JSON wallet", "json", "[ REDACTED ]");
- if ("mnemonic" in account && account.mnemonic && account.mnemonic.locale === "en") {
- const mnemonic = Mnemonic.fromEntropy(account.mnemonic.entropy);
- const wallet = HDNodeWallet.fromMnemonic(mnemonic, account.mnemonic.path);
- if (wallet.address === account.address && wallet.privateKey === account.privateKey) {
- return wallet;
- }
- console.log("WARNING: JSON mismatch address/privateKey != mnemonic; fallback onto private key");
- }
- const wallet = new Wallet(account.privateKey);
- assertArgument(wallet.address === account.address, "address/privateKey mismatch", "json", "[ REDACTED ]");
- return wallet;
- }
- /**
- * Creates (asynchronously) a **Wallet** by decrypting the %%json%%
- * with %%password%%.
- *
- * If %%progress%% is provided, it is called periodically during
- * decryption so that any UI can be updated.
- */
- static async fromEncryptedJson(json, password, progress) {
- let account = null;
- if (isKeystoreJson(json)) {
- account = await decryptKeystoreJson(json, password, progress);
- }
- else if (isCrowdsaleJson(json)) {
- if (progress) {
- progress(0);
- await stall(0);
- }
- account = decryptCrowdsaleJson(json, password);
- if (progress) {
- progress(1);
- await stall(0);
- }
- }
- return Wallet.#fromAccount(account);
- }
- /**
- * Creates a **Wallet** by decrypting the %%json%% with %%password%%.
- *
- * The [[fromEncryptedJson]] method is preferred, as this method
- * will lock up and freeze the UI during decryption, which may take
- * some time.
- */
- static fromEncryptedJsonSync(json, password) {
- let account = null;
- if (isKeystoreJson(json)) {
- account = decryptKeystoreJsonSync(json, password);
- }
- else if (isCrowdsaleJson(json)) {
- account = decryptCrowdsaleJson(json, password);
- }
- else {
- assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
- }
- return Wallet.#fromAccount(account);
- }
- /**
- * Creates a new random [[HDNodeWallet]] using the available
- * [cryptographic random source](randomBytes).
- *
- * If there is no crytographic random source, this will throw.
- */
- static createRandom(provider) {
- const wallet = HDNodeWallet.createRandom();
- if (provider) {
- return wallet.connect(provider);
- }
- return wallet;
- }
- /**
- * Creates a [[HDNodeWallet]] for %%phrase%%.
- */
- static fromPhrase(phrase, provider) {
- const wallet = HDNodeWallet.fromPhrase(phrase);
- if (provider) {
- return wallet.connect(provider);
- }
- return wallet;
- }
- }
- const Base64 = ")!@#$%^&*(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
- /**
- * @_ignore
- */
- function decodeBits(width, data) {
- const maxValue = (1 << width) - 1;
- const result = [];
- let accum = 0, bits = 0, flood = 0;
- for (let i = 0; i < data.length; i++) {
- // Accumulate 6 bits of data
- accum = ((accum << 6) | Base64.indexOf(data[i]));
- bits += 6;
- // While we have enough for a word...
- while (bits >= width) {
- // ...read the word
- const value = (accum >> (bits - width));
- accum &= (1 << (bits - width)) - 1;
- bits -= width;
- // A value of 0 indicates we exceeded maxValue, it
- // floods over into the next value
- if (value === 0) {
- flood += maxValue;
- }
- else {
- result.push(value + flood);
- flood = 0;
- }
- }
- }
- return result;
- }
- /**
- * @_ignore
- */
- function decodeOwlA(data, accents) {
- let words = decodeOwl(data).join(",");
- // Inject the accents
- accents.split(/,/g).forEach((accent) => {
- const match = accent.match(/^([a-z]*)([0-9]+)([0-9])(.*)$/);
- assertArgument(match !== null, "internal error parsing accents", "accents", accents);
- let posOffset = 0;
- const positions = decodeBits(parseInt(match[3]), match[4]);
- const charCode = parseInt(match[2]);
- const regex = new RegExp(`([${match[1]}])`, "g");
- words = words.replace(regex, (all, letter) => {
- const rem = --positions[posOffset];
- if (rem === 0) {
- letter = String.fromCharCode(letter.charCodeAt(0), charCode);
- posOffset++;
- }
- return letter;
- });
- });
- return words.split(",");
- }
- /**
- * An OWL-A format Wordlist extends the OWL format to add an
- * overlay onto an OWL format Wordlist to support diacritic
- * marks.
- *
- * This class is generally not useful to most developers as
- * it is used mainly internally to keep Wordlists for languages
- * based on latin-1 small.
- *
- * If necessary, there are tools within the ``generation/`` folder
- * to create the necessary data.
- */
- class WordlistOwlA extends WordlistOwl {
- #accent;
- /**
- * Creates a new Wordlist for %%locale%% using the OWLA %%data%%
- * and %%accent%% data and validated against the %%checksum%%.
- */
- constructor(locale, data, accent, checksum) {
- super(locale, data, checksum);
- this.#accent = accent;
- }
- /**
- * The OWLA-encoded accent data.
- */
- get _accent() { return this.#accent; }
- /**
- * Decode all the words for the wordlist.
- */
- _decodeWords() {
- return decodeOwlA(this._data, this._accent);
- }
- }
- const wordlists = {
- en: LangEn.wordlist(),
- };
- /////////////////////////////
- //
- // dummy change; to pick-up ws security issue changes
- var ethers = /*#__PURE__*/Object.freeze({
- __proto__: null,
- AbiCoder: AbiCoder,
- AbstractProvider: AbstractProvider,
- AbstractSigner: AbstractSigner,
- AlchemyProvider: AlchemyProvider,
- AnkrProvider: AnkrProvider,
- BaseContract: BaseContract,
- BaseWallet: BaseWallet,
- Block: Block,
- BrowserProvider: BrowserProvider,
- ChainstackProvider: ChainstackProvider,
- CloudflareProvider: CloudflareProvider,
- ConstructorFragment: ConstructorFragment,
- Contract: Contract,
- ContractEventPayload: ContractEventPayload,
- ContractFactory: ContractFactory,
- ContractTransactionReceipt: ContractTransactionReceipt,
- ContractTransactionResponse: ContractTransactionResponse,
- ContractUnknownEventPayload: ContractUnknownEventPayload,
- EnsPlugin: EnsPlugin,
- EnsResolver: EnsResolver,
- ErrorDescription: ErrorDescription,
- ErrorFragment: ErrorFragment,
- EtherSymbol: EtherSymbol,
- EtherscanPlugin: EtherscanPlugin,
- EtherscanProvider: EtherscanProvider,
- EventFragment: EventFragment,
- EventLog: EventLog,
- EventPayload: EventPayload,
- FallbackFragment: FallbackFragment,
- FallbackProvider: FallbackProvider,
- FeeData: FeeData,
- FeeDataNetworkPlugin: FeeDataNetworkPlugin,
- FetchCancelSignal: FetchCancelSignal,
- FetchRequest: FetchRequest,
- FetchResponse: FetchResponse,
- FetchUrlFeeDataNetworkPlugin: FetchUrlFeeDataNetworkPlugin,
- FixedNumber: FixedNumber,
- Fragment: Fragment,
- FunctionFragment: FunctionFragment,
- GasCostPlugin: GasCostPlugin,
- HDNodeVoidWallet: HDNodeVoidWallet,
- HDNodeWallet: HDNodeWallet,
- Indexed: Indexed,
- InfuraProvider: InfuraProvider,
- InfuraWebSocketProvider: InfuraWebSocketProvider,
- Interface: Interface,
- IpcSocketProvider: IpcSocketProvider,
- JsonRpcApiProvider: JsonRpcApiProvider,
- JsonRpcProvider: JsonRpcProvider,
- JsonRpcSigner: JsonRpcSigner,
- LangEn: LangEn,
- Log: Log,
- LogDescription: LogDescription,
- MaxInt256: MaxInt256,
- MaxUint256: MaxUint256,
- MessagePrefix: MessagePrefix,
- MinInt256: MinInt256,
- Mnemonic: Mnemonic,
- MulticoinProviderPlugin: MulticoinProviderPlugin,
- N: N$1,
- NamedFragment: NamedFragment,
- Network: Network,
- NetworkPlugin: NetworkPlugin,
- NonceManager: NonceManager,
- ParamType: ParamType,
- PocketProvider: PocketProvider,
- QuickNodeProvider: QuickNodeProvider,
- Result: Result,
- Signature: Signature,
- SigningKey: SigningKey,
- SocketBlockSubscriber: SocketBlockSubscriber,
- SocketEventSubscriber: SocketEventSubscriber,
- SocketPendingSubscriber: SocketPendingSubscriber,
- SocketProvider: SocketProvider,
- SocketSubscriber: SocketSubscriber,
- StructFragment: StructFragment,
- Transaction: Transaction,
- TransactionDescription: TransactionDescription,
- TransactionReceipt: TransactionReceipt,
- TransactionResponse: TransactionResponse,
- Typed: Typed,
- TypedDataEncoder: TypedDataEncoder,
- UndecodedEventLog: UndecodedEventLog,
- UnmanagedSubscriber: UnmanagedSubscriber,
- Utf8ErrorFuncs: Utf8ErrorFuncs,
- VoidSigner: VoidSigner,
- Wallet: Wallet,
- WebSocketProvider: WebSocketProvider,
- WeiPerEther: WeiPerEther,
- Wordlist: Wordlist,
- WordlistOwl: WordlistOwl,
- WordlistOwlA: WordlistOwlA,
- ZeroAddress: ZeroAddress,
- ZeroHash: ZeroHash,
- accessListify: accessListify,
- assert: assert,
- assertArgument: assertArgument,
- assertArgumentCount: assertArgumentCount,
- assertNormalize: assertNormalize,
- assertPrivate: assertPrivate,
- checkResultErrors: checkResultErrors,
- computeAddress: computeAddress,
- computeHmac: computeHmac,
- concat: concat,
- copyRequest: copyRequest,
- dataLength: dataLength,
- dataSlice: dataSlice,
- decodeBase58: decodeBase58,
- decodeBase64: decodeBase64,
- decodeBytes32String: decodeBytes32String,
- decodeRlp: decodeRlp,
- decryptCrowdsaleJson: decryptCrowdsaleJson,
- decryptKeystoreJson: decryptKeystoreJson,
- decryptKeystoreJsonSync: decryptKeystoreJsonSync,
- defaultPath: defaultPath,
- defineProperties: defineProperties,
- dnsEncode: dnsEncode,
- encodeBase58: encodeBase58,
- encodeBase64: encodeBase64,
- encodeBytes32String: encodeBytes32String,
- encodeRlp: encodeRlp,
- encryptKeystoreJson: encryptKeystoreJson,
- encryptKeystoreJsonSync: encryptKeystoreJsonSync,
- ensNormalize: ensNormalize,
- formatEther: formatEther,
- formatUnits: formatUnits,
- fromTwos: fromTwos,
- getAccountPath: getAccountPath,
- getAddress: getAddress,
- getBigInt: getBigInt,
- getBytes: getBytes,
- getBytesCopy: getBytesCopy,
- getCreate2Address: getCreate2Address,
- getCreateAddress: getCreateAddress,
- getDefaultProvider: getDefaultProvider,
- getIcapAddress: getIcapAddress,
- getIndexedAccountPath: getIndexedAccountPath,
- getNumber: getNumber,
- getUint: getUint,
- hashMessage: hashMessage,
- hexlify: hexlify,
- id: id,
- isAddress: isAddress,
- isAddressable: isAddressable,
- isBytesLike: isBytesLike,
- isCallException: isCallException,
- isCrowdsaleJson: isCrowdsaleJson,
- isError: isError,
- isHexString: isHexString,
- isKeystoreJson: isKeystoreJson,
- isValidName: isValidName,
- keccak256: keccak256,
- lock: lock,
- makeError: makeError,
- mask: mask,
- namehash: namehash,
- parseEther: parseEther,
- parseUnits: parseUnits$1,
- pbkdf2: pbkdf2,
- randomBytes: randomBytes,
- recoverAddress: recoverAddress,
- resolveAddress: resolveAddress,
- resolveProperties: resolveProperties,
- ripemd160: ripemd160,
- scrypt: scrypt,
- scryptSync: scryptSync,
- sha256: sha256,
- sha512: sha512,
- showThrottleMessage: showThrottleMessage,
- solidityPacked: solidityPacked,
- solidityPackedKeccak256: solidityPackedKeccak256,
- solidityPackedSha256: solidityPackedSha256,
- stripZerosLeft: stripZerosLeft,
- toBeArray: toBeArray,
- toBeHex: toBeHex,
- toBigInt: toBigInt,
- toNumber: toNumber,
- toQuantity: toQuantity,
- toTwos: toTwos,
- toUtf8Bytes: toUtf8Bytes,
- toUtf8CodePoints: toUtf8CodePoints,
- toUtf8String: toUtf8String,
- uuidV4: uuidV4,
- verifyMessage: verifyMessage,
- verifyTypedData: verifyTypedData,
- version: version,
- wordlists: wordlists,
- zeroPadBytes: zeroPadBytes,
- zeroPadValue: zeroPadValue
- });
- export { AbiCoder, AbstractProvider, AbstractSigner, AlchemyProvider, AnkrProvider, BaseContract, BaseWallet, Block, BrowserProvider, ChainstackProvider, CloudflareProvider, ConstructorFragment, Contract, ContractEventPayload, ContractFactory, ContractTransactionReceipt, ContractTransactionResponse, ContractUnknownEventPayload, EnsPlugin, EnsResolver, ErrorDescription, ErrorFragment, EtherSymbol, EtherscanPlugin, EtherscanProvider, EventFragment, EventLog, EventPayload, FallbackFragment, FallbackProvider, FeeData, FeeDataNetworkPlugin, FetchCancelSignal, FetchRequest, FetchResponse, FetchUrlFeeDataNetworkPlugin, FixedNumber, Fragment, FunctionFragment, GasCostPlugin, HDNodeVoidWallet, HDNodeWallet, Indexed, InfuraProvider, InfuraWebSocketProvider, Interface, IpcSocketProvider, JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner, LangEn, Log, LogDescription, MaxInt256, MaxUint256, MessagePrefix, MinInt256, Mnemonic, MulticoinProviderPlugin, N$1 as N, NamedFragment, Network, NetworkPlugin, NonceManager, ParamType, PocketProvider, QuickNodeProvider, Result, Signature, SigningKey, SocketBlockSubscriber, SocketEventSubscriber, SocketPendingSubscriber, SocketProvider, SocketSubscriber, StructFragment, Transaction, TransactionDescription, TransactionReceipt, TransactionResponse, Typed, TypedDataEncoder, UndecodedEventLog, UnmanagedSubscriber, Utf8ErrorFuncs, VoidSigner, Wallet, WebSocketProvider, WeiPerEther, Wordlist, WordlistOwl, WordlistOwlA, ZeroAddress, ZeroHash, accessListify, assert, assertArgument, assertArgumentCount, assertNormalize, assertPrivate, checkResultErrors, computeAddress, computeHmac, concat, copyRequest, dataLength, dataSlice, decodeBase58, decodeBase64, decodeBytes32String, decodeRlp, decryptCrowdsaleJson, decryptKeystoreJson, decryptKeystoreJsonSync, defaultPath, defineProperties, dnsEncode, encodeBase58, encodeBase64, encodeBytes32String, encodeRlp, encryptKeystoreJson, encryptKeystoreJsonSync, ensNormalize, ethers, formatEther, formatUnits, fromTwos, getAccountPath, getAddress, getBigInt, getBytes, getBytesCopy, getCreate2Address, getCreateAddress, getDefaultProvider, getIcapAddress, getIndexedAccountPath, getNumber, getUint, hashMessage, hexlify, id, isAddress, isAddressable, isBytesLike, isCallException, isCrowdsaleJson, isError, isHexString, isKeystoreJson, isValidName, keccak256, lock, makeError, mask, namehash, parseEther, parseUnits$1 as parseUnits, pbkdf2, randomBytes, recoverAddress, resolveAddress, resolveProperties, ripemd160, scrypt, scryptSync, sha256, sha512, showThrottleMessage, solidityPacked, solidityPackedKeccak256, solidityPackedSha256, stripZerosLeft, toBeArray, toBeHex, toBigInt, toNumber, toQuantity, toTwos, toUtf8Bytes, toUtf8CodePoints, toUtf8String, uuidV4, verifyMessage, verifyTypedData, version, wordlists, zeroPadBytes, zeroPadValue };
- //# sourceMappingURL=ethers.js.map
|