From 77718278230058c1bea86fa6a559bb3008200eee Mon Sep 17 00:00:00 2001 From: Lyka Labrada Date: Wed, 25 Oct 2023 17:13:10 +0800 Subject: [PATCH] feat(core): add evm feature (#4052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature(ui-ux): added dvm evm designs for onboarding (#3983) * added new image slide on the welcome screen * added condition to create wallet page * shortened import * update snapshot * added onboarding translations * added DE and FR translations * Update mobile-app/app/components/icons/WalletIcon.tsx Co-authored-by: Lyka Labrada * Update mobile-app/app/components/icons/WalletIcon.tsx Co-authored-by: Lyka Labrada * fixed logo cut off * updated snapshot * included contentFit contain * updated for consistency * Update shared/translations/languages/zh-Hant.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/zh-Hant.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/zh-Hant.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/zh-Hans.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/zh-Hans.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/zh-Hans.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/it.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/fr.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/it.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/fr.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/de.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/es.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/es.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * Update shared/translations/languages/de.json Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * updated ZHS and ZHT translations * Update mobile-app/app/screens/WalletNavigator/screens/CreateWallet/CreateWalletGuidelines.tsx Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * removed unnecessary return --------- Co-authored-by: Lyka Labrada Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * feature(ui-ux): dvm <> evm portfolio (#3979) * moved toggle_balance below * added mb for android * added DFI and EVM button * design changed; moved toggle balance back * added domain toggle skeleton * added domainProvider * added domain context to switch * added switch to portfolio navigator * added gradient border * conditionally display elements * some styling for EVM page * empty portfolio * empty evm portfolio * used common icon * updated the stylings * removed get DFI tag for EVM * changed to enum * updated to use ENUM instead * Update mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx Co-authored-by: Lyka Labrada * Update mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx Co-authored-by: Lyka Labrada * Update mobile-app/app/components/DomainSwitch.tsx Co-authored-by: Lyka Labrada * Update mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.tsx Co-authored-by: Lyka Labrada * Update mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx Co-authored-by: Lyka Labrada * reduced isEvmDomain conditions and css show/hide * moved condition outside of component * removed isEvmDomain for test.tsx * removed unnecessary isEvmDomain * Update mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx Co-authored-by: Lyka Labrada * fix(core): portfolio (evm-dvm) tests fix (#4006) * fix(core): portfolio tests fix * fix action button tests * rename to domain context * rename on mock * rename mock file --------- Co-authored-by: Lyka Labrada Co-authored-by: Pierre Gee Co-authored-by: Pierre Gee * feat(ui-ux): hide bottom nagivation when EMV network is selected (#4011) * feat(ui-ux): hide bottom nagivation when EMV network is selected * future proof condition * chore(ops): bump to add changi network * chore(ops): bump packages to display changi * feat(ui-ux): add evm faq screen (#4013) * feat(ui-ux): add evm faq screen * feat(ui-ux): update test snapshot * add metachain faq translations * add evm faq english translation for es and it --------- Co-authored-by: Pierre Gee * feat(core): Transfer Domain feature branch (WIP) (#4007) * feat(core): allow evm conversion * update value and text based on domain * feature(ui-ux): evm support for address book (#4008) * initial commit for address book * added backward compatibility * create and edit address update * added style for portfolio bottom sheet * fix linting * lint fix * added address type selector * making close icon size to 22 px consistant * added address type selector in AddressRow component * seperating instance of addressbook and walletaddresses * test fix * chore * backward compatibility for already saved address * bug fix * add search support for evm address * lint issue fix * added selectAllLabeledWalletAddress selector to show address label for evm address * removed unused filters and attributes * chore * added evm tag * chore fix * chore key error fix * added e2e tests * added translation * chore: fixed pr comments * translation * fix(ui-ux): fixed domain switch toggle (#4012) * fix(ui-ux): fixed domain switch toggle * added testcse * updated DFI to DVM * updated DFI to DVM in enum * updated dfi to dvm in useWalletAddress * toggle btn style fix * test case fix * feat(core): support transfer domain in convert screen (#4014) * feat(core): support transfer domain in convert screen * ensure utxo reserved fee when converting from utxo to dfi * consistent function init * explicit function return type * set state by following data change instead of triggering via event * consistent naming convention across convert screen and hooks * fix displayed text for token symbol * declare hooks before any function * handle disabled toggle button * fix displayed text on convert screen * update toast in text * fix transfer domain signer * fix lints * fix token detail screen navigation to convert * update unit texts * update drawer and prompts for dfi converter * Update more explicit token convert symbols * suffix with -evm for evm tokens * fix lint * fix hardcoded domain * fix(ui-ux): translations for convert screen (#4028) * fix(ui-ux): update copy text in convert screen * fix(ui-ux): update translations * add translations * translations * update de translations * add missing it translation object * fix conflict * chore(ops): bump packages to display changi (#4030) * chore(ops): bump to add changi network * chore(ops): bump packages to display changi * feat(ui-ux): add svg icons for sui and xchf tokens (#4031) * feat(ui-ux): add svg icons for sui and xchf tokens * fix invlalid svg props * update sui svg to a flatter one * fix rect prop --------- Co-authored-by: JJ Adonis * fix(ui-ux): updated walletkit package to filter out burn token pool pair (#4033) * fix(ui-ux): updated walletkit package to filter out burn token pool pair * fix(e2e): network details * chore(ops): bump walletkit (#4036) * fix(ui-ux): svg border for evm tokens (#4029) * fix(ui-ux): svg border for evm tokens * fix(ui-ux): conditional icon sizing with svg border on evm tokens * feature(ui-ux): enable transfer domain (#4032) * fix(ui-ux): filter out LP tokens in EVM domain * fix(ui-ux): UI labels for address types * fix(ui-ux): sendconfirmationscreen evm bg for addresses * fix(ui-ux): hide any address labels if there are error messages * remove unused comment * fix lint * fix(ui-ux): to display address label even with err msg * fix(ui-ux): labelled address * fix(ui-ux): cater for selected whitelisted evm addr * feat(e2e): add tests * fix: lint for AddressRow * feat: enable transfer domain * fix(ui-ux): update UI for convert confirmation screen * fix(e2e): network details * Revert "fix(e2e): network details" This reverts commit c29aef84836faef72a11278bdfd45724d05043fc. * fix(ui-ux): update isEVMDomain flag * fix(ui-ux): remove LP filter * fix(lint): add empty data for evmtx --------- Co-authored-by: Lyka Labrada * fix(ui-ux): fix selection of whitelisted address that redirects to edit address (#4040) * fix(ui-ux): fix selection of whitelisted address that redirects to edit address * chore(test): update snapshot * chore(ui-ux): resolved ui bug for address book screen (#4041) * fix(ui-ux): copy evm address when evm domain is toggled on (#4043) * feat(core): add evmtx signer on convert (#4038) * feat(core): add evmtx signer on convert * feat(core): fix evmxt 'to' address for dvm to evm transferdomain * feat(core): update transferdomain implementation for dst20 tokens * feat(core): update handle transferdomain tokenId for EVM tokens * update docker * update evmtx signature * update check for dfi token * add function to get dst20 token contract address * revert unnecessary changes on feautureflagcontext * update blockchain node to beta14 * feat(core): implement transfer domain with signed evmtx on Send * add README.md for the contractA abi * extraxt evmtx signer into a separate function * add todo * remove commented line * set nonce to 0 * feature(ui-ux): address book ui for transfer domain (#4042) * feature(ui-ux): address book UI for transfer domain * feature(ui-ux): address book bottom sheet in portfolio page * update comment * remove eslint-disable-next-line react-hooks/exhaustive-deps * feat(ui-ux): standardize evm tag UI across screens * feat(ui-ux): display address label * fix(ui-ux): remove caret if not from send screen * chore: update package * fix: lint for address row * fix(ui-ux): fix send nonce and vm address (#4045) --------- Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> Co-authored-by: Chloe <44501120+chloezxyy@users.noreply.github.com> Co-authored-by: Lyka Labrada Co-authored-by: JJ Adonis * fix(ui-ux): address book bottom sheet in portfolio page (#4046) * fix(ui-ux): address book bottom sheet in portfolio page * add check if editing current address label * feat(ui-ux): fetch evm balance for convert screen (#4009) * feat(core): allow evm conversion * update value and text based on domain * feat(ui-ux): fetch evm balance for convert screen * feat(ui-ux): rename ethTokenBalances to evmTokenBalances * remove 0x address * update eth rpc for testnet * feature(ui-ux): evm support for address book (#4008) * initial commit for address book * added backward compatibility * create and edit address update * added style for portfolio bottom sheet * fix linting * lint fix * added address type selector * making close icon size to 22 px consistant * added address type selector in AddressRow component * seperating instance of addressbook and walletaddresses * test fix * chore * backward compatibility for already saved address * bug fix * add search support for evm address * lint issue fix * added selectAllLabeledWalletAddress selector to show address label for evm address * removed unused filters and attributes * chore * added evm tag * chore fix * chore key error fix * added e2e tests * added translation * chore: fixed pr comments * translation * fix(ui-ux): fixed domain switch toggle (#4012) * fix(ui-ux): fixed domain switch toggle * added testcse * updated DFI to DVM * updated DFI to DVM in enum * updated dfi to dvm in useWalletAddress * toggle btn style fix * test case fix * replace token0 with CAS * feat(core): fetch eth coin balance * rename ethRpc to evmApi * add evm address details type * feat(core): add evmAddress inside WalletContext * feat(ui-ux): display evm address on portfolio when EVM domain is toggled * revert getEvmAddress * remove promise return type in walletcontext * feat(core): support transfer domain in convert screen (#4014) * feat(core): support transfer domain in convert screen * ensure utxo reserved fee when converting from utxo to dfi * consistent function init * explicit function return type * set state by following data change instead of triggering via event * consistent naming convention across convert screen and hooks * fix displayed text for token symbol * declare hooks before any function * handle disabled toggle button * fix displayed text on convert screen * update toast in text * fix transfer domain signer * fix lints * fix token detail screen navigation to convert * update unit texts * update drawer and prompts for dfi converter * Update more explicit token convert symbols * suffix with -evm for evm tokens * fix lint * fix hardcoded domain * update evm tokens on convert screen * fix(ui-ux): translations for convert screen (#4028) * fix(ui-ux): update copy text in convert screen * fix(ui-ux): update translations * add translations * translations * update de translations * add missing it translation object * fix conflict * chore(ops): bump packages to display changi (#4030) * chore(ops): bump to add changi network * chore(ops): bump packages to display changi * feat(ui-ux): add svg icons for sui and xchf tokens (#4031) * feat(ui-ux): add svg icons for sui and xchf tokens * fix invlalid svg props * update sui svg to a flatter one * fix rect prop --------- Co-authored-by: JJ Adonis * fix(ui-ux): updated walletkit package to filter out burn token pool pair (#4033) * fix(ui-ux): updated walletkit package to filter out burn token pool pair * fix(e2e): network details * chore(ops): bump walletkit (#4036) * fix(ui-ux): svg border for evm tokens (#4029) * fix(ui-ux): svg border for evm tokens * fix(ui-ux): conditional icon sizing with svg border on evm tokens * feature(ui-ux): enable transfer domain (#4032) * fix(ui-ux): filter out LP tokens in EVM domain * fix(ui-ux): UI labels for address types * fix(ui-ux): sendconfirmationscreen evm bg for addresses * fix(ui-ux): hide any address labels if there are error messages * remove unused comment * fix lint * fix(ui-ux): to display address label even with err msg * fix(ui-ux): labelled address * fix(ui-ux): cater for selected whitelisted evm addr * feat(e2e): add tests * fix: lint for AddressRow * feat: enable transfer domain * fix(ui-ux): update UI for convert confirmation screen * fix(e2e): network details * Revert "fix(e2e): network details" This reverts commit c29aef84836faef72a11278bdfd45724d05043fc. * fix(ui-ux): update isEVMDomain flag * fix(ui-ux): remove LP filter * fix(lint): add empty data for evmtx --------- Co-authored-by: Lyka Labrada * fix(ui-ux): fix selection of whitelisted address that redirects to edit address (#4040) * fix(ui-ux): fix selection of whitelisted address that redirects to edit address * chore(test): update snapshot * chore(ui-ux): resolved ui bug for address book screen (#4041) * update temporary blockscout api * feature(ui-ux): updated receive token screen to support evm address (#4025) Co-authored-by: Lyka Labrada * fix(ui-ux): copy evm address when evm domain is toggled on (#4043) * feat(core): add evmtx signer on convert (#4038) * feat(core): add evmtx signer on convert * feat(core): fix evmxt 'to' address for dvm to evm transferdomain * feat(core): update transferdomain implementation for dst20 tokens * feat(core): update handle transferdomain tokenId for EVM tokens * update docker * update evmtx signature * update check for dfi token * add function to get dst20 token contract address * revert unnecessary changes on feautureflagcontext * update blockchain node to beta14 * feat(core): implement transfer domain with signed evmtx on Send * add README.md for the contractA abi * extraxt evmtx signer into a separate function * add todo * remove commented line * set nonce to 0 * add default target evm token * feature(ui-ux): address book ui for transfer domain (#4042) * feature(ui-ux): address book UI for transfer domain * feature(ui-ux): address book bottom sheet in portfolio page * update comment * remove eslint-disable-next-line react-hooks/exhaustive-deps * feat(ui-ux): standardize evm tag UI across screens * feat(ui-ux): display address label * fix(ui-ux): remove caret if not from send screen * chore: update package * fix: lint for address row * feature(ui-ux): updated portfolio screen to support evm address (#4044) * chore * added logic for total portfolio value * updated defichain version * Update evmApi.ts * add default target evm token * chore --------- Co-authored-by: Lyka Labrada * fix missing evm target token for non-dfi tokens * transferdomain - get dynamic eth rpc url per network * fix(core): updated token selection screen (#4047) fix(core): updated tokenselectionscreen * fix(ui-ux): fix convert selection (#4048) Co-authored-by: Lyka Labrada * feat(ui-ux): move evm data inside redux store (#4049) * feat(ui-ux): move evm data inside redux store * perform batch dispatch * update deps array when fetching evm details --------- Co-authored-by: pierregee Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> Co-authored-by: Chloe <44501120+chloezxyy@users.noreply.github.com> Co-authored-by: JJ Adonis Co-authored-by: Harsh * feature(core): added rpc calls for playground to calculate evm balance (#4053) * feature(core): added rpc calls for playground to calculate evm balance * chore * fix(ui-ux): utxo-evm bug (#4051) * fix(ui-ux): utxo-evm bug * throw error on sending lp to evm address * feat(ui-ux): add hasFetchedEvmTokens flag in store for loader (#4054) * feat(ui-ux): add hasFetchedEvmTokens flag in store * add evm domain condition --------- Co-authored-by: Pierre Gee * fix(core): fix feature branch conflict to 'main' (#4055) * chore(ops): bump packages to display changi (#4030) * chore(ops): bump to add changi network * chore(ops): bump packages to display changi * feat(ui-ux): add svg icons for sui and xchf tokens (#4031) * feat(ui-ux): add svg icons for sui and xchf tokens * fix invlalid svg props * update sui svg to a flatter one * fix rect prop --------- Co-authored-by: JJ Adonis * fix(ui-ux): updated walletkit package to filter out burn token pool pair (#4033) * fix(ui-ux): updated walletkit package to filter out burn token pool pair * fix(e2e): network details * chore(ops): bump walletkit (#4036) --------- Co-authored-by: Pierre Gee Co-authored-by: JJ Adonis Co-authored-by: Chloe <44501120+chloezxyy@users.noreply.github.com> * chore(core): refactored transfer domain provider (#4058) * refactore transferdomain provider * fix(ui-ux): fixed icon for evm DFI on swap token listing * fix convert screen provider issue * added chainId in evm provider * added nonce in td request * Update mobile-app/app/screens/AppNavigator/screens/Dex/CompositeSwap/SwapTokenSelectionScreen.tsx Co-authored-by: Pierre Gee --------- Co-authored-by: Pierre Gee * fix(chore): updated evm tokenId and fixed DFI evm icon and balance (#4059) * refactore transferdomain provider * fix(ui-ux): fixed icon for evm DFI on swap token listing * fix convert screen provider issue * added chainId in evm provider * added nonce in td request * fix(chore): updated evm tokenId and fixed DFI evm icon and balance inconsistancy * updated dfi name * updated EVM suffix names * chore * removed (EVM) for DFI token * feat(e2e): address book transfer domain (#4057) * feat(e2e): address book transfer domain * fix(ui-ux): display updated wallet label on portfolio screen * feat(e2e): setup to send dfi to evm domain --------- Co-authored-by: Pierre Gee * feat(ui-ux): update transferdomain to pass only one vin (#4060) * feat(ui-ux): update transferdomain to pass only one vin * chore(deps): bump walletkit package * fix(chore): bug fix for transferdomain (#4063) * refactore transferdomain provider * fix(ui-ux): fixed icon for evm DFI on swap token listing * fix convert screen provider issue * added chainId in evm provider * added nonce in td request * fix(chore): updated evm tokenId and fixed DFI evm icon and balance inconsistancy * updated dfi name * updated EVM suffix names * chore * removed (EVM) for DFI token * Balance details screen for EVM token * fixed evm dif related bugs * feat(core): feature flag evm (#4056) * chore(ops): bump packages to display changi (#4030) * chore(ops): bump to add changi network * chore(ops): bump packages to display changi * feat(ui-ux): add svg icons for sui and xchf tokens (#4031) * feat(ui-ux): add svg icons for sui and xchf tokens * fix invlalid svg props * update sui svg to a flatter one * fix rect prop --------- Co-authored-by: JJ Adonis * fix(ui-ux): updated walletkit package to filter out burn token pool pair (#4033) * fix(ui-ux): updated walletkit package to filter out burn token pool pair * fix(e2e): network details * chore(ops): bump walletkit (#4036) * feat(core): feature flag evm * add feature flag * feat(core): hide evm in address book * fix maximum depth * disable sending to evm address * rm comment --------- Co-authored-by: Lyka Labrada Co-authored-by: JJ Adonis Co-authored-by: Chloe <44501120+chloezxyy@users.noreply.github.com> * fix(ui-ux): choose address by domain (#4065) fix(uiux): choose address by domain * chore(ui-ux): hide address type selection if evm disabled (#4064) Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * chore(deps): bump expo-image (#4039) * chore(deps): bump expo-image * chore(deps): bump expo-image@1.3.4 and related packages * fix conflict --------- Co-authored-by: pierregee * fix(chore): fixed ios/android loading issue (#4066) * fixed TextEncoder error * fixed loading issue * removed text-encoding * fixed wrong balance issue * fix 9 decimal points on transfer domain * fix package and mobile expo --------- Co-authored-by: pierregee * fix(ui-ux): display chevron if entrypoint is settings (#4067) * fix(ui-ux): fixed address title in address input screen (#4070) * fix(ui-ux): fixed address title in address input screen * fixed label issue * fixed minor issue related to evm icons * fix issue with evm tx --------- Co-authored-by: pierregee * feat(core): service provider - allow custom evm and eth rpc urls (#4068) * feat(ui-ux): update service provider description on settings * feat(core): update service provider storage api and add custom * feat(uii-ux): add custom url input for multiple providers * feat(ui-ux): disable evm urls when evmfeature is disabled * fix(core): fix custom provider context overriding value * feat(ui-ux): change custom provider type to enum * feat(core): keep 'SERVICE_PROVIDER_URL' key for dvm for backward compatibility * feat(core): update dvm key provider for backward compatibility * add ethRpcUrl to EVMProvider deps * fix provider storage not setting properly * update provider button from 'continue' to 'save changes' * hide evm and eth rpc urls when evmfeature flag is disabled * address pr comments --------- Co-authored-by: Pierre Gee * feat(ui-ux): update blockscout url (#4071) * fix(core): fixed hang issue on click of denomination currency (#4072) * feat(core): update testnet eth rpc url (#4073) * fix(ui-ux): fixed search unsaved address in addressbook screen (#4078) * fix(chore): fixed network icon issue on network change (#4076) fix(chore): fixed network icon issue on network change * fix(core): fix send dvm to dvm txn (#4075) * fix(core): fix send dvm to dvm txn * fix(core): update evm provider * fix lint issue * change lint error fix * fix(core): fix null data for evm wallet details (#4077) Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * feat(core): return default evm providers url when evm flag is disabled (#4074) * feat(core): reset custom evm and ethrpc urls when evm feature is disabled * chore(translations): add translations for updated service provider screen * add missing it and es translations * return default evm providers url when evm flag is disabled * remove unnecessary condition * remove unnecessary deps --------- Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * fix(ui-ux): fixed address book label overlap issue for evm address (#4079) * fix(core): fix unit test case (#4081) * fix(ui-ux): hide Get DFI btn on empty portfolio screen (#4080) * fix(core): fixed app crashing issue (#4083) * fix(core): handle auto-conversion of utxo to dfi token (#4082) * fix(core): handle auto-conversion of utxo to dfi token * update getinputtokentype if-condition * updated getInputTokenType condition for send token --------- Co-authored-by: Harsh * fix(core): fix invalid nonce error (#4087) * fix(ui-ux): fixed Send screen displays no assets displayed issue (#4088) * fix(ui-ux): fixed Send screen displays no assets displayed issue * updated token listing condition * fix(ui-ux): fixed token detail screen to hide loan data in evm domain (#4089) * fix(ui-ux): fixed Send screen displays no assets displayed issue * updated token listing condition * fixed token detail screen to hide load data in evm domain --------- Co-authored-by: Lyka Labrada * fix(ui-ux): hide swap btn for evm domain on token details screen (#4090) * chore(core): disallow http from custom service provider url (#4091) * fix(ui-ux): fix evm faq description (#4092) * fix(ui-ux): hide loan related data on portfolio card (#4093) * fix(core): fix decimal value turning into exponential notation string (#4094) fix(core): fix decimal turning into notation * fix(core): skip eth provider for transfer domain (#4095) * fix(core): skip eth provider for transfer domain * fix lint error * feat(ui-ux): remove duplicate `for EVM` text on token name (#4096) * Revert "fix(core): skip eth provider for transfer domain (#4095)" This reverts commit df92ccc8a9436dc4fea9b566dca6cea8c70eab4e. * fix(ui-ux): remove duplicate 'for EVM' * fix(core): set testnet eth rpc as default * feat(ui-ux): log error in evm provider (#4097) * feat(ui-ux): redirect token summary link to metascan for evm (#4098) * fix(ui-ux): display evm address as from on convert (#4099) * chore(logs): add info logs in evm provider (#4100) * chore(tests): fix e2e runner (#4069) * test * test * fix sendconfirmation and addresses tests * fix address e2e for TD * updated getInputTokenType condition for send token * fixed service provider e2e * fix service provider e2e * change delay back to 3000 * update test invalid url * chore * address spec fix * e2e fix * fix e2e * use changi rpc for remote pg * choer(tests): update snapshot --------- Co-authored-by: Lyka Labrada Co-authored-by: Harsh Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * feat(ui-ux): remove usememo in evm provider (#4101) * feat(core): update testnet eth rpc url (#4102) * feat(ui-ux): put back usememo in evm provider * feat(core): update testnet eth rpc url * chore(e2e): update td addresses test * chore(tests): test e2e runner (#4104) * chore(tests): add delay to service prrovider * chore(tests): update transferdomain addresses test * chore(tests): remove delay to service provider * chore(ops): update packages * chore(ops): temporarily hide addresss selection * fix(e2e): fixed address specs e2e (#4106) * fix(e2e): fixed address specs e2e * minor fix * fix(ui-ux): handle empty wallet address (#4107) Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> * fix(ui-ux): fixed Both error / valid messages are displayed when scan… (#4109) * fix(ui-ux): fixed Both error / valid messages are displayed when scanning address during send EVM to EVM * fix verified message for dvm address * minor fix --------- Co-authored-by: elocin Co-authored-by: Harsh R <53080940+fullstackninja864@users.noreply.github.com> Co-authored-by: Pierre Gee Co-authored-by: Pierre Gee Co-authored-by: chloe <44501120+chloezxyy@users.noreply.github.com> Co-authored-by: JJ Adonis Co-authored-by: Harsh --- .github/workflows/ci-e2e.yml | 2 +- babel.config.js | 1 + docker-compose.yml | 16 +- mobile-app/App.tsx | 41 +- mobile-app/app/api/index.ts | 1 + .../app/api/persistence/domain_storage.ts | 16 + .../app/api/transaction/dfi_converter.ts | 51 +- .../app/api/transaction/transfer_domain.ts | 325 ++ mobile-app/app/api/wallet/service_provider.ts | 30 +- mobile-app/app/components/AddressEvmTag.tsx | 27 + .../app/components/BottomSheetHeader.tsx | 2 +- .../components/BottomSheetTokenListHeader.tsx | 2 +- mobile-app/app/components/DomainSwitch.tsx | 93 + .../app/components/EVMLinearGradient.tsx | 28 + mobile-app/app/components/EvmTag.tsx | 31 + .../app/components/HeaderNetworkStatus.tsx | 7 +- .../app/components/HeaderTitle.test.tsx | 3 +- mobile-app/app/components/HeaderTitle.tsx | 11 +- mobile-app/app/components/InputHelperText.tsx | 4 +- mobile-app/app/components/SummaryTitle.tsx | 130 +- .../app/components/TokenDropdownButton.tsx | 19 +- .../app/components/WalletAddressRow.test.tsx | 7 +- .../app/components/WalletTextInputV2.tsx | 10 +- .../app/components/icons/WalletIcon.tsx | 22 + .../components/icons/assets/ConvertIcon.tsx | 18 + .../app/components/icons/assets/EvmDFI.tsx | 52 + .../app/components/icons/assets/index.ts | 5 +- .../app/contexts/CustomServiceProvider.tsx | 202 + mobile-app/app/contexts/DomainContext.tsx | 105 + mobile-app/app/contexts/EVMProvider.tsx | 65 + .../app/contexts/FeatureFlagContext.tsx | 8 +- .../__mocks__/CustomServiceProvider.tsx | 11 + .../app/contexts/__mocks__/DomainContext.tsx | 10 + .../app/contexts/__mocks__/EVMProvider.tsx | 6 + mobile-app/app/hooks/useAddressBook.ts | 6 +- mobile-app/app/hooks/useAddressLabel.ts | 5 +- mobile-app/app/hooks/useWalletAddress.ts | 20 +- mobile-app/app/hooks/wallet/Conversion.ts | 24 +- .../AppNavigator/BottomTabNavigator.tsx | 97 +- .../Auctions/screens/PlaceBidScreen.tsx | 39 +- .../Dex/CompositeSwap/CompositeSwapScreen.tsx | 103 +- .../SwapTokenSelectionScreen.tsx | 37 +- .../screens/Dex/DexAddLiquidity.tsx | 67 +- .../AppNavigator/screens/Dex/DexNavigator.tsx | 1 + .../PoolPairCards/PoolPairCards.tsx | 32 +- .../components/BottomSheetLoanTokensList.tsx | 23 +- .../screens/AddOrRemoveCollateralScreen.tsx | 82 +- .../Loans/screens/BorrowLoanTokenScreen.tsx | 81 +- .../Loans/screens/CreateVaultScreen.tsx | 41 +- .../Loans/screens/PaybackLoanScreen.tsx | 59 +- .../screens/Portfolio/PortfolioNavigator.tsx | 72 +- .../screens/Portfolio/PortfolioScreen.tsx | 211 +- .../assets/EmptyEvmPortfolioIcon.tsx | 89 + .../components/ActionButtons.test.tsx | 18 +- .../Portfolio/components/ActionButtons.tsx | 208 +- .../components/AddressListEditButton.test.tsx | 7 +- .../Portfolio/components/AddressRow.tsx | 311 +- .../AddressSelectionButton.test.tsx | 7 +- .../components/AddressSelectionButtonV2.tsx | 48 +- .../components/BottomSheetAddressBook.tsx | 263 - .../components/BottomSheetAddressDetail.tsx | 498 -- .../components/BottomSheetAddressDetailV2.tsx | 163 +- .../CreateOrEditAddressLabelForm.tsx | 277 +- .../components/DFIBalanceCard.test.tsx | 11 + .../Portfolio/components/DFIBalanceCard.tsx | 60 +- .../Portfolio/components/PortfolioCard.tsx | 59 +- .../components/TokenBreakdownDetailsV2.tsx | 27 +- .../Portfolio/components/TokenIcon.tsx | 17 +- .../components/TotalPortfolio.test.tsx | 1 + .../Portfolio/components/TotalPortfolio.tsx | 59 +- .../__snapshots__/ActionButtons.test.tsx.snap | 148 + .../Portfolio/hooks/EvmTokenBalances.ts | 130 + .../screens/Portfolio/hooks/TokenBalance.ts | 103 + .../screens/AddOrEditAddressBookScreen.tsx | 164 +- .../Portfolio/screens/AddressBookScreen.tsx | 577 +- .../screens/ConvertConfirmationScreen.tsx | 295 +- .../Portfolio/screens/ConvertScreen.tsx | 521 +- .../Portfolio/screens/EvmFeatureFaq.tsx | 97 + .../Portfolio/screens/OCG/CFPDetailScreen.tsx | 35 +- .../screens/OCG/DFIPDetailScreen.tsx | 17 +- .../Portfolio/screens/ReceiveScreen.test.tsx | 2 +- .../Portfolio/screens/ReceiveScreen.tsx | 23 +- .../screens/SendConfirmationScreen.tsx | 198 +- .../screens/Portfolio/screens/SendScreen.tsx | 107 +- .../Portfolio/screens/TokenDetailScreen.tsx | 179 +- .../screens/TokenSelectionScreen.tsx | 80 +- .../__snapshots__/ReceiveScreen.test.tsx.snap | 2 +- .../screens/Settings/SettingsNavigator.tsx | 31 +- .../screens/Settings/SettingsScreen.tsx | 34 +- .../Settings/components/CustomUrlInput.tsx | 140 + .../Settings/components/ResetButton.tsx | 91 +- .../screens/Settings/screens/AboutScreen.tsx | 10 +- .../Settings/screens/FeatureFlagScreen.tsx | 10 +- .../Settings/screens/KnowledgeBaseScreen.tsx | 8 +- .../screens/ServiceProviderScreen.tsx | 265 +- .../FeatureFlagScreen.test.tsx.snap | 2 +- .../KnowledgeBaseScreen.test.tsx.snap | 75 + .../NetworkSelectionScreen.test.tsx.snap | 95 +- .../PasscodePrompt.tsx | 10 +- .../CreateWallet/CreateWalletGuidelines.tsx | 50 +- .../CreateWalletGuidelines.test.tsx.snap | 151 + ...nboardingNetworkSelectScreen.test.tsx.snap | 95 +- .../screens/components/OnboardingCarousel.tsx | 10 + mobile-app/app/screens/enum.ts | 7 + mobile-app/app/styles.json | 84 + mobile-app/app/tailwind.config.js | 5 + .../transferDomain/addresses.spec.ts | 226 + .../dex/swap/swap_tabs_dropdowns.spec.ts | 19 +- .../wallet/portfolio/addresses.spec.ts | 103 +- .../wallet/portfolio/portfolio.spec.ts | 99 +- .../functional/wallet/portfolio/send.spec.ts | 296 +- .../wallet/portfolio/sendConfirmation.spec.ts | 8 +- .../wallet/settings/addressBook.spec.ts | 76 +- .../wallet/settings/serviceProvider.spec.ts | 50 +- package-lock.json | 4659 ++++++++++------- package.json | 111 +- .../onboarding/welcome-screen-e-dark.png | Bin 0 -> 13761 bytes .../onboarding/welcome-screen-e-light.png | Bin 0 -> 13305 bytes shared/contexts/DeFiScanContext.tsx | 31 +- shared/contexts/StatsProvider.tsx | 16 +- shared/contexts/WalletContext.tsx | 19 +- shared/contracts/DST20V1.json | 298 ++ shared/contracts/README.md | 19 + shared/contracts/TransferDomainV1.json | 181 + shared/store/evm.ts | 137 + shared/store/index.ts | 2 + shared/store/userPreferences.ts | 91 +- shared/translations/languages/de.json | 64 +- shared/translations/languages/es.json | 66 +- shared/translations/languages/fr.json | 66 +- shared/translations/languages/it.json | 66 +- shared/translations/languages/zh-Hans.json | 100 +- shared/translations/languages/zh-Hant.json | 94 +- tsconfig.json | 2 + 134 files changed, 10289 insertions(+), 4945 deletions(-) create mode 100644 mobile-app/app/api/persistence/domain_storage.ts create mode 100644 mobile-app/app/api/transaction/transfer_domain.ts create mode 100644 mobile-app/app/components/AddressEvmTag.tsx create mode 100644 mobile-app/app/components/DomainSwitch.tsx create mode 100644 mobile-app/app/components/EVMLinearGradient.tsx create mode 100644 mobile-app/app/components/EvmTag.tsx create mode 100644 mobile-app/app/components/icons/WalletIcon.tsx create mode 100644 mobile-app/app/components/icons/assets/ConvertIcon.tsx create mode 100644 mobile-app/app/components/icons/assets/EvmDFI.tsx create mode 100644 mobile-app/app/contexts/CustomServiceProvider.tsx create mode 100644 mobile-app/app/contexts/DomainContext.tsx create mode 100644 mobile-app/app/contexts/EVMProvider.tsx create mode 100644 mobile-app/app/contexts/__mocks__/CustomServiceProvider.tsx create mode 100644 mobile-app/app/contexts/__mocks__/DomainContext.tsx create mode 100644 mobile-app/app/contexts/__mocks__/EVMProvider.tsx create mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/assets/EmptyEvmPortfolioIcon.tsx delete mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressBook.tsx delete mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetail.tsx create mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts create mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts create mode 100644 mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/EvmFeatureFaq.tsx create mode 100644 mobile-app/app/screens/AppNavigator/screens/Settings/components/CustomUrlInput.tsx create mode 100644 mobile-app/cypress/e2e/functional/transferDomain/addresses.spec.ts create mode 100644 shared/assets/images/onboarding/welcome-screen-e-dark.png create mode 100644 shared/assets/images/onboarding/welcome-screen-e-light.png create mode 100644 shared/contracts/DST20V1.json create mode 100644 shared/contracts/README.md create mode 100644 shared/contracts/TransferDomainV1.json create mode 100644 shared/store/evm.ts diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index b126777135..611189a6ab 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -37,7 +37,7 @@ jobs: - run: .github/workflows/ci/wait-for http://localhost:3001/_actuator/probes/liveness -t 240 - run: .github/workflows/ci/wait-for http://localhost:3002/_actuator/probes/liveness -t 240 - - run: .github/workflows/ci/wait-for http://localhost:19551/ping -t 240 + - run: .github/workflows/ci/wait-for http://localhost:19550/ping -t 240 - uses: cypress-io/github-action@d79d2d530a66e641eb4a5f227e13bc985c60b964 # v4.2.2 with: diff --git a/babel.config.js b/babel.config.js index 318d3baf0a..08a024188d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -14,6 +14,7 @@ module.exports = function (api) { "@shared-api": "./shared/api", "@shared-contexts": "./shared/contexts", "@shared-types": "./shared/types", + "@shared-contracts": "./shared/contracts", "@screens": "./mobile-app/app/screens", "@store": "./shared/store", "@translations": "./shared/translations", diff --git a/docker-compose.yml b/docker-compose.yml index ed37f5d4f3..9264159771 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,17 +12,22 @@ services: ports: - "19553:80" - "19552:8080" - - "19551:8082" + - "19550:8082" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" defi-blockchain: - image: defi/defichain:master-91a01aea0 + image: defi/defichain:HEAD-420563c450 + ports: + - "19554:19554" + - "19551:19551" command: > defid -printtoconsole -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0 + -ethrpcbind=0.0.0.0 + -rpcallowcors=http://localhost:8081 -rpcuser=playground -rpcpassword=playground -rpcworkqueue=512 @@ -55,10 +60,11 @@ services: -grandcentralheight=16 -grandcentralepilogueheight=17 -nextnetworkupgradeheight=18 - -changiintermediateheight=19 + environment: + - RUST_LOG=debug defi-playground: - image: ghcr.io/birthdayresearch/playground-api:3.34.0 + image: ghcr.io/birthdayresearch/playground-api:4.0.0-rc.1.2 depends_on: - defi-blockchain ports: @@ -71,7 +77,7 @@ services: - "traefik.http.routers.playground.entrypoints=web" defi-whale: - image: ghcr.io/birthdayresearch/whale-api:3.34.0 + image: ghcr.io/birthdayresearch/whale-api:4.0.0-rc.1.2 depends_on: - defi-blockchain ports: diff --git a/mobile-app/App.tsx b/mobile-app/App.tsx index 78650c3473..b841265c61 100644 --- a/mobile-app/App.tsx +++ b/mobile-app/App.tsx @@ -4,6 +4,7 @@ import { SecuredStoreAPI, LanguagePersistence, ThemePersistence, + DomainPersistence, Logging, } from "@api"; import { AppStateContextProvider } from "@contexts/AppStateContext"; @@ -28,6 +29,7 @@ import { LanguageProvider, useLanguage, } from "@shared-contexts/LanguageProvider"; +import { DomainProvider } from "@contexts/DomainContext"; import * as Localization from "expo-localization"; import { useColorScheme } from "react-native"; import { WalletPersistence } from "@api/wallet"; @@ -45,6 +47,8 @@ import { WalletToast } from "@components/WalletToast"; import { ServiceProviderPersistence } from "@api/wallet/service_provider"; import { FavouritePoolpairProvider } from "@contexts/FavouritePoolpairContext"; import BigNumber from "bignumber.js"; +import { EVMProvider } from "@contexts/EVMProvider"; +import { CustomServiceProvider } from "@contexts/CustomServiceProvider"; /** * Loads @@ -110,19 +114,30 @@ export default function App(): JSX.Element | null { api={LanguagePersistence} locale={Localization.locale} > - - - - - -
- - - - - + + + + + + + + +
+ + + + + + + + diff --git a/mobile-app/app/api/index.ts b/mobile-app/app/api/index.ts index fb4624ce8c..cdd78d2d69 100644 --- a/mobile-app/app/api/index.ts +++ b/mobile-app/app/api/index.ts @@ -7,3 +7,4 @@ export { FeatureFlagPersistence } from "./persistence/feature_flag_storage"; export { SlippageTolerancePersistence } from "./persistence/slippage-tolerance_storage"; export { PortfolioCurrencyPersistence } from "./persistence/portfolio_currency_storage"; export { FavouritePoolpairsPersistence } from "./persistence/favourite_poolpairs_storage"; +export { DomainPersistence } from "./persistence/domain_storage"; diff --git a/mobile-app/app/api/persistence/domain_storage.ts b/mobile-app/app/api/persistence/domain_storage.ts new file mode 100644 index 0000000000..8d86b1f31e --- /dev/null +++ b/mobile-app/app/api/persistence/domain_storage.ts @@ -0,0 +1,16 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; + +const KEY = "WALLET.EVMDOMAIN"; + +async function set(domain: NonNullable): Promise { + await AsyncStorage.setItem(KEY, domain); +} + +async function get(): Promise { + return await AsyncStorage.getItem(KEY); +} + +export const DomainPersistence = { + set, + get, +}; diff --git a/mobile-app/app/api/transaction/dfi_converter.ts b/mobile-app/app/api/transaction/dfi_converter.ts index 759487524b..ab2b10648a 100644 --- a/mobile-app/app/api/transaction/dfi_converter.ts +++ b/mobile-app/app/api/transaction/dfi_converter.ts @@ -6,13 +6,12 @@ import { CTransactionSegWit, TransactionSegWit, } from "@defichain/jellyfish-transaction"; - -export type ConversionMode = "utxosToAccount" | "accountToUtxos"; +import { ConvertDirection } from "@screens/enum"; export async function dfiConversionSigner( account: WhaleWalletAccount, amount: BigNumber, - mode: ConversionMode + mode: ConvertDirection, ): Promise { const script = await account.getScript(); const builder = account.withTransactionBuilder(); @@ -32,7 +31,7 @@ export async function dfiConversionSigner( }, ], }, - script + script, ); } else { signed = await builder.account.accountToUtxos( @@ -46,7 +45,7 @@ export async function dfiConversionSigner( ], mintingOutputsStart: 2, // 0: DfTx, 1: change, 2: minted utxos (mandated by jellyfish-tx) }, - script + script, ); } return new CTransactionSegWit(signed); @@ -54,47 +53,55 @@ export async function dfiConversionSigner( export function dfiConversionCrafter( amount: BigNumber, - mode: ConversionMode, + convertDirection: ConvertDirection, onBroadcast: () => any, onConfirmation: () => void, - submitButtonLabel?: string + submitButtonLabel?: string, ): DfTxSigner { + if ( + ![ + ConvertDirection.accountToUtxos, + ConvertDirection.utxosToAccount, + ].includes(convertDirection) + ) { + throw new Error("Unexpected DFI conversion"); + } + const [symbolA, symbolB] = - mode === "utxosToAccount" - ? ["UTXO", translate("screens/OceanInterface", "tokens")] - : [translate("screens/OceanInterface", "tokens"), "UTXO"]; + convertDirection === ConvertDirection.utxosToAccount + ? ["UTXO", translate("screens/OceanInterface", "DFI")] + : [translate("screens/OceanInterface", "DFI"), "UTXO"]; return { sign: async (account: WhaleWalletAccount) => - await dfiConversionSigner(account, amount, mode), + await dfiConversionSigner(account, amount, convertDirection), title: translate( "screens/ConvertConfirmScreen", - "Convert {{amount}} DFI to {{target}}", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens", { amount: amount.toFixed(8), - target: - mode === "utxosToAccount" - ? translate("screens/ConvertScreen", "tokens") - : "UTXO", - } + symbolA, + symbolB, + }, ), drawerMessages: { preparing: translate("screens/OceanInterface", "Preparing to convert…"), waiting: translate( "screens/OceanInterface", - "Converting {{amount}} DFI {{symbolA}} to {{symbolB}}", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens", { symbolA: symbolA, symbolB: symbolB, amount: amount.toFixed(8), - } + }, ), complete: translate( "screens/OceanInterface", - "{{amount}} DFI converted to {{symbolB}}", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens", { - symbolB: symbolB, + symbolA, + symbolB, amount: amount.toFixed(8), - } + }, ), }, onBroadcast, diff --git a/mobile-app/app/api/transaction/transfer_domain.ts b/mobile-app/app/api/transaction/transfer_domain.ts new file mode 100644 index 0000000000..0eced51a21 --- /dev/null +++ b/mobile-app/app/api/transaction/transfer_domain.ts @@ -0,0 +1,325 @@ +import { translate } from "@translations"; +import BigNumber from "bignumber.js"; +import { ethers, providers, utils } from "ethers"; +import { DfTxSigner } from "@waveshq/walletkit-ui/dist/store"; +import { WhaleWalletAccount } from "@defichain/whale-api-wallet"; +import { + CTransactionSegWit, + TransferDomain, + Script, +} from "@defichain/jellyfish-transaction"; +import { Prevout } from "@defichain/jellyfish-transaction-builder"; +import { fromAddress, Eth } from "@defichain/jellyfish-address"; +import { NetworkName } from "@defichain/jellyfish-network"; +import { ConvertDirection } from "@screens/enum"; +import TransferDomainV1 from "@shared-contracts/TransferDomainV1.json"; + +export const TD_CONTRACT_ADDR = "0xdf00000000000000000000000000000000000001"; + +const TRANSFER_DOMAIN_TYPE = { + DVM: 2, + EVM: 3, +}; + +export interface TransferDomainToken { + tokenId: string; + displaySymbol: string; + displayTextSymbol: string; + balance: BigNumber; +} + +interface TransferDomainSigner { + account: WhaleWalletAccount; + sourceTokenId: string; + targetTokenId: string; + amount: BigNumber; + convertDirection: ConvertDirection; + dvmAddress: string; + evmAddress: string; + chainId?: number; + networkName: NetworkName; + nonce: number; +} + +export async function transferDomainSigner({ + account, + sourceTokenId, + targetTokenId, + amount, + convertDirection, + dvmAddress, + evmAddress, + chainId, + networkName, + nonce, +}: TransferDomainSigner): Promise { + const dvmScript = fromAddress(dvmAddress, networkName)?.script as Script; + const evmScript = Eth.fromAddress(evmAddress) as Script; + const builder = account.withTransactionBuilder(); + + const isEvmToDvm = convertDirection === ConvertDirection.evmToDvm; + + const [sourceScript, dstScript] = isEvmToDvm + ? [evmScript, dvmScript] + : [dvmScript, evmScript]; + + const [srcDomain, dstDomain] = isEvmToDvm + ? [TRANSFER_DOMAIN_TYPE.EVM, TRANSFER_DOMAIN_TYPE.DVM] + : [TRANSFER_DOMAIN_TYPE.DVM, TRANSFER_DOMAIN_TYPE.EVM]; + + const signedEvmTxData = await createSignedEvmTx({ + isEvmToDvm, + sourceTokenId: stripEvmSuffixFromTokenId(sourceTokenId).toString(), + targetTokenId: stripEvmSuffixFromTokenId(targetTokenId).toString(), + amount, + dvmAddress, + evmAddress, + accountEvmAddress: await account.getEvmAddress(), + privateKey: await account.privateKey(), + chainId, + nonce, + }); + + const transferDomain: TransferDomain = { + items: [ + { + src: { + address: sourceScript, + domain: srcDomain, + amount: { + token: stripEvmSuffixFromTokenId(sourceTokenId), + amount: amount, + }, + data: isEvmToDvm ? signedEvmTxData : new Uint8Array([]), + }, + dst: { + address: dstScript, + domain: dstDomain, + amount: { + token: stripEvmSuffixFromTokenId(targetTokenId), + amount: amount, + }, + data: isEvmToDvm ? new Uint8Array([]) : signedEvmTxData, + }, + }, + ], + }; + + const { utxos, walletOwnerDvmScript } = await getTransferDomainVin( + account, + networkName, + ); + + const signed = await builder.account.transferDomain( + transferDomain, + walletOwnerDvmScript, + utxos, + ); + return new CTransactionSegWit(signed); +} + +async function getTransferDomainVin( + account: WhaleWalletAccount, + networkName: NetworkName, +): Promise<{ utxos: Prevout[]; walletOwnerDvmScript: Script }> { + const walletOwnerDvmAddress = await account.getAddress(); + const walletOwnerDvmScript = fromAddress(walletOwnerDvmAddress, networkName) + ?.script as Script; + + const utxoList = await account.client.address.listTransactionUnspent( + walletOwnerDvmAddress, + ); + + const utxos: Prevout[] = []; + if (utxoList.length > 0) { + utxos.push({ + txid: utxoList[0].vout.txid, + vout: utxoList[0].vout.n, + value: new BigNumber(utxoList[0].vout.value), + script: walletOwnerDvmScript, + tokenId: utxoList[0].vout.tokenId ?? 0, + }); + } + + return { utxos, walletOwnerDvmScript }; +} + +export function transferDomainCrafter({ + amount, + convertDirection, + sourceToken, + targetToken, + networkName, + onBroadcast, + onConfirmation, + chainId, + submitButtonLabel, + dvmAddress, + evmAddress, + nonce, +}: { + amount: BigNumber; + convertDirection: ConvertDirection; + sourceToken: TransferDomainToken; + targetToken: TransferDomainToken; + networkName: NetworkName; + onBroadcast: () => any; + onConfirmation: () => void; + chainId?: number; + submitButtonLabel?: string; + dvmAddress: string; + evmAddress: string; + nonce: number; +}): DfTxSigner { + if ( + ![ConvertDirection.evmToDvm, ConvertDirection.dvmToEvm].includes( + convertDirection, + ) + ) { + throw new Error("Unexpected transfer domain"); + } + + const [symbolA, symbolB] = + convertDirection === ConvertDirection.dvmToEvm + ? [ + sourceToken.displayTextSymbol, + `${targetToken.displayTextSymbol} (EVM)`, + ] + : [ + `${targetToken.displayTextSymbol} (EVM)`, + sourceToken.displayTextSymbol, + ]; + + return { + sign: async (account: WhaleWalletAccount) => + await transferDomainSigner({ + account, + amount, + convertDirection, + networkName, + sourceTokenId: sourceToken.tokenId, + targetTokenId: targetToken.tokenId, + dvmAddress, + evmAddress, + chainId, + nonce, + }), + title: translate( + "screens/ConvertConfirmScreen", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens", + { + amount: amount.toFixed(8), + symbolA, + symbolB, + }, + ), + drawerMessages: { + preparing: translate("screens/OceanInterface", "Preparing to convert…"), + waiting: translate( + "screens/OceanInterface", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens", + { + symbolA: symbolA, + symbolB: symbolB, + amount: amount.toFixed(8), + }, + ), + complete: translate( + "screens/OceanInterface", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens", + { + symbolA: symbolA, + symbolB: symbolB, + amount: amount.toFixed(8), + }, + ), + }, + onBroadcast, + onConfirmation, + submitButtonLabel: + submitButtonLabel !== undefined + ? translate("screens/ConvertConfirmScreen", submitButtonLabel) + : undefined, + }; +} + +interface EvmTxSigner { + isEvmToDvm: boolean; + sourceTokenId: string; + targetTokenId: string; + amount: BigNumber; + dvmAddress: string; + evmAddress: string; + accountEvmAddress: string; + privateKey: Buffer; + chainId?: number; + nonce: number; +} + +async function createSignedEvmTx({ + isEvmToDvm, + sourceTokenId, + targetTokenId, + amount, + dvmAddress, + evmAddress, + privateKey, + chainId, + nonce, +}: EvmTxSigner): Promise { + let data; + const tdFace = new utils.Interface(TransferDomainV1.abi); + const from = isEvmToDvm ? evmAddress : TD_CONTRACT_ADDR; + const to = isEvmToDvm ? TD_CONTRACT_ADDR : evmAddress; + const parsedAmount = utils.parseUnits( + amount.decimalPlaces(8, BigNumber.ROUND_DOWN).toFixed(), + 18, + ); // TODO: Get decimals from token contract + const vmAddress = dvmAddress; + + if (sourceTokenId === "0" || targetTokenId === "0") { + /* For DFI, use `transfer` function */ + const transferDfi = [from, to, parsedAmount, vmAddress]; + data = tdFace.encodeFunctionData("transfer", transferDfi); + } else { + /* For DST20, use `transferDST20` function */ + const dst20TokenId = stripEvmSuffixFromTokenId(sourceTokenId); + const contractAddress = getAddressFromDST20TokenId(dst20TokenId); + const transferDST20 = [contractAddress, from, to, parsedAmount, vmAddress]; + data = tdFace.encodeFunctionData("transferDST20", transferDST20); + } + const wallet = new ethers.Wallet(privateKey); + + const tx: providers.TransactionRequest = { + to: TD_CONTRACT_ADDR, + nonce, + chainId, + data: data, + value: 0, + gasLimit: 0, + gasPrice: 0, + type: 0, + }; + const evmtxSigned = (await wallet.signTransaction(tx)).substring(2); // rm prefix `0x` + return new Uint8Array(Buffer.from(evmtxSigned, "hex") || []); +} + +export function stripEvmSuffixFromTokenId(tokenId: string) { + if (tokenId.includes("_evm")) { + return Number(tokenId.replace("_evm", "")); + } + return Number(tokenId); +} + +/** + * Get DST20 contract address + * https://github.com/DeFiCh/ain/blob/f5a671362f9899080d0a0dddbbcdcecb7c19d9e3/lib/ain-contracts/src/lib.rs#L79 + */ +export function getAddressFromDST20TokenId(tokenId: number | string): string { + const parsedTokenId = BigInt(tokenId); + const numberStr = parsedTokenId.toString(16); // Convert parsedTokenId to hexadecimal + const paddedNumberStr = numberStr.padStart(38, "0"); // Pad with zeroes to the left + const finalStr = `ff${paddedNumberStr}`; + const tokenContractAddess = utils.getAddress(finalStr); + return tokenContractAddess; +} diff --git a/mobile-app/app/api/wallet/service_provider.ts b/mobile-app/app/api/wallet/service_provider.ts index ea2d13362b..aecc8e9665 100644 --- a/mobile-app/app/api/wallet/service_provider.ts +++ b/mobile-app/app/api/wallet/service_provider.ts @@ -1,14 +1,34 @@ import { SecuredStoreAPI } from "@api"; +import { CustomServiceProviderType } from "@contexts/CustomServiceProvider"; const KEY = "WALLET.SERVICE_PROVIDER_URL"; -async function set(url: NonNullable): Promise { - await SecuredStoreAPI.setItem(KEY, url); +async function set( + url: NonNullable, + type: CustomServiceProviderType = CustomServiceProviderType.DVM, +): Promise { + await SecuredStoreAPI.setItem(`${KEY}.${type}`, url); } -async function get(): Promise { - const val = await SecuredStoreAPI.getItem(KEY); - return val != null ? val : undefined; +async function get( + type: CustomServiceProviderType = CustomServiceProviderType.DVM, +): Promise { + const PROVIDER_KEY = `${KEY}.${type}`; + const val = await SecuredStoreAPI.getItem(PROVIDER_KEY); + if (val !== null) { + return val; + } + + if (type === CustomServiceProviderType.DVM && val === null) { + const existingDvm = await SecuredStoreAPI.getItem(KEY); + if (existingDvm !== null) { + await SecuredStoreAPI.setItem(PROVIDER_KEY, existingDvm); + await SecuredStoreAPI.removeItem(KEY); + return existingDvm; + } + } + + return undefined; } /** diff --git a/mobile-app/app/components/AddressEvmTag.tsx b/mobile-app/app/components/AddressEvmTag.tsx new file mode 100644 index 0000000000..cc7a0af821 --- /dev/null +++ b/mobile-app/app/components/AddressEvmTag.tsx @@ -0,0 +1,27 @@ +import { tailwind } from "@tailwind"; +import { LinearGradient } from "expo-linear-gradient"; + +export function AddressEvmTag({ + children, + customStyle, + testID, +}: { + children: React.ReactElement; + customStyle?: string; + testID: string; +}): JSX.Element { + return ( + + {children} + + ); +} diff --git a/mobile-app/app/components/BottomSheetHeader.tsx b/mobile-app/app/components/BottomSheetHeader.tsx index f1f0dd78f4..970e413110 100644 --- a/mobile-app/app/components/BottomSheetHeader.tsx +++ b/mobile-app/app/components/BottomSheetHeader.tsx @@ -39,7 +39,7 @@ export function BottomSheetHeader({ light={tailwind("text-mono-light-v2-900")} iconType="Feather" name="x-circle" - size={24} + size={22} /> diff --git a/mobile-app/app/components/BottomSheetTokenListHeader.tsx b/mobile-app/app/components/BottomSheetTokenListHeader.tsx index 32e16b366a..7e41e9107d 100644 --- a/mobile-app/app/components/BottomSheetTokenListHeader.tsx +++ b/mobile-app/app/components/BottomSheetTokenListHeader.tsx @@ -25,7 +25,7 @@ export function BottomSheetTokenListHeader({ diff --git a/mobile-app/app/components/DomainSwitch.tsx b/mobile-app/app/components/DomainSwitch.tsx new file mode 100644 index 0000000000..1b14ba1553 --- /dev/null +++ b/mobile-app/app/components/DomainSwitch.tsx @@ -0,0 +1,93 @@ +import { View, Text } from "react-native"; +import { ThemedTouchableOpacityV2 } from "@components/themed"; +import { getNativeIcon } from "@components/icons/assets"; +import { useThemeContext } from "@waveshq/walletkit-ui"; +import React from "react"; +import { useDomainContext, DomainType } from "@contexts/DomainContext"; +import { tailwind } from "@tailwind"; +import { LinearGradient } from "expo-linear-gradient"; + +export function DomainSwitch({ testID }: { testID: string }): JSX.Element { + const { isLight } = useThemeContext(); + const { domain, setDomain } = useDomainContext(); + const DFIIcon = getNativeIcon("DFIlogo"); + const EvmDFIIcon = getNativeIcon("EvmDFI"); + + const toggleDomain = async () => { + await setDomain( + domain === DomainType.DVM ? DomainType.EVM : DomainType.DVM, + ); + }; + return ( + + {domain === DomainType.DVM && ( + + + + + + + + DVM + + + + )} + {domain === DomainType.EVM && ( + + + + + + + + + EVM + + + + + )} + + ); +} diff --git a/mobile-app/app/components/EVMLinearGradient.tsx b/mobile-app/app/components/EVMLinearGradient.tsx new file mode 100644 index 0000000000..c57b6455e6 --- /dev/null +++ b/mobile-app/app/components/EVMLinearGradient.tsx @@ -0,0 +1,28 @@ +import { tailwind } from "@tailwind"; +import { LinearGradient } from "expo-linear-gradient"; +import { ReactElement } from "react"; + +/* Only apply evm border color if it's an EVM Token */ +export function EVMLinearGradient({ + children, + isEvmToken, +}: { + children: ReactElement; + isEvmToken?: boolean; +}): JSX.Element | null { + if (isEvmToken) { + return ( + + {children} + + ); + } + + return children; +} diff --git a/mobile-app/app/components/EvmTag.tsx b/mobile-app/app/components/EvmTag.tsx new file mode 100644 index 0000000000..091ccfb555 --- /dev/null +++ b/mobile-app/app/components/EvmTag.tsx @@ -0,0 +1,31 @@ +import { tailwind } from "@tailwind"; +import { Text } from "@components/Text"; +import { LinearGradient } from "expo-linear-gradient"; + +export function EvmTag({ + text = "EVM", + index, + testIDSuffix, +}: { + text?: string; + index: number; + testIDSuffix: string; +}): JSX.Element { + return ( + + + {text} + + + ); +} diff --git a/mobile-app/app/components/HeaderNetworkStatus.tsx b/mobile-app/app/components/HeaderNetworkStatus.tsx index 2131397629..38fdd6dca4 100644 --- a/mobile-app/app/components/HeaderNetworkStatus.tsx +++ b/mobile-app/app/components/HeaderNetworkStatus.tsx @@ -13,6 +13,7 @@ import { ViewStyle, } from "react-native"; import { useSelector } from "react-redux"; +import { useCustomServiceProviderContext } from "@contexts/CustomServiceProvider"; import { NetworkIcon } from "./icons/assets/NetworkIcon"; import { ThemedTextV2 } from "./themed"; @@ -26,7 +27,9 @@ export function HeaderNetworkStatus({ containerStyle?: StyleProp; }): JSX.Element { const { network } = useNetworkContext(); - const { isCustomUrl } = useServiceProviderContext(); + const { isCustomUrl: isCustomDvmUrl } = useServiceProviderContext(); + const { isCustomEvmUrl, isCustomEthRpcUrl } = + useCustomServiceProviderContext(); const { connected } = useSelector((state: RootState) => state.block); return ( @@ -53,7 +56,7 @@ export function HeaderNetworkStatus({ > {network} - {isCustomUrl && ( + {(isCustomDvmUrl || isCustomEvmUrl || isCustomEthRpcUrl) && ( ({ useNavigation: jest.fn(), })); @@ -45,7 +46,7 @@ describe("Header title", () => { subHeadingType="NetworkSelect" onPress={jest.fn()} disabled={false} - /> + />, ); expect(rendered.toJSON()).toMatchSnapshot(); }); diff --git a/mobile-app/app/components/HeaderTitle.tsx b/mobile-app/app/components/HeaderTitle.tsx index 45509e3b77..020d96ab62 100644 --- a/mobile-app/app/components/HeaderTitle.tsx +++ b/mobile-app/app/components/HeaderTitle.tsx @@ -8,6 +8,7 @@ import { } from "@waveshq/walletkit-ui"; import { RootState } from "@store"; import { tailwind } from "@tailwind"; +import { useCustomServiceProviderContext } from "@contexts/CustomServiceProvider"; import { ThemedIcon, ThemedText } from "./themed"; type SubHeadingType = "Status" | "NetworkSelect"; @@ -43,7 +44,7 @@ export function HeaderTitle({ onPress={onPress ?? goToNetworkDetails} testID={containerTestID} style={tailwind( - `flex-col ${Platform.OS === "ios" ? "items-center" : ""}` + `flex-col ${Platform.OS === "ios" ? "items-center" : ""}`, )} > {text !== undefined && ( @@ -68,7 +69,9 @@ export function HeaderTitle({ export function ConnectionStatus(): JSX.Element { const { network } = useNetworkContext(); - const { isCustomUrl } = useServiceProviderContext(); + const { isCustomUrl: isCustomDvmUrl } = useServiceProviderContext(); + const { isCustomEvmUrl, isCustomEthRpcUrl } = + useCustomServiceProviderContext(); const connected = useSelector((state: RootState) => state.block.connected); return ( @@ -76,7 +79,7 @@ export function ConnectionStatus(): JSX.Element { style={tailwind( `h-2 w-2 rounded-full ${ connected ? "bg-green-500" : "bg-red-500" - } mr-1.5` + } mr-1.5`, )} testID="header_status_indicator" /> @@ -90,7 +93,7 @@ export function ConnectionStatus(): JSX.Element { {network} - {isCustomUrl && ( + {(isCustomDvmUrl || isCustomEvmUrl || isCustomEthRpcUrl) && ( - {`${props.label}`} + {props.label} - {`${props.label}`} + {props.label} 0 + ? props.toAddressLabel + : props.toAddress; return ( <> ) : ( - + + + )} @@ -82,7 +103,7 @@ export function SummaryTitle(props: ISummaryTitleProps): JSX.Element { dark={tailwind("bg-mono-dark-v2-200")} light={tailwind("bg-mono-light-v2-200")} style={tailwind( - "rounded-full pl-1 pr-2.5 py-1 flex flex-row items-center overflow-hidden ml-2" + "rounded-full pl-1 pr-2.5 py-1 flex flex-row items-center overflow-hidden ml-2", )} > @@ -116,39 +137,80 @@ export function SummaryTitle(props: ISummaryTitleProps): JSX.Element { > {props.customToAddressTitle ?? translate("screens/common", "To")} - - {props.addressType === AddressType.WalletAddress && ( - - - - )} - + <> + {props.addressType === AddressType.WalletAddress && ( + + + + )} + + {toAddressLabel} + + + + ) : ( + // Whitelisted address - DVM + - {props.toAddressLabel != null && props.toAddressLabel.length > 0 - ? props.toAddressLabel - : props.toAddress} - - + {props.addressType === AddressType.WalletAddress && ( + + + + )} + + {toAddressLabel} + + + )} )} diff --git a/mobile-app/app/components/TokenDropdownButton.tsx b/mobile-app/app/components/TokenDropdownButton.tsx index 9ffab19ee1..5fcba32749 100644 --- a/mobile-app/app/components/TokenDropdownButton.tsx +++ b/mobile-app/app/components/TokenDropdownButton.tsx @@ -6,6 +6,7 @@ import { import { getNativeIcon } from "@components/icons/assets"; import { tailwind } from "@tailwind"; import { translate } from "@translations"; +import { EVMLinearGradient } from "./EVMLinearGradient"; export enum TokenDropdownButtonStatus { Active, @@ -15,13 +16,20 @@ export enum TokenDropdownButtonStatus { } export function TokenDropdownButton(props: { + tokenId?: string; symbol?: string; + displayedTextSymbol?: string; testID: string; onPress?: () => void; status: TokenDropdownButtonStatus; + isEvmToken?: boolean; }): JSX.Element { const Icon = - props.symbol !== undefined ? getNativeIcon(props.symbol) : undefined; + props.symbol !== undefined + ? props.tokenId === "0_evm" + ? getNativeIcon("DFI (EVM)") + : getNativeIcon(props.symbol) + : undefined; return ( - + + + + - {props.symbol} + {props.displayedTextSymbol ?? props.symbol} )} @@ -72,7 +83,7 @@ export function TokenDropdownButton(props: { size={24} style={tailwind( { "ml-2.5": props.symbol === undefined }, - { "ml-3.5": props.symbol !== undefined } + { "ml-3.5": props.symbol !== undefined }, )} dark={tailwind("text-mono-dark-v2-700")} light={tailwind("text-mono-light-v2-700")} diff --git a/mobile-app/app/components/WalletAddressRow.test.tsx b/mobile-app/app/components/WalletAddressRow.test.tsx index d7d63e2c60..99bc6c4f0f 100644 --- a/mobile-app/app/components/WalletAddressRow.test.tsx +++ b/mobile-app/app/components/WalletAddressRow.test.tsx @@ -4,6 +4,7 @@ import { RootState } from "@store"; import { Provider } from "react-redux"; import { userPreferences } from "@store/userPreferences"; +import { DomainType } from "@contexts/DomainContext"; import { WalletAddressRow } from "./WalletAddressRow"; jest.mock("@shared-contexts/WalletContext"); @@ -15,15 +16,15 @@ describe("Wallet Address Row", () => { addresses: { foo: { address: "foo", + evmAddress: "", label: "foo", - isMine: true, }, }, addressBook: { bar: { address: "bar", label: "bar", - isMine: false, + addressDomainType: DomainType.DVM, }, }, }, @@ -36,7 +37,7 @@ describe("Wallet Address Row", () => { const rendered = render( - + , ); expect(rendered.toJSON()).toMatchSnapshot(); }); diff --git a/mobile-app/app/components/WalletTextInputV2.tsx b/mobile-app/app/components/WalletTextInputV2.tsx index 73817cc862..9758e0c3c2 100644 --- a/mobile-app/app/components/WalletTextInputV2.tsx +++ b/mobile-app/app/components/WalletTextInputV2.tsx @@ -180,7 +180,7 @@ export const WalletTextInputV2 = forwardRef( typeof inlineText?.text === "string" && ( ( ); - } + }, ); export function ClearButtonV2(props: { @@ -231,7 +231,7 @@ const TextInputDefault = forwardRef( return ( ); - } + }, ); const TextInputIOS = forwardRef( @@ -246,7 +246,7 @@ const TextInputIOS = forwardRef( onFocus(e); } }, - [shouldHandleKeyboardEvents] + [shouldHandleKeyboardEvents], ); const handleOnBlur = useCallback(() => { shouldHandleKeyboardEvents.value = true; @@ -265,5 +265,5 @@ const TextInputIOS = forwardRef( {...otherProps} /> ); - } + }, ); diff --git a/mobile-app/app/components/icons/WalletIcon.tsx b/mobile-app/app/components/icons/WalletIcon.tsx new file mode 100644 index 0000000000..f4fac1381b --- /dev/null +++ b/mobile-app/app/components/icons/WalletIcon.tsx @@ -0,0 +1,22 @@ +import Svg, { Path, Rect, SvgProps } from "react-native-svg"; + +export function WalletIcon(props: SvgProps): JSX.Element { + return ( + + + + + ); +} diff --git a/mobile-app/app/components/icons/assets/ConvertIcon.tsx b/mobile-app/app/components/icons/assets/ConvertIcon.tsx new file mode 100644 index 0000000000..04b30d5d27 --- /dev/null +++ b/mobile-app/app/components/icons/assets/ConvertIcon.tsx @@ -0,0 +1,18 @@ +import Svg, { Path, SvgProps } from "react-native-svg"; + +interface ConvertIconProps extends SvgProps { + iconSize?: number; +} + +export function ConvertIcon(props: ConvertIconProps): JSX.Element { + return ( + + + + ); +} diff --git a/mobile-app/app/components/icons/assets/EvmDFI.tsx b/mobile-app/app/components/icons/assets/EvmDFI.tsx new file mode 100644 index 0000000000..97bd2b76d5 --- /dev/null +++ b/mobile-app/app/components/icons/assets/EvmDFI.tsx @@ -0,0 +1,52 @@ +import Svg, { + ClipPath, + Defs, + G, + LinearGradient, + Path, + Rect, + Stop, + SvgProps, +} from "react-native-svg"; + +export function EvmDFI(props: SvgProps): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/mobile-app/app/components/icons/assets/index.ts b/mobile-app/app/components/icons/assets/index.ts index d95319e877..7429981566 100644 --- a/mobile-app/app/components/icons/assets/index.ts +++ b/mobile-app/app/components/icons/assets/index.ts @@ -21,11 +21,13 @@ import { dSOL } from "./dSOL"; import { dSUI } from "./dSUI"; import { XCHF } from "./XCHF"; import { dXCHF } from "./dXCHF"; +import { EvmDFI } from "./EvmDFI"; const mapping: Record JSX.Element> = { _UTXO: DFI, DFI: DFI, "DFI (UTXO)": DFI, + "DFI (EVM)": EvmDFI, "DFI (Token)": DFI, BTC: BTC, DOT: DOT, @@ -43,6 +45,7 @@ const mapping: Record JSX.Element> = { DUSD: dUSD, dEUROC: dEUROC, DFIlogo: DFIlogo, + EvmDFI: EvmDFI, dDOT: dDOT, dMATIC: dMATIC, dSOL: dSOL, @@ -56,7 +59,7 @@ const mapping: Record JSX.Element> = { * @return {(props: SvgProps) => JSX.Element} */ export function getNativeIcon( - symbol: string + symbol: string, ): (props: SvgProps) => JSX.Element { const Icon = mapping[symbol]; if (Icon === undefined) { diff --git a/mobile-app/app/contexts/CustomServiceProvider.tsx b/mobile-app/app/contexts/CustomServiceProvider.tsx new file mode 100644 index 0000000000..7be70b2dd9 --- /dev/null +++ b/mobile-app/app/contexts/CustomServiceProvider.tsx @@ -0,0 +1,202 @@ +import { EnvironmentNetwork } from "@waveshq/walletkit-core"; +import { useNetworkContext } from "@waveshq/walletkit-ui"; +import { BaseLogger } from "@waveshq/walletkit-ui/dist/contexts/logger"; +import React, { + createContext, + PropsWithChildren, + useContext, + useEffect, + useMemo, + useState, +} from "react"; +import { useDomainContext } from "./DomainContext"; + +export enum CustomServiceProviderType { + DVM = "DVM", + EVM = "EVM", + ETHRPC = "ETHRPC", +} + +interface CustomServiceProviderContextProps { + api: { + get: (type: CustomServiceProviderType) => Promise; + set: ( + url: NonNullable, + type?: CustomServiceProviderType, + ) => Promise; + }; + logger: BaseLogger; +} + +interface CustomServiceProviderURLProps + extends CustomServiceProviderContextProps { + network: EnvironmentNetwork; + defaultUrl: string; + type: CustomServiceProviderType; +} + +interface CustomServiceProviderLoader { + isUrlLoaded: boolean; + url: NonNullable; +} + +function useCustomServiceProviderUrl({ + api, + network, + logger, + defaultUrl, + type, +}: CustomServiceProviderURLProps): CustomServiceProviderLoader { + const [isUrlLoaded, setIsUrlLoaded] = useState(false); + const [url, setUrl] = useState>(defaultUrl); + + useEffect(() => { + api + .get(type) + .then((val) => { + setUrl(val !== undefined ? val : defaultUrl); + }) + .catch((err) => logger.error(err)) + .finally(() => setIsUrlLoaded(true)); + }, [url, network]); + + return { + isUrlLoaded, + url, + }; +} + +interface CustomServiceProviderContextI { + evmUrl: NonNullable; + ethRpcUrl: NonNullable; + isCustomEvmUrl: boolean; + isCustomEthRpcUrl: boolean; + defaultEvmUrl: string; + defaultEthRpcUrl: string; + setCustomUrl: ( + url: NonNullable, + type?: CustomServiceProviderType, + ) => Promise; +} + +const CustomServiceProviderContext = + createContext(undefined as any); + +export function useCustomServiceProviderContext(): CustomServiceProviderContextI { + return useContext(CustomServiceProviderContext); +} + +function getBlockscoutUrl(network: EnvironmentNetwork) { + // TODO: Add proper blockscout url for each network + switch (network) { + case EnvironmentNetwork.LocalPlayground: + case EnvironmentNetwork.RemotePlayground: + case EnvironmentNetwork.DevNet: + case EnvironmentNetwork.Changi: + return "https://blockscout.changi.ocean.jellyfishsdk.com"; + case EnvironmentNetwork.TestNet: + return "https://blockscout.testnet.ocean.jellyfishsdk.com"; + case EnvironmentNetwork.MainNet: + default: + return "https://blockscout.mainnet.ocean.jellyfishsdk.com"; + } +} + +function getEthRpcUrl(network: EnvironmentNetwork) { + // TODO: Add proper ethereum RPC URLs for each network + switch (network) { + case EnvironmentNetwork.LocalPlayground: + return "http://localhost:19551"; + case EnvironmentNetwork.RemotePlayground: + case EnvironmentNetwork.DevNet: + case EnvironmentNetwork.Changi: + return "http://34.34.156.49:20551"; // TODO: add final eth rpc url for changi, devnet and remote playground + case EnvironmentNetwork.MainNet: + return "https://changi.dfi.team"; // TODO: add final eth rpc url for mainnet, with proper domain name + case EnvironmentNetwork.TestNet: + default: + return "https://eth.testnet.ocean.jellyfishsdk.com"; + } +} + +export function CustomServiceProvider( + props: CustomServiceProviderContextProps & PropsWithChildren, +): JSX.Element | null { + const { api, children, logger } = props; + const { network } = useNetworkContext(); + const { isEvmFeatureEnabled } = useDomainContext(); + const params = { api, network, logger }; + + // EVM + const defaultEvmUrl = getBlockscoutUrl(network); + const { url: evmUrl } = useCustomServiceProviderUrl({ + ...params, + defaultUrl: defaultEvmUrl, + type: CustomServiceProviderType.EVM, + }); + + // ETH-RPC + const defaultEthRpcUrl = getEthRpcUrl(network); + const { url: ethRpcUrl } = useCustomServiceProviderUrl({ + ...params, + defaultUrl: defaultEthRpcUrl, + type: CustomServiceProviderType.ETHRPC, + }); + + const [currentUrl, setCurrentUrl] = useState<{ + [key in CustomServiceProviderType]: string; + }>({ + [CustomServiceProviderType.DVM]: "", // not used here, added only to satify `key` type + [CustomServiceProviderType.EVM]: evmUrl, + [CustomServiceProviderType.ETHRPC]: ethRpcUrl, + }); + + useEffect(() => { + const url = isEvmFeatureEnabled ? evmUrl : defaultEvmUrl; + setCurrentUrl((prevState) => ({ + ...prevState, + [CustomServiceProviderType.EVM]: url, + })); + }, [evmUrl, isEvmFeatureEnabled]); + + useEffect(() => { + const url = isEvmFeatureEnabled ? ethRpcUrl : defaultEthRpcUrl; + setCurrentUrl((prevState) => ({ + ...prevState, + [CustomServiceProviderType.ETHRPC]: url, + })); + }, [ethRpcUrl, isEvmFeatureEnabled]); + + const isCustomEvmUrl = useMemo( + () => currentUrl.EVM !== defaultEvmUrl, + [currentUrl.EVM, defaultEvmUrl], + ); + const isCustomEthRpcUrl = useMemo( + () => currentUrl.ETHRPC !== defaultEthRpcUrl, + [currentUrl.ETHRPC, defaultEthRpcUrl], + ); + + const setCustomUrl = async ( + newUrl: string, + type: CustomServiceProviderType = CustomServiceProviderType.DVM, + ): Promise => { + setCurrentUrl((prevState) => ({ ...prevState, [type]: newUrl })); + await api.set(newUrl, type); + }; + + const context: CustomServiceProviderContextI = { + evmUrl: currentUrl.EVM ?? defaultEvmUrl, + ethRpcUrl: currentUrl.ETHRPC ?? defaultEthRpcUrl, + isCustomEvmUrl, + isCustomEthRpcUrl, + defaultEvmUrl, + defaultEthRpcUrl, + setCustomUrl, + }; + + return ( + + {children} + + ); +} diff --git a/mobile-app/app/contexts/DomainContext.tsx b/mobile-app/app/contexts/DomainContext.tsx new file mode 100644 index 0000000000..b91f0d20b4 --- /dev/null +++ b/mobile-app/app/contexts/DomainContext.tsx @@ -0,0 +1,105 @@ +import React, { + createContext, + useContext, + useEffect, + useState, + PropsWithChildren, +} from "react"; +import { useLogger } from "@shared-contexts/NativeLoggingProvider"; +import { useFeatureFlagContext } from "./FeatureFlagContext"; + +interface DomainLoader { + isDomainLoaded: boolean; + domain: NonNullable; +} + +interface DomainContextI { + api: { + get: () => Promise; + set: (domain: NonNullable) => Promise; + }; +} + +export enum DomainType { + DVM = "DVM", + EVM = "EVM", +} + +export function useDomain({ api }: DomainContextI): DomainLoader { + const defaultDomain = DomainType.DVM; + const logger = useLogger(); + const [isDomainLoaded, setIsDomainLoaded] = useState(false); + const [domain, setDomain] = useState>(defaultDomain); + + useEffect(() => { + api + .get() + .then((l) => { + let currentDomain: NonNullable = defaultDomain; + if (l !== null && l !== undefined) { + currentDomain = l as DomainType; // TODO fix this hardcoded typing if possible + } + setDomain(currentDomain); + }) + .catch((err) => logger.error(err)) + .finally(() => setIsDomainLoaded(true)); + }, []); + + return { + isDomainLoaded, + domain, + }; +} + +interface Domain { + domain: NonNullable; + isEvmFeatureEnabled: boolean; + setDomain: (domain: NonNullable) => Promise; +} + +const DomainContext = createContext(undefined as any); + +export function useDomainContext(): Domain { + return useContext(DomainContext); +} + +export function DomainProvider( + props: DomainContextI & PropsWithChildren, +): JSX.Element | null { + const { isFeatureAvailable } = useFeatureFlagContext(); + const { api } = props; + const { domain } = useDomain({ api }); + const [currentDomain, setCurrentDomain] = + useState>(domain); + + useEffect(() => { + setCurrentDomain(domain); + }, [domain]); + + useEffect(() => { + switch (currentDomain) { + case "EVM": + setDomain(DomainType.EVM); + break; + default: + setDomain(DomainType.DVM); + } + }, [currentDomain]); + + const setDomain = async (domain: DomainType): Promise => { + setCurrentDomain(domain); + await api.set(domain); + }; + + const context: Domain = { + domain: isFeatureAvailable("evm") ? currentDomain : DomainType.DVM, + isEvmFeatureEnabled: isFeatureAvailable("evm"), + setDomain, + }; + + return ( + + {props.children} + + ); +} diff --git a/mobile-app/app/contexts/EVMProvider.tsx b/mobile-app/app/contexts/EVMProvider.tsx new file mode 100644 index 0000000000..8a90d54115 --- /dev/null +++ b/mobile-app/app/contexts/EVMProvider.tsx @@ -0,0 +1,65 @@ +import React, { + createContext, + useContext, + useEffect, + useMemo, + useState, +} from "react"; +import { providers } from "ethers"; +import { useNetworkContext } from "@waveshq/walletkit-ui"; +import { BaseLogger } from "@waveshq/walletkit-ui/dist/contexts/logger"; +import { useCustomServiceProviderContext } from "./CustomServiceProvider"; + +interface EVMProviderContextI { + provider: providers.JsonRpcProvider | null; + chainId?: number; +} +const EVMProviderContext = createContext(undefined as any); + +export function useEVMProvider(): EVMProviderContextI { + return useContext(EVMProviderContext); +} + +export function EVMProvider({ + children, + logger, +}: React.PropsWithChildren<{ logger: BaseLogger }>): JSX.Element | null { + const { ethRpcUrl } = useCustomServiceProviderContext(); + const { network } = useNetworkContext(); + const [chainId, setChainId] = useState(); + const [provider, setProvider] = useState( + null, + ); + + const getProvider = async () => { + try { + const provider = new providers.JsonRpcProvider(ethRpcUrl); + const { chainId } = await provider.getNetwork(); + setChainId(chainId); + setProvider(provider); + } catch (e) { + logger.error(e); + // Note: Added this for cases wherein eth rpc url is invalid or unreachable + setChainId(0); + setProvider(null); + } + }; + + useEffect(() => { + getProvider(); + }, [network, ethRpcUrl]); + + const client = useMemo( + () => ({ + provider, + chainId, + }), + [network, chainId, ethRpcUrl, provider], + ); + + return ( + + {children} + + ); +} diff --git a/mobile-app/app/contexts/FeatureFlagContext.tsx b/mobile-app/app/contexts/FeatureFlagContext.tsx index 4f2ef2595e..eb2b72f1a6 100644 --- a/mobile-app/app/contexts/FeatureFlagContext.tsx +++ b/mobile-app/app/contexts/FeatureFlagContext.tsx @@ -43,7 +43,7 @@ export function useFeatureFlagContext(): FeatureFlagContextI { } export function FeatureFlagProvider( - props: React.PropsWithChildren + props: React.PropsWithChildren, ): JSX.Element | null { const { network } = useNetworkContext(); const { url, isCustomUrl } = useServiceProviderContext(); @@ -80,7 +80,7 @@ export function FeatureFlagProvider( satisfies(appVersion, flag.version) && flag.networks?.includes(network) && flag.id === featureId && - flag.stage === "beta" + flag.stage === "beta", ); } @@ -118,7 +118,7 @@ export function FeatureFlagProvider( } const updateEnabledFeatures = async ( - flags: FeatureFlagID[] + flags: FeatureFlagID[], ): Promise => { setEnabledFeatures(flags); await FeatureFlagPersistence.set(flags); @@ -151,7 +151,7 @@ export function FeatureFlagProvider( satisfies(appVersion, flag.version) && flag.networks?.includes(network) && flag.platforms?.includes(Platform.OS) && - flag.stage === "beta" + flag.stage === "beta", ), }; diff --git a/mobile-app/app/contexts/__mocks__/CustomServiceProvider.tsx b/mobile-app/app/contexts/__mocks__/CustomServiceProvider.tsx new file mode 100644 index 0000000000..97d0492f83 --- /dev/null +++ b/mobile-app/app/contexts/__mocks__/CustomServiceProvider.tsx @@ -0,0 +1,11 @@ +export const useCustomServiceProviderContext = () => { + return { + evmUrl: "", + ethRpcUrl: "", + isCustomEvmUrl: false, + isCustomEthRpcUrl: false, + defaultEvmUrl: "", + defaultEthRpcUrl: "", + setCustomUrl: jest.fn(), + }; +}; diff --git a/mobile-app/app/contexts/__mocks__/DomainContext.tsx b/mobile-app/app/contexts/__mocks__/DomainContext.tsx new file mode 100644 index 0000000000..0a95faf8dd --- /dev/null +++ b/mobile-app/app/contexts/__mocks__/DomainContext.tsx @@ -0,0 +1,10 @@ +export enum DomainType { + DVM = "DVM", + EVM = "EVM", +} + +export const useDomainContext = () => { + return { + domain: "DVM", + }; +}; diff --git a/mobile-app/app/contexts/__mocks__/EVMProvider.tsx b/mobile-app/app/contexts/__mocks__/EVMProvider.tsx new file mode 100644 index 0000000000..7a6a8aab19 --- /dev/null +++ b/mobile-app/app/contexts/__mocks__/EVMProvider.tsx @@ -0,0 +1,6 @@ +export const useEVMProvider = () => { + return { + provider: null, + chainId: 1133, + }; +}; diff --git a/mobile-app/app/hooks/useAddressBook.ts b/mobile-app/app/hooks/useAddressBook.ts index 3e4ac59b2c..ef3b69470e 100644 --- a/mobile-app/app/hooks/useAddressBook.ts +++ b/mobile-app/app/hooks/useAddressBook.ts @@ -9,20 +9,22 @@ export function useAddressBook(): { } { const { network } = useNetworkContext(); const userPreferences = useSelector( - (state: RootState) => state.userPreferences + (state: RootState) => state.userPreferences, ); const dispatch = useAppDispatch(); const clearAddressBook = (): void => { const emptyAddressBook = {}; + // clear redux store dispatch(setAddressBook(emptyAddressBook)).then(() => { dispatch( + // clear persistance storage data setUserPreferences({ network, preferences: { ...userPreferences, addressBook: emptyAddressBook, }, - }) + }), ); }); }; diff --git a/mobile-app/app/hooks/useAddressLabel.ts b/mobile-app/app/hooks/useAddressLabel.ts index afcfaf664a..f86669c376 100644 --- a/mobile-app/app/hooks/useAddressLabel.ts +++ b/mobile-app/app/hooks/useAddressLabel.ts @@ -1,9 +1,10 @@ import { useSelector } from "react-redux"; import { RootState } from "@store"; +import { selectAllLabeledWalletAddress } from "@store/userPreferences"; export function useAddressLabel(address: string): string | null { - const addresses = useSelector( - (state: RootState) => state.userPreferences?.addresses + const addresses = useSelector((state: RootState) => + selectAllLabeledWalletAddress(state.userPreferences), ); let label = null; if (addresses?.[address] != null) { diff --git a/mobile-app/app/hooks/useWalletAddress.ts b/mobile-app/app/hooks/useWalletAddress.ts index 1fbccb3867..18bd7b9c7b 100644 --- a/mobile-app/app/hooks/useWalletAddress.ts +++ b/mobile-app/app/hooks/useWalletAddress.ts @@ -1,17 +1,27 @@ import { useWalletContext } from "@shared-contexts/WalletContext"; import { useCallback } from "react"; +export interface WalletAddressI { + dvm: string; + evm: string; + generatedLabel: string; +} + export function useWalletAddress(): { - fetchWalletAddresses: () => Promise; + fetchWalletAddresses: () => Promise; } { const { wallet, addressLength } = useWalletContext(); - const fetchWalletAddresses = useCallback(async (): Promise => { - const addresses: string[] = []; + const fetchWalletAddresses = useCallback(async (): Promise< + WalletAddressI[] + > => { + const addresses: WalletAddressI[] = []; for (let i = 0; i <= addressLength; i++) { const account = wallet.get(i); - const address = await account.getAddress(); - addresses.push(address); + const dvm = await account.getAddress(); + const evm = await account.getEvmAddress(); + const generatedLabel = `Address ${i + 1}`; + addresses.push({ dvm, evm, generatedLabel }); } return addresses; }, [wallet, addressLength]); diff --git a/mobile-app/app/hooks/wallet/Conversion.ts b/mobile-app/app/hooks/wallet/Conversion.ts index 42338f6721..d0da4047f9 100644 --- a/mobile-app/app/hooks/wallet/Conversion.ts +++ b/mobile-app/app/hooks/wallet/Conversion.ts @@ -8,11 +8,9 @@ import { unifiedDFISelector, transactionQueue, } from "@waveshq/walletkit-ui/dist/store"; -import { - ConversionMode, - dfiConversionCrafter, -} from "@api/transaction/dfi_converter"; +import { dfiConversionCrafter } from "@api/transaction/dfi_converter"; import { NativeLoggingProps } from "@shared-contexts/NativeLoggingProvider"; +import { ConvertDirection } from "@screens/enum"; interface useConversionProps { inputToken: InputToken; @@ -36,13 +34,13 @@ export function useConversion(props: useConversionProps): ConversionResult { const [isConversionRequired, setIsConversionRequired] = useState(false); const [conversionAmount, setConversionAmount] = useState(new BigNumber("0")); const DFIUnified = useSelector((state: RootState) => - unifiedDFISelector(state.wallet) + unifiedDFISelector(state.wallet), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const unifiedAmount = new BigNumber(DFIUnified.amount); const reservedDFI = 0.1; @@ -63,7 +61,7 @@ export function useConversion(props: useConversionProps): ConversionResult { setConversionAmount( amount .minus(type === "utxo" ? DFIUtxo.amount : DFIToken.amount) - .plus(type === "utxo" ? reservedDFI : 0) + .plus(type === "utxo" ? reservedDFI : 0), ); setIsConversionRequired(true); } else { @@ -78,11 +76,11 @@ export function useConversion(props: useConversionProps): ConversionResult { } export function queueConvertTransaction( - { mode, amount }: { mode: ConversionMode; amount: BigNumber }, + { mode, amount }: { mode: ConvertDirection; amount: BigNumber }, dispatch: Dispatch, onBroadcast: () => void, logger: NativeLoggingProps, - onConfirmation: () => void = () => {} + onConfirmation: () => void = () => {}, ): void { try { dispatch( @@ -92,9 +90,9 @@ export function queueConvertTransaction( mode, onBroadcast, onConfirmation, - "CONVERTING" - ) - ) + "CONVERTING", + ), + ), ); } catch (e) { logger.error(e); diff --git a/mobile-app/app/screens/AppNavigator/BottomTabNavigator.tsx b/mobile-app/app/screens/AppNavigator/BottomTabNavigator.tsx index e79ef958cb..f45ca3ab37 100644 --- a/mobile-app/app/screens/AppNavigator/BottomTabNavigator.tsx +++ b/mobile-app/app/screens/AppNavigator/BottomTabNavigator.tsx @@ -10,6 +10,7 @@ import { PortfolioIcon, } from "@screens/WalletNavigator/assets/BottomNavIcon"; import { useThemeContext } from "@waveshq/walletkit-ui"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { PortfolioNavigator } from "./screens/Portfolio/PortfolioNavigator"; import { DexNavigator } from "./screens/Dex/DexNavigator"; import { LoansNavigator } from "./screens/Loans/LoansNavigator"; @@ -41,6 +42,7 @@ const getTabBarLabel = ({ export function BottomTabNavigator(): JSX.Element { const { isLight } = useThemeContext(); + const { domain } = useDomainContext(); return ( <> @@ -54,7 +56,8 @@ export function BottomTabNavigator(): JSX.Element { "px-5 py-2 h-16 border-t", { "bg-mono-light-v2-00 border-mono-light-v2-100": isLight }, { "bg-mono-dark-v2-00 border-mono-dark-v2-100": !isLight }, - { "pt-1 pb-4 h-24": Platform.OS === "ios" } + { "pt-1 pb-4 h-24": Platform.OS === "ios" }, + { hidden: domain !== DomainType.DVM }, ), tabBarActiveTintColor: getColor("brand-v2-500"), tabBarInactiveTintColor: isLight @@ -80,50 +83,58 @@ export function BottomTabNavigator(): JSX.Element { }} /> - - getTabBarLabel({ - focused, - color, - title: translate("BottomTabNavigator", "DEX"), - }), - tabBarTestID: "bottom_tab_dex", - tabBarIcon: ({ color }) => , - }} - /> + {domain === DomainType.DVM && ( + <> + + getTabBarLabel({ + focused, + color, + title: translate("BottomTabNavigator", "DEX"), + }), + tabBarTestID: "bottom_tab_dex", + tabBarIcon: ({ color }) => , + }} + /> - - getTabBarLabel({ - focused, - color, - title: translate("BottomTabNavigator", "Loans"), - }), - tabBarTestID: "bottom_tab_loans", - tabBarIcon: ({ color }) => , - }} - /> + + getTabBarLabel({ + focused, + color, + title: translate("BottomTabNavigator", "Loans"), + }), + tabBarTestID: "bottom_tab_loans", + tabBarIcon: ({ color }) => ( + + ), + }} + /> - - getTabBarLabel({ - focused, - color, - title: translate("BottomTabNavigator", "Auctions"), - }), - tabBarTestID: "bottom_tab_auctions", - tabBarIcon: ({ color }) => , - }} - /> + + getTabBarLabel({ + focused, + color, + title: translate("BottomTabNavigator", "Auctions"), + }), + tabBarTestID: "bottom_tab_auctions", + tabBarIcon: ({ color }) => ( + + ), + }} + /> + + )} ); diff --git a/mobile-app/app/screens/AppNavigator/screens/Auctions/screens/PlaceBidScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Auctions/screens/PlaceBidScreen.tsx index 0b9155fbaf..e25e34bb01 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Auctions/screens/PlaceBidScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Auctions/screens/PlaceBidScreen.tsx @@ -47,13 +47,13 @@ type Props = StackScreenProps; export function PlaceBidScreen(props: Props): JSX.Element { const { batch, vault } = props.route.params; const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const ownedToken = tokens.find((token) => token.id === batch.loan.id); const { minNextBidInToken, totalCollateralsValueInUSD } = useAuctionBidValue( batch, - vault.liquidationPenalty + vault.liquidationPenalty, ); const [fee, setFee] = useState(new BigNumber(0.0001)); const { bottomSheetRef, containerRef, isModalDisplayed, bottomSheetScreen } = @@ -61,15 +61,15 @@ export function PlaceBidScreen(props: Props): JSX.Element { const navigation = useNavigation>(); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const blockCount = useSelector((state: RootState) => state.block.count) ?? 0; const { blocksRemaining } = useAuctionTime( vault.liquidationHeight, - blockCount + blockCount, ); const logger = useLogger(); const client = useWhaleApiClient(); @@ -100,7 +100,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { async function onBidPercentagePress( amount: BigNumber, - type: BidAmountButtonTypes + type: BidAmountButtonTypes, ): Promise { setValue("bidAmount", amount.toFixed(8)); await trigger("bidAmount"); @@ -117,7 +117,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { type: "wallet_toast", placement: "top", duration: TOAST_DURATION, - } + }, ); } @@ -137,7 +137,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { const ownedTokenAmount = ownedToken === undefined ? "0" : ownedToken.amount; const displayHigherBidWarning = getAmountInUSDValue(bidAmount).gte( - totalCollateralsValueInUSD.times(1.2) + totalCollateralsValueInUSD.times(1.2), ); const displayMinBidError = formState.errors.bidAmount?.type === "min"; const displayMinBidMessage = @@ -149,7 +149,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { @@ -165,12 +165,12 @@ export function PlaceBidScreen(props: Props): JSX.Element { { ownedAmount: ownedToken?.amount ?? "0.00", symbol: batch.loan.displaySymbol, - } + }, )} @@ -207,6 +207,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { {}} status={TokenDropdownButtonStatus.Locked} @@ -216,7 +217,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { light={tailwind("bg-mono-light-v2-00")} dark={tailwind("bg-mono-dark-v2-00")} style={tailwind( - "flex flex-row justify-around items-center py-3 mt-6 mx-1 rounded-xl-v2 font-normal-v2" + "flex flex-row justify-around items-center py-3 mt-6 mx-1 rounded-xl-v2 font-normal-v2", )} > {Object.values(BidAmountButtonTypes).map( @@ -230,7 +231,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { hasBorder={length - 1 !== index} /> ); - } + }, )} @@ -251,7 +252,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { { amount: minNextBidInToken.toFixed(8), symbol: batch.loan.symbol, - } + }, )} )} @@ -271,13 +272,13 @@ export function PlaceBidScreen(props: Props): JSX.Element { renderText={(value: string) => ( {translate( "components/QuickBid", "Your bid is higher than the auction's collateral value of {{currency}}{{amount}}", - { amount: value, currency: "$" } + { amount: value, currency: "$" }, )} )} @@ -291,7 +292,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { dark={tailwind("border-gray-700")} light={tailwind("border-gray-300")} style={tailwind( - "p-5 border-0.5 rounded-lg-v2 mx-1 my-6 font-normal-v2" + "p-5 border-0.5 rounded-lg-v2 mx-1 my-6 font-normal-v2", )} > {translate("screens/PlaceBidScreen", "Auction timeout")} @@ -332,7 +333,7 @@ export function PlaceBidScreen(props: Props): JSX.Element { > {translate( "screens/PlaceBidScreen", - "Review full details in the next screen" + "Review full details in the next screen", )} state.block.count ?? 0); const pairs = useSelector((state: RootState) => state.wallet.poolpairs); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const reservedDfi = 0.1; @@ -152,7 +153,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const [estimatedLessFeesAfterSlippage, setEstimatedLessFeesAfterSlippage] = useState(undefined); const [activeButtonGroup, setActiveButtonGroup] = useState( - ButtonGroupTabKey.InstantSwap + ButtonGroupTabKey.InstantSwap, ); const [isFutureSwap, setIsFutureSwap] = useState(false); const [bestPathEstimatedReturn, setBestPathEstimatedReturn] = useState< @@ -161,24 +162,24 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const [oraclePriceMessage, setOraclePriceMessage] = useState( translate( "screens/CompositeSwapScreen", - "Future swap uses the oracle price of the selected token on the settlement block" - ) + "Future swap uses the oracle price of the selected token on the settlement block", + ), ); const [hasShownInputFocusBefore, setHasShownInputFocusBefore] = useState(false); const executionBlock = useSelector( - (state: RootState) => state.futureSwaps.executionBlock + (state: RootState) => state.futureSwaps.executionBlock, ); const { timeRemaining, transactionDate, isEnded } = useFutureSwapDate( executionBlock, - blockCount + blockCount, ); const { fromTokens, toTokens } = useSwappableTokens( selectedTokenA?.id, selectedTokenA?.displaySymbol, selectedTokenA?.symbol, - activeButtonGroup === ButtonGroupTabKey.FutureSwap + activeButtonGroup === ButtonGroupTabKey.FutureSwap, ); const { isFutureSwapOptionEnabled, @@ -242,7 +243,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const { tokenA, tokenB } = watch(); const isReservedUtxoUsed = getDisplayUtxoWarningStatus( new BigNumber(tokenA), - selectedTokenA?.displaySymbol ?? "" + selectedTokenA?.displaySymbol ?? "", ); const { isConversionRequired, conversionAmount } = useConversion({ @@ -260,7 +261,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const maxAmount = BigNumber.max( new BigNumber(token.amount).minus(reservedDfi), - 0 + 0, ); return maxAmount.isLessThanOrEqualTo(0) ? new BigNumber(0).toFixed(8) @@ -269,7 +270,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const onTokenSelect = ( { tokenId, reserve, token: { displaySymbol, symbol } }: BottomSheetToken, - direction: "FROM" | "TO" + direction: "FROM" | "TO", ): void => { if ( (selectedTokenA?.displaySymbol === displaySymbol && @@ -386,7 +387,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { name: route.params.fromToken.name, }, }, - "FROM" + "FROM", ); return; @@ -408,7 +409,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { }, reserve: pair.data.tokenA.reserve, }, - "FROM" + "FROM", ); } if (tokenSelectOption.to.isPreselected) { @@ -423,7 +424,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { }, reserve: pair.data.tokenB.reserve, }, - "TO" + "TO", ); } }, [ @@ -451,7 +452,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { if (selectedTokenA !== undefined && selectedTokenB !== undefined) { const poolPairs = await getArbitraryPoolPair( selectedTokenA.id, - selectedTokenB.id + selectedTokenB.id, ); setSelectedPoolPairs(poolPairs); } @@ -472,7 +473,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { await calculatePriceRates( selectedTokenA.id, selectedTokenB.id, - new BigNumber(tokenA) + new BigNumber(tokenA), ); // Find the selected reserve in case it's null. From Token Detail Screen, reserve does not exist due to pair not existing @@ -485,10 +486,10 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { ? selectedTokenA.reserve : selectedReserve; const slippage = new BigNumber(1).minus( - new BigNumber(tokenA).div(tokenAReserve) + new BigNumber(tokenA).div(tokenAReserve), ); setEstimatedLessFeesAfterSlippage( - new BigNumber(estimatedLessDexFees).multipliedBy(slippage) + new BigNumber(estimatedLessDexFees).multipliedBy(slippage), ); setPriceRates([ @@ -522,7 +523,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { useEffect(() => { setIsFutureSwap( activeButtonGroup === ButtonGroupTabKey.FutureSwap && - isFutureSwapOptionEnabled + isFutureSwapOptionEnabled, ); }, [activeButtonGroup, isFutureSwapOptionEnabled]); @@ -534,7 +535,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { const fetchBestPath = async () => { const bestPath = await getBestPath( selectedTokenA.id === "0_unified" ? "0" : selectedTokenA.id, - selectedTokenB.id === "0_unified" ? "0" : selectedTokenB.id + selectedTokenB.id === "0_unified" ? "0" : selectedTokenB.id, ); setBestPathEstimatedReturn({ estimatedReturn: bestPath.estimatedReturn, @@ -559,38 +560,38 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { dexFeesInTokenBUnit = Burn fees + commission fee of 1 tokenA */ const dexFeesInTokenBUnit = new BigNumber( - bestPathEstimatedReturn?.estimatedReturn ?? 0 + bestPathEstimatedReturn?.estimatedReturn ?? 0, ) .minus( - new BigNumber(bestPathEstimatedReturn?.estimatedReturnLessDexFees ?? 0) + new BigNumber(bestPathEstimatedReturn?.estimatedReturnLessDexFees ?? 0), ) .multipliedBy(tokenA); /* Transaction fee + DEX fees */ return getPrecisedCurrencyValue( getTokenPrice("DFI", fee).plus( - getTokenPrice(selectedTokenB.symbol, dexFeesInTokenBUnit) - ) + getTokenPrice(selectedTokenB.symbol, dexFeesInTokenBUnit), + ), ); }, [priceRates, selectedTokenB, tokenA, bestPathEstimatedReturn, fee]); useEffect(() => { let message = translate( "screens/CompositeSwapScreen", - "Future swap uses the oracle price of the selected token on the settlement block" + "Future swap uses the oracle price of the selected token on the settlement block", ); if (selectedTokenA !== undefined) { if (selectedTokenA.displaySymbol === "DUSD") { if (selectedTokenB === undefined) { message = translate( "screens/CompositeSwapScreen", - "You are buying dTokens at 5% more than the oracle price at settlement block." + "You are buying dTokens at 5% more than the oracle price at settlement block.", ); } else { message = translate( "screens/CompositeSwapScreen", "You are buying {{displaySymbol}} at 5% more than the oracle price at settlement block.", - { displaySymbol: selectedTokenB.displaySymbol } + { displaySymbol: selectedTokenB.displaySymbol }, ); } } else { @@ -599,7 +600,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { "You are selling your {{displaySymbol}} at 5% less than the oracle price at settlement block.", { displaySymbol: selectedTokenA.displaySymbol, - } + }, ); } } @@ -721,7 +722,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { if (isConversionRequired) { queueConvertTransaction( { - mode: "utxosToAccount", + mode: ConvertDirection.utxosToAccount, amount: conversionAmount, }, dispatch, @@ -742,7 +743,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { params, merge: true, }); - } + }, ); } else { navigation.navigate("ConfirmCompositeSwapScreen", params); @@ -775,7 +776,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { return getTokenPrice(token.symbol, new BigNumber(tokenAmount)); }, - [] + [], ); const isBothTokensSelected = (): boolean => { @@ -784,7 +785,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { async function onPercentagePress( amount: string, - type: AmountButtonTypes + type: AmountButtonTypes, ): Promise { setValue("tokenA", amount); await trigger("tokenA"); @@ -811,7 +812,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { type: "wallet_toast", placement: "top", duration: TOAST_DURATION, - } + }, ); } @@ -858,7 +859,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { @@ -880,7 +881,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { @@ -933,7 +934,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { }} placeholder="0.00" placeholderTextColor={getColor( - isLight ? "mono-light-v2-900" : "mono-dark-v2-900" + isLight ? "mono-light-v2-900" : "mono-dark-v2-900", )} ref={amountInputRef} testID="text_input_tokenA" @@ -947,7 +948,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { validate: { greaterThanZero: (value: string) => new BigNumber( - value !== undefined && value !== "" ? value : 0 + value !== undefined && value !== "" ? value : 0, ).isGreaterThan(0), }, }} @@ -955,7 +956,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { navigateToTokenSelectionScreen(TokenListType.From) @@ -985,7 +987,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { > {translate( "screens/CompositeSwapScreen", - "Select a token first" + "Select a token first", )} )} @@ -1000,7 +1002,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { > {translate( "screens/CompositeSwapScreen", - "Insufficient balance" + "Insufficient balance", )} )} @@ -1015,7 +1017,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { > {translate( "screens/CompositeSwapScreen", - "A small amount of UTXO is reserved for fees" + "A small amount of UTXO is reserved for fees", )} )} @@ -1083,7 +1085,7 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { isBothTokensSelected() && priceRates !== undefined && activeButtonGroup === ButtonGroupTabKey.InstantSwap, - } + }, )} light={tailwind("border-mono-light-v2-300")} dark={tailwind("border-mono-dark-v2-300")} @@ -1096,12 +1098,13 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { tokenAmount={new BigNumber(tokenB).toFixed(8)} tokenUsdAmount={getAmountInUSDValue( selectedTokenB ?? undefined, - tokenB + tokenB, )} /> )} navigateToTokenSelectionScreen(TokenListType.To) @@ -1164,11 +1167,11 @@ export function CompositeSwapScreen({ route }: Props): JSX.Element { {isConversionRequired ? translate( "screens/CompositeSwapScreen", - "By continuing, the required amount of DFI will be converted" + "By continuing, the required amount of DFI will be converted", ) : translate( "screens/CompositeSwapScreen", - "Review full details in the next screen" + "Review full details in the next screen", )} )} diff --git a/mobile-app/app/screens/AppNavigator/screens/Dex/CompositeSwap/SwapTokenSelectionScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Dex/CompositeSwap/SwapTokenSelectionScreen.tsx index d33cf315ff..6f0f66ffe3 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Dex/CompositeSwap/SwapTokenSelectionScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Dex/CompositeSwap/SwapTokenSelectionScreen.tsx @@ -18,6 +18,7 @@ import { useTokenPrice } from "@screens/AppNavigator/screens/Portfolio/hooks/Tok import { translate } from "@translations"; import { useThemeContext } from "@waveshq/walletkit-ui"; import { PortfolioParamList } from "@screens/AppNavigator/screens/Portfolio/PortfolioNavigator"; +import { DomainType } from "@contexts/DomainContext"; export enum TokenListType { From = "FROM", @@ -30,6 +31,8 @@ export interface SelectionToken { token: { name: string; displaySymbol: string; + displayTextSymbol?: string; + domainType?: DomainType; symbol: string; isLPS?: boolean; }; @@ -45,6 +48,7 @@ export function SwapTokenSelectionScreen({ route }: Props): JSX.Element { listType, list, onTokenPress, + isConvert = false, isFutureSwap = false, isSearchDTokensOnly = false, } = route.params; @@ -109,7 +113,7 @@ export function SwapTokenSelectionScreen({ route }: Props): JSX.Element { showClearButton={debouncedSearchTerm !== ""} placeholder={translate( "screens/SwapTokenSelectionScreen", - "Search token" + "Search token", )} containerStyle={tailwind([ "border-0.5", @@ -147,9 +151,11 @@ export function SwapTokenSelectionScreen({ route }: Props): JSX.Element { "screens/SwapTokenSelectionScreen", listType === TokenListType.From ? "AVAILABLE TOKENS" + : isConvert + ? "AVAILABLE FOR CONVERT" : isFutureSwap ? "AVAILABLE FOR FUTURE SWAP" - : "AVAILABLE FOR SWAP" + : "AVAILABLE FOR SWAP", )} ) : ( @@ -162,7 +168,7 @@ export function SwapTokenSelectionScreen({ route }: Props): JSX.Element { {translate( "screens/SwapTokenSelectionScreen", getEmptyResultText(), - { searchTerm: debouncedSearchTerm } + { searchTerm: debouncedSearchTerm }, )} )} @@ -175,7 +181,7 @@ export function SwapTokenSelectionScreen({ route }: Props): JSX.Element { type TokenPrice = ( symbol: string, amount: BigNumber, - isLPS?: boolean | undefined + isLPS?: boolean | undefined, ) => BigNumber; interface TokenItemProps { @@ -199,13 +205,12 @@ function TokenItem({ const activePriceUSDT = getTokenPrice( item.token.symbol, new BigNumber("1"), - item.token.isLPS + item.token.isLPS, ); - return ( @@ -238,7 +247,7 @@ function TokenItem({ renderText={(value) => ( @@ -250,7 +259,7 @@ function TokenItem({ {listType === TokenListType.From ? ( ( [t.token.displaySymbol, t.token.name].some((searchItem) => - searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()) - ) + searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()), + ), ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Dex/DexAddLiquidity.tsx b/mobile-app/app/screens/AppNavigator/screens/Dex/DexAddLiquidity.tsx index 442419d6a0..648f02ab14 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Dex/DexAddLiquidity.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Dex/DexAddLiquidity.tsx @@ -41,6 +41,7 @@ import { ButtonV2 } from "@components/ButtonV2"; import { useToast } from "react-native-toast-notifications"; import { useBottomSheet } from "@hooks/useBottomSheet"; import { useDisplayUtxoWarning } from "@hooks/wallet/DisplayUtxoWarning"; +import { ConvertDirection } from "@screens/enum"; import { ViewPoolHeader } from "./components/ViewPoolHeader"; import { ViewPoolDetails, DataRoutes } from "./components/ViewPoolDetails"; import { LiquidityCalculationSummary } from "./components/LiquidityCalculationSummary"; @@ -63,20 +64,20 @@ export function AddLiquidityScreen(props: Props): JSX.Element { const navigation = useNavigation>(); const dispatch = useAppDispatch(); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const pairs = useSelector((state: RootState) => state.wallet.poolpairs); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const { getTokenPrice } = useTokenPrice(); const { pair: pairData, pairInfo, originScreen } = props.route.params; @@ -106,7 +107,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { const [tokenAAmount, setTokenAAmount] = useState(""); const [tokenBAmount, setTokenBAmount] = useState(""); const [sharePercentage, setSharePercentage] = useState( - new BigNumber(0) + new BigNumber(0), ); const [canContinue, setCanContinue] = useState(false); @@ -118,7 +119,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { inputToken: { type: "token", amount: new BigNumber( - pair?.tokenA.id === "0" ? tokenAAmount : tokenBAmount + pair?.tokenA.id === "0" ? tokenAAmount : tokenBAmount, ), }, deps: [pair, tokenAAmount, tokenBAmount, balanceA, balanceB], @@ -175,11 +176,11 @@ export function AddLiquidityScreen(props: Props): JSX.Element { setSharePercentage(refAmount.div(pair.tokenB.reserve)); } }, - [pair] + [pair], ); const getAddressTokenById = ( - poolpairTokenId: string + poolpairTokenId: string, ): WalletToken | undefined => { return tokens.find((token) => { if (poolpairTokenId === "0" || poolpairTokenId === "0_utxo") { @@ -207,7 +208,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { _amount: string, type: AmountButtonTypes, displaySymbolA: string, - displaySymbolB: string + displaySymbolB: string, ): void { showToast(type, displaySymbolA, displaySymbolB); } @@ -224,7 +225,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { if (isConversionRequired) { queueConvertTransaction( { - mode: "utxosToAccount", + mode: ConvertDirection.utxosToAccount, amount: conversionAmount, }, dispatch, @@ -282,7 +283,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { }, merge: true, }); - } + }, ); } else { navigation.navigate({ @@ -309,7 +310,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { function showToast( type: AmountButtonTypes, displaySymbolA: string, - displaySymbolB: string + displaySymbolB: string, ): void { if (displaySymbolA === undefined || displaySymbolB === undefined) { return; @@ -354,7 +355,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { pair !== undefined && getDisplayUtxoWarningStatus( new BigNumber(tokenAAmount), - pair?.tokenA.displaySymbol + pair?.tokenA.displaySymbol, ) && new BigNumber(tokenAAmount).isGreaterThan(0) ) { @@ -369,7 +370,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { pair !== undefined && getDisplayUtxoWarningStatus( new BigNumber(tokenBAmount), - pair?.tokenB.displaySymbol + pair?.tokenB.displaySymbol, ) && new BigNumber(tokenBAmount).isGreaterThan(0) ) { @@ -403,14 +404,14 @@ export function AddLiquidityScreen(props: Props): JSX.Element { ? TransactionCardStatus.Error : isInputAFocus ? TransactionCardStatus.Active - : undefined + : undefined, ); setTokenBTransactionCardStatus( hasBError ? TransactionCardStatus.Error : isInputBFocus ? TransactionCardStatus.Active - : undefined + : undefined, ); }, [hasAError, hasBError, isInputAFocus, isInputBFocus]); @@ -424,8 +425,8 @@ export function AddLiquidityScreen(props: Props): JSX.Element { new BigNumber(tokenAAmount), new BigNumber(tokenBAmount), balanceA, - balanceB - ) + balanceB, + ), ); }, [pair, tokenAAmount, tokenBAmount, balanceA, balanceB]); @@ -445,10 +446,10 @@ export function AddLiquidityScreen(props: Props): JSX.Element { aSymbol, bSymbol, aToBRate: new BigNumber(poolpair.tokenB.reserve).div( - poolpair.tokenA.reserve + poolpair.tokenA.reserve, ), bToARate: new BigNumber(poolpair.tokenA.reserve).div( - poolpair.tokenB.reserve + poolpair.tokenB.reserve, ), }); if (addressTokenA !== undefined) { @@ -456,9 +457,9 @@ export function AddLiquidityScreen(props: Props): JSX.Element { addressTokenA.id === "0_unified" ? BigNumber.max( new BigNumber(addressTokenA.amount).minus(reservedDfi), - 0 + 0, ) - : new BigNumber(addressTokenA.amount) + : new BigNumber(addressTokenA.amount), ); } if (addressTokenB !== undefined) { @@ -466,9 +467,9 @@ export function AddLiquidityScreen(props: Props): JSX.Element { addressTokenB.id === "0_unified" ? BigNumber.max( new BigNumber(addressTokenB.amount).minus(reservedDfi), - 0 + 0, ) - : new BigNumber(addressTokenB.amount) + : new BigNumber(addressTokenB.amount), ); } } @@ -514,7 +515,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { amount, type, pair.tokenA.displaySymbol, - pair.tokenB.displaySymbol + pair.tokenB.displaySymbol, ); }} symbol={pair.tokenA.displaySymbol} @@ -537,7 +538,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { amount, type, pair.tokenA.displaySymbol, - pair.tokenB.displaySymbol + pair.tokenB.displaySymbol, ); }} symbol={pair.tokenB.displaySymbol} @@ -575,7 +576,7 @@ export function AddLiquidityScreen(props: Props): JSX.Element { resultingLplhs={{ value: translate( "screens/AddLiquidity", - "LP Tokens to receive" + "LP Tokens to receive", ), testID: "lp_tokens_to_receive", themedProps: { @@ -590,9 +591,9 @@ export function AddLiquidityScreen(props: Props): JSX.Element { testID: "lp_tokens_to_receive_value", usdAmount: getTokenPrice( pair.aSymbol, - new BigNumber(tokenAAmount) + new BigNumber(tokenAAmount), ).plus( - getTokenPrice(pair.bSymbol, new BigNumber(tokenBAmount)) + getTokenPrice(pair.bSymbol, new BigNumber(tokenBAmount)), ), themedProps: { style: tailwind("font-semibold-v2 text-sm"), @@ -610,11 +611,11 @@ export function AddLiquidityScreen(props: Props): JSX.Element { {isConversionRequired ? translate( "screens/AddLiquidity", - "By continuing, the required amount of DFI will be converted" + "By continuing, the required amount of DFI will be converted", ) : translate( "screens/AddLiquidity", - "Review full details in the next screen" + "Review full details in the next screen", )} @@ -668,7 +669,7 @@ function canAddLiquidity( tokenAAmount: BigNumber, tokenBAmount: BigNumber, balanceA: BigNumber | undefined, - balanceB: BigNumber | undefined + balanceB: BigNumber | undefined, ): boolean { if (tokenAAmount.isNaN() || tokenBAmount.isNaN()) { // empty string, use still input-ing diff --git a/mobile-app/app/screens/AppNavigator/screens/Dex/DexNavigator.tsx b/mobile-app/app/screens/AppNavigator/screens/Dex/DexNavigator.tsx index a32e453092..9ea9e73458 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Dex/DexNavigator.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Dex/DexNavigator.tsx @@ -61,6 +61,7 @@ export interface DexParamList { listType: TokenListType; list: SelectionToken[]; onTokenPress: (token: SelectionToken) => void; + isConvert?: boolean; isFutureSwap: boolean; isSearchDTokensOnly?: boolean; }; diff --git a/mobile-app/app/screens/AppNavigator/screens/Dex/components/PoolPairCards/PoolPairCards.tsx b/mobile-app/app/screens/AppNavigator/screens/Dex/components/PoolPairCards/PoolPairCards.tsx index 422c3c7765..5b213fcc32 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Dex/components/PoolPairCards/PoolPairCards.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Dex/components/PoolPairCards/PoolPairCards.tsx @@ -78,7 +78,7 @@ export function PoolPairCards({ useFavouritePoolpairContext(); const sortedPairs = sortPoolpairsByFavourite( availablePairs, - isFavouritePoolpair + isFavouritePoolpair, ); const { tvl } = useSelector((state: RootState) => state.block); const [filteredYourPairs, setFilteredYourPairs] = @@ -89,7 +89,7 @@ export function PoolPairCards({ const pairSortingFn = ( pairA: DexItem, - pairB: DexItem + pairB: DexItem, ): number => availablePairs.findIndex((x) => x.data.id === pairA.data.id) - availablePairs.findIndex((x) => x.data.id === pairB.data.id); @@ -109,9 +109,9 @@ export function PoolPairCards({ .filter((pair) => pair.data.displaySymbol .toLowerCase() - .includes(debouncedSearchTerm.trim().toLowerCase()) + .includes(debouncedSearchTerm.trim().toLowerCase()), ) - .sort(pairSortingFn) + .sort(pairSortingFn), ); } else { setFilteredYourPairs([]); @@ -166,7 +166,7 @@ export function PoolPairCards({ title={translate("screens/DexScreen", "No favorites added")} subtitle={translate( "screens/DexScreen", - "Tap the star icon to add your favorite pools here" + "Tap the star icon to add your favorite pools here", )} /> )} @@ -198,7 +198,7 @@ export function PoolPairCards({ dark={tailwind("text-mono-dark-v2-500")} light={tailwind("text-mono-light-v2-500")} style={tailwind( - "font-normal-v2 text-xs uppercase pl-10 mb-2" + "font-normal-v2 text-xs uppercase pl-10 mb-2", )} > {translate("screens/DexScreen", "Available pairs")} @@ -243,7 +243,7 @@ function PoolCard({ const isFavoritePair = isFavouritePoolpair(yourPair.id); const poolPairData = pairs.find( - (pr) => pr.data.symbol === (yourPair as AddressToken).symbol + (pr) => pr.data.symbol === (yourPair as AddressToken).symbol, ); const mappedPair = poolPairData?.data; @@ -291,7 +291,7 @@ function PoolCard({ walletTokenPrice={getTokenPrice( yourPair.symbol, new BigNumber((yourPair as WalletToken).amount), - true + true, )} /> )} @@ -353,7 +353,7 @@ function AvailablePool(props: AvailablePoolProps): JSX.Element { isFavouritePair={props.isFavouritePair} onPress={() => { showToast( - props.isFavouritePair ? "UNSET_FAVOURITE" : "SET_FAVOURITE" + props.isFavouritePair ? "UNSET_FAVOURITE" : "SET_FAVOURITE", ); props.setFavouritePoolpair(props.pair.id); }} @@ -378,10 +378,10 @@ function AvailablePool(props: AvailablePoolProps): JSX.Element { {props.pair?.apr?.total !== undefined && props.pair?.apr?.total !== null && ( >, - isFavouritePair: (id: string) => boolean + isFavouritePair: (id: string) => boolean, ): Array> { return pairs.slice().sort((firstPair, secondPair) => { if (isFavouritePair(firstPair.data.id)) { @@ -566,7 +568,7 @@ function NewPoolsSection({ onActionPress={() => onActionPress( pairItem.data as PoolPairData, - pairItem.data as WalletToken + pairItem.data as WalletToken, ) } onPress={() => onPress(pairItem.data.id)} diff --git a/mobile-app/app/screens/AppNavigator/screens/Loans/components/BottomSheetLoanTokensList.tsx b/mobile-app/app/screens/AppNavigator/screens/Loans/components/BottomSheetLoanTokensList.tsx index 4b4901a8b0..3194daa6e4 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Loans/components/BottomSheetLoanTokensList.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Loans/components/BottomSheetLoanTokensList.tsx @@ -40,7 +40,7 @@ export const BottomSheetLoanTokensList = ({ return filterLoanTokensBySearchTerm( loanTokens, debouncedSearchTerm, - isSearchFocus + isSearchFocus, ); }, [debouncedSearchTerm, isSearchFocus]); @@ -64,12 +64,12 @@ export const BottomSheetLoanTokensList = ({ keyExtractor={(item) => item.tokenId} renderItem={({ item }: ListRenderItemInfo): JSX.Element => { const currentPrice = getPrecisedTokenValue( - getActivePrice(item.token.symbol, item.activePrice) + getActivePrice(item.token.symbol, item.activePrice), ); return ( @@ -101,7 +102,7 @@ export const BottomSheetLoanTokensList = ({ renderText={(value) => ( @@ -117,7 +118,7 @@ export const BottomSheetLoanTokensList = ({ renderText={(value) => ( @@ -145,7 +146,7 @@ export const BottomSheetLoanTokensList = ({ showClearButton={searchString !== ""} placeholder={translate( "components/BottomSheetLoanTokensList", - "Search with token name" + "Search with token name", )} containerStyle={tailwind([ "border-0.5", @@ -184,12 +185,12 @@ export const BottomSheetLoanTokensList = ({ {searchString.trim() === "" ? translate( "components/BottomSheetLoanTokensList", - "Search with token name" + "Search with token name", ) : translate( "components/BottomSheetLoanTokensList", "Search results for “{{searchTerm}}”", - { searchTerm: searchString } + { searchTerm: searchString }, )} @@ -210,14 +211,14 @@ export const BottomSheetLoanTokensList = ({ function filterLoanTokensBySearchTerm( loanTokens: LoanToken[], searchTerm: string, - isFocused: boolean + isFocused: boolean, ): LoanToken[] { if (searchTerm === "") { return isFocused ? [] : loanTokens; } return loanTokens.filter((t) => { return [t.token.displaySymbol].some((searchItem) => - searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()) + searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()), ); }); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/AddOrRemoveCollateralScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/AddOrRemoveCollateralScreen.tsx index 0fae6a1ff0..000c61b98a 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/AddOrRemoveCollateralScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/AddOrRemoveCollateralScreen.tsx @@ -54,6 +54,7 @@ import { queueConvertTransaction } from "@hooks/wallet/Conversion"; import { NavigationProp, useNavigation } from "@react-navigation/native"; import { BottomSheetTokenListHeader } from "@components/BottomSheetTokenListHeader"; import { LoanVaultTokenAmount } from "@defichain/whale-api-client/dist/api/loan"; +import { ConvertDirection } from "@screens/enum"; import { getActivePrice } from "../../Auctions/helpers/ActivePrice"; import { ActiveUSDValueV2 } from "../VaultDetail/components/ActiveUSDValueV2"; import { LoanParamList } from "../LoansNavigator"; @@ -96,17 +97,17 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { const dispatch = useAppDispatch(); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const navigation = useNavigation>(); @@ -130,7 +131,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { isAdd && selectedCollateralItem.token.id === "0" ? new BigNumber(collateralAmount).isGreaterThan(DFIToken.amount) && new BigNumber(collateralAmount).isLessThanOrEqualTo( - selectedCollateralItem.available + selectedCollateralItem.available, ) : false; @@ -139,7 +140,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { : collateralAmount; const collateralInputValue = getCollateralValue( new BigNumber(collateralInputAmount), - selectedCollateralItem + selectedCollateralItem, ); // Vault collaterals value @@ -149,26 +150,26 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { ? new BigNumber(currentVaultCollateralValue).plus(collateralInputValue) : new BigNumber(currentVaultCollateralValue).minus(collateralInputValue); const totalVaultCollateralValueInUSD = new BigNumber( - getPrecisedTokenValue(totalVaultCollateralValue) + getPrecisedTokenValue(totalVaultCollateralValue), ); // Collateral value for selected token const currentTokenBalance = vault?.collateralAmounts?.find( - (c) => c.id === selectedCollateralItem?.token.id + (c) => c.id === selectedCollateralItem?.token.id, )?.amount ?? "0"; const totalTokenBalance = isAdd ? new BigNumber(currentTokenBalance)?.plus(collateralInputAmount) : BigNumber.max( 0, - new BigNumber(currentTokenBalance)?.minus(collateralInputAmount) + new BigNumber(currentTokenBalance)?.minus(collateralInputAmount), ); const tokenCollateralValue = getCollateralValue( totalTokenBalance, - selectedCollateralItem + selectedCollateralItem, ); const totalTokenValueInUSD = new BigNumber( - getPrecisedTokenValue(tokenCollateralValue) + getPrecisedTokenValue(tokenCollateralValue), ); const activePrice = new BigNumber( @@ -177,8 +178,8 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { selectedCollateralItem.activePrice, selectedCollateralItem.factor, "ACTIVE", - "COLLATERAL" - ) + "COLLATERAL", + ), ); const collateralVaultShare = getVaultShare(totalTokenBalance, activePrice, totalVaultCollateralValue) ?? @@ -197,7 +198,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { totalVaultCollateralValue, new BigNumber(vault.loanValue), selectedCollateralItem.token.id, - totalTokenBalance + totalTokenBalance, ); const getUpdatedCollateralAmounts = (): LoanVaultTokenAmount[] => { @@ -211,11 +212,11 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { activePrice: selectedCollateralItem.activePrice, }; const collateralExists = vault.collateralAmounts.find( - (col) => col.id === selectedCollateralItem.token.id + (col) => col.id === selectedCollateralItem.token.id, ); if (collateralExists) { const updatedCollateralAmounts = vault.collateralAmounts.map((col) => - col.id === collateralAmountToUpdate.id ? collateralAmountToUpdate : col + col.id === collateralAmountToUpdate.id ? collateralAmountToUpdate : col, ); return updatedCollateralAmounts; } else { @@ -239,7 +240,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { async function onPercentageChange( amount: string, - type: AmountButtonTypes + type: AmountButtonTypes, ): Promise { setValue("collateralAmount", amount); await trigger("collateralAmount"); @@ -272,18 +273,18 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { translate( "screens/AddOrRemoveCollateralScreen", isAdd ? toastOptionsOnAdd.message : toastOptionsOnRemove.message, - isAdd ? toastOptionsOnAdd.params : toastOptionsOnRemove.params + isAdd ? toastOptionsOnAdd.params : toastOptionsOnRemove.params, ), { type: "wallet_toast", placement: "top", duration: TOAST_DURATION, - } + }, ); } const onAddCollateral = async ( - props: LoanParamList["ConfirmEditCollateralScreen"] + props: LoanParamList["ConfirmEditCollateralScreen"], ): Promise => { const initialParams = { name: "ConfirmEditCollateralScreen", @@ -295,7 +296,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { }; if (isConversionRequired) { const conversionAmount = new BigNumber(props.amount).minus( - DFIToken.amount + DFIToken.amount, ); initialParams.params.conversion = { DFIUtxo, @@ -305,14 +306,14 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { } as any; queueConvertTransaction( { - mode: "utxosToAccount", + mode: ConvertDirection.utxosToAccount, amount: conversionAmount, }, dispatch, () => { navigation.navigate(initialParams); }, - logger + logger, ); } else { navigation.navigate(initialParams); @@ -320,7 +321,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { }; const onRemoveCollateral = async ( - props: LoanParamList["ConfirmEditCollateralScreen"] + props: LoanParamList["ConfirmEditCollateralScreen"], ): Promise => { navigation.navigate({ name: "ConfirmEditCollateralScreen", @@ -334,7 +335,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { const handleEditCollateral = async (): Promise => { const collateralItem = collateralTokens.find( - (col) => col.token.id === selectedCollateralItem.token.id + (col) => col.token.id === selectedCollateralItem.token.id, ); if (vault === undefined || collateralItem === undefined) { return; @@ -397,7 +398,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { new BigNumber(vault.loanValue) .multipliedBy(vault.loanScheme.minColRatio) .dividedBy(100) - .dividedBy(2) + .dividedBy(2), ); if (isDFILessThanHalfOfRequiredCollateral) { return { @@ -433,7 +434,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { style={tailwind("flex-col flex-1")} testID="add_remove_collateral_screen" contentContainerStyle={tailwind( - "flex-grow justify-between pt-8 px-5 pb-14" + "flex-grow justify-between pt-8 px-5 pb-14", )} > @@ -446,7 +447,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { > {translate( "screens/AddOrRemoveCollateralScreen", - isAdd ? "I WANT TO ADD" : "I WANT TO REMOVE" + isAdd ? "I WANT TO ADD" : "I WANT TO REMOVE", )} @@ -475,7 +476,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { > @@ -515,6 +516,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { { setBottomSheetScreen([ @@ -540,7 +542,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { @@ -577,7 +579,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { { amount: selectedCollateralItem.available.toFixed(8), symbol: selectedCollateralItem.token.displaySymbol, - } + }, ) : translate( "screens/AddOrRemoveCollateralScreen", @@ -585,7 +587,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { { amount: currentTokenBalance, symbol: selectedCollateralItem.token.displaySymbol, - } + }, )} )} @@ -600,7 +602,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { > {translate( "screens/AddOrRemoveCollateralScreen", - "A small amount of UTXO is reserved for fees" + "A small amount of UTXO is reserved for fees", )} )} @@ -616,7 +618,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { > {translate( "screens/AddOrRemoveCollateralScreen", - "Insufficient Balance" + "Insufficient Balance", )} )} @@ -631,7 +633,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { > {translate( "screens/AddOrRemoveCollateralScreen", - removeCollateralError.message + removeCollateralError.message, )} )} @@ -655,7 +657,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { lhs={{ value: translate( "screens/AddOrRemoveCollateralScreen", - "Vault ID" + "Vault ID", ), testID: "add_remove_collateral_vault_id_label", themedProps: lhsThemedProps, @@ -684,7 +686,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { lhs={{ value: translate( "screens/AddOrRemoveCollateralScreen", - "Vault share" + "Vault share", ), testID: "add_remove_collateral_vault_share", themedProps: lhsThemedProps, @@ -714,7 +716,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { lhs={{ value: translate( "screens/AddOrRemoveCollateralScreen", - "Max loan amount" + "Max loan amount", ), testID: "add_remove_collateral_max_loan", themedProps: lhsThemedProps, @@ -756,7 +758,7 @@ export function AddOrRemoveCollateralScreen({ route }: Props): JSX.Element { "screens/AddOrRemoveCollateralScreen", isConversionRequired ? "By continuing, the required amount of DFI will be converted" - : "Review full details in the next screen" + : "Review full details in the next screen", )} )} @@ -826,7 +828,7 @@ function TotalTokenCollateralRow(props: { > {translate( "screens/AddOrRemoveCollateralScreen", - "Total collateral" + "Total collateral", )} diff --git a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/BorrowLoanTokenScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/BorrowLoanTokenScreen.tsx index 4c2bf5f580..3dca96f01f 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/BorrowLoanTokenScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/BorrowLoanTokenScreen.tsx @@ -80,23 +80,23 @@ export function BorrowLoanTokenScreen({ const blockCount = useSelector((state: RootState) => state.block.count); const vaults = useSelector((state: RootState) => vaultsSelector(state.loans)); const loanTokens = useSelector((state: RootState) => - loanTokensSelector(state.loans) + loanTokensSelector(state.loans), ); const [vault, setVault] = useState(route.params.vault); const [loanToken, setLoanToken] = useState(route.params.loanToken); const [totalAnnualInterest, setTotalAnnualInterest] = useState( - new BigNumber(NaN) + new BigNumber(NaN), ); const [fee, setFee] = useState(new BigNumber(0.0001)); const interestPerBlock = useInterestPerBlock( new BigNumber(vault.loanScheme.interestRate ?? NaN), - new BigNumber(loanToken.interest) + new BigNumber(loanToken.interest), ); const { requiredTokensShare } = useValidCollateralRatio( vault.collateralAmounts, new BigNumber(vault.collateralValue), - new BigNumber(vault.loanValue) + new BigNumber(vault.loanValue), ); const maxLoanAmount = useMaxLoan({ @@ -105,16 +105,16 @@ export function BorrowLoanTokenScreen({ existingLoanValue: new BigNumber(vault.loanValue), minColRatio: new BigNumber(vault.loanScheme.minColRatio), loanActivePrice: new BigNumber( - getActivePrice(loanToken.token.symbol, loanToken.activePrice) + getActivePrice(loanToken.token.symbol, loanToken.activePrice), ), interestPerBlock: interestPerBlock, }); const blocksPerDay = useBlocksPerDay(); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); // Form Input @@ -129,9 +129,9 @@ export function BorrowLoanTokenScreen({ ? new BigNumber(0) : new BigNumber(borrowAmount), new BigNumber( - getActivePrice(loanToken.token.symbol, loanToken.activePrice) + getActivePrice(loanToken.token.symbol, loanToken.activePrice), ), - interestPerBlock + interestPerBlock, ); const [disableContinue, setDisableContinue] = useState(false); const { isDFILessThanHalfOfRequiredCollateral } = @@ -142,13 +142,13 @@ export function BorrowLoanTokenScreen({ loanValue: new BigNumber(vault.loanValue).plus( new BigNumber(borrowAmount).isNaN() ? new BigNumber(0) - : new BigNumber(borrowAmount) + : new BigNumber(borrowAmount), ), loanToken: loanToken, minColRatio: vault.loanScheme.minColRatio, }); const { atRiskThreshold } = useColRatioThreshold( - new BigNumber(vault.loanScheme.minColRatio) + new BigNumber(vault.loanScheme.minColRatio), ); // Bottom sheet @@ -172,7 +172,7 @@ export function BorrowLoanTokenScreen({ @@ -201,7 +201,7 @@ export function BorrowLoanTokenScreen({ @@ -233,7 +233,7 @@ export function BorrowLoanTokenScreen({ async function onPercentagePress( amount: string, - type: AmountButtonTypes + type: AmountButtonTypes, ): Promise { setValue("borrowAmount", amount); await trigger("borrowAmount"); @@ -259,14 +259,14 @@ export function BorrowLoanTokenScreen({ type: "wallet_toast", placement: "top", duration: TOAST_DURATION, - } + }, ); } const updateInterestAmount = (): void => { const loanTokenPrice = getActivePrice( loanToken.token.symbol, - loanToken.activePrice + loanToken.activePrice, ); if (borrowAmount === undefined || loanTokenPrice === "0") { return; @@ -336,14 +336,14 @@ export function BorrowLoanTokenScreen({ fetchVaults({ address, client, - }) + }), ); } }, [blockCount, address, isFocused]); useEffect(() => { const updatedVault = vaults.find( - (v) => v.vaultId === vault.vaultId + (v) => v.vaultId === vault.vaultId, ) as LoanVaultActive; setVault(updatedVault); }, [vaults]); @@ -358,7 +358,7 @@ export function BorrowLoanTokenScreen({ resultingColRatio.isLessThan(vault.loanScheme.minColRatio) || hasPendingJob || hasPendingBroadcastJob || - !formState.isValid + !formState.isValid, ); }, [ resultingColRatio, @@ -379,7 +379,7 @@ export function BorrowLoanTokenScreen({ @@ -411,7 +411,7 @@ export function BorrowLoanTokenScreen({ > @@ -436,7 +436,7 @@ export function BorrowLoanTokenScreen({ }} placeholder="0.00" placeholderTextColor={getColor( - isLight ? "mono-light-v2-500" : "mono-dark-v2-500" + isLight ? "mono-light-v2-500" : "mono-dark-v2-500", )} testID="text_input_borrow_amount" /> @@ -448,7 +448,7 @@ export function BorrowLoanTokenScreen({ validate: { greaterThanZero: (value: string) => new BigNumber( - value !== undefined && value !== "" ? value : 0 + value !== undefined && value !== "" ? value : 0, ).isGreaterThan(0), hasDFIandDUSDCollateral: () => requiredTokensShare.isGreaterThan(0), // need >0 DFI and or DUSD to take loan @@ -461,12 +461,12 @@ export function BorrowLoanTokenScreen({ price={new BigNumber( typeof borrowAmount === "string" && borrowAmount.length > 0 ? borrowAmount - : 0 + : 0, ).multipliedBy( getActivePrice( loanToken.token.symbol, - loanToken.activePrice - ) + loanToken.activePrice, + ), )} style={tailwind("text-sm")} testId="borrow_amount_in_usd" @@ -476,6 +476,7 @@ export function BorrowLoanTokenScreen({ { setBottomSheetScreen(bottomSheetLoanTokenList); @@ -494,7 +495,7 @@ export function BorrowLoanTokenScreen({ > {translate( "screens/BorrowLoanTokenScreen", - "Amount entered will result in vault liquidation" + "Amount entered will result in vault liquidation", )} )} @@ -536,7 +537,7 @@ export function BorrowLoanTokenScreen({ > {translate( "screens/BorrowLoanTokenScreen", - inputValidationMessage.message + inputValidationMessage.message, )} ) : ( @@ -549,7 +550,7 @@ export function BorrowLoanTokenScreen({ > {translate( "screens/BorrowLoanTokenScreen", - "Review full details in the next screen" + "Review full details in the next screen", )} ) @@ -611,7 +612,7 @@ function VaultInput(props: VaultInputProps): JSX.Element { /> ; @@ -48,20 +49,20 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { const { network } = useNetworkContext(); const { address } = useWalletContext(); const loanSchemes = useSelector((state: RootState) => - ascColRatioLoanScheme(state.loans) + ascColRatioLoanScheme(state.loans), ); const hasFetchedLoanSchemes = useSelector( - (state: RootState) => state.loans.hasFetchedLoanSchemes + (state: RootState) => state.loans.hasFetchedLoanSchemes, ); const logger = useLogger(); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const RESERVE_AMOUNT = 2.1; @@ -72,7 +73,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { const [conversionStatus, setConversionStatus] = useState( new BigNumber(RESERVE_AMOUNT).gt(DFIUtxo.amount) ? ConversionStatus.Required - : ConversionStatus.Not_Required + : ConversionStatus.Not_Required, ); const [conversionAmount, setConversionAmount] = useState< BigNumber | undefined @@ -84,7 +85,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { network === EnvironmentNetwork.TestNet || network === EnvironmentNetwork.DevNet ? 2 - : 1 + : 1, ); const onSubmit = async (): Promise => { @@ -100,7 +101,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { const convertAmount = new BigNumber(RESERVE_AMOUNT).minus(DFIUtxo.amount); queueConvertTransaction( { - mode: "accountToUtxos", + mode: ConvertDirection.accountToUtxos, amount: convertAmount, }, dispatch, @@ -111,7 +112,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { logger, () => { setConversionStatus(ConversionStatus.Completed); - } + }, ); } else { if (hasPendingJob || hasPendingBroadcastJob) { @@ -131,10 +132,10 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { fetchVaults({ address, client, - }) + }), ); }, - logger + logger, ); } }; @@ -167,7 +168,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { const needsConvert = new BigNumber(RESERVE_AMOUNT).gt(DFIUtxo.amount); setConversionStatus( - needsConvert ? ConversionStatus.Required : ConversionStatus.Not_Required + needsConvert ? ConversionStatus.Required : ConversionStatus.Not_Required, ); if (needsConvert) { setConversionAmount(undefined); @@ -184,7 +185,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { > {translate( "screens/CreateVaultScreen", - "Select a loan scheme for your vault." + "Select a loan scheme for your vault.", )} @@ -222,7 +223,7 @@ export function CreateVaultScreen({ navigation, route }: Props): JSX.Element { "screens/CreateVaultScreen", conversionStatus === ConversionStatus.Required ? "Continue" - : "Create vault" + : "Create vault", )} onPress={onSubmit} styleProps="mt-0 mx-7" @@ -249,7 +250,7 @@ function ButtonActionMessage(props: { "screens/CreateVaultScreen", props.isConversionRequired ? "By continuing, the required amount of DFI will be converted" - : "Monitor your vault’s collateralization to prevent liquidation." + : "Monitor your vault’s collateralization to prevent liquidation.", )} )} @@ -267,11 +268,11 @@ async function createVault( dispatch: Dispatch, onBroadcast: () => void, onConfirmation: () => void, - logger: NativeLoggingProps + logger: NativeLoggingProps, ): Promise { try { const signer = async ( - account: WhaleWalletAccount + account: WhaleWalletAccount, ): Promise => { const script = await account.getScript(); const builder = account.withTransactionBuilder(); @@ -280,7 +281,7 @@ async function createVault( ownerAddress: script, schemeId: loanScheme.id, }, - script + script, ); return new CTransactionSegWit(signed); }; @@ -292,14 +293,14 @@ async function createVault( drawerMessages: { preparing: translate( "screens/OceanInterface", - "Preparing to create vault…" + "Preparing to create vault…", ), waiting: translate("screens/OceanInterface", "Creating vault"), complete: translate("screens/OceanInterface", "Vault created"), }, onBroadcast, onConfirmation, - }) + }), ); } catch (e) { logger.error(e); diff --git a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/PaybackLoanScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/PaybackLoanScreen.tsx index bcdd0a04f3..9f11afa8b8 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Loans/screens/PaybackLoanScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Loans/screens/PaybackLoanScreen.tsx @@ -61,10 +61,10 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { const dispatch = useAppDispatch(); const [vault, setVault] = useState(routeParams.vault); const [loanTokenAmount, setLoanTokenAmount] = useState( - routeParams.loanTokenAmount + routeParams.loanTokenAmount, ); const vaults = useSelector((state: RootState) => - activeVaultsSelector(state.loans) + activeVaultsSelector(state.loans), ); useEffect(() => { @@ -72,7 +72,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { }, []); const collateralTokens = useSelector( - (state: RootState) => state.loans.collateralTokens + (state: RootState) => state.loans.collateralTokens, ); useEffect(() => { @@ -81,7 +81,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { setVault(vault); } const loanTokenAmount = vault?.loanAmounts.find( - (l: LoanVaultTokenAmount) => l.id === routeParams.loanTokenAmount.id + (l: LoanVaultTokenAmount) => l.id === routeParams.loanTokenAmount.id, ); if (loanTokenAmount !== undefined) { setLoanTokenAmount(loanTokenAmount); @@ -89,7 +89,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { }, [vaults]); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const toast = useToast(); const TOAST_DURATION = 2000; @@ -102,7 +102,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { }); } const loanToken = useSelector((state: RootState) => - loanTokenByTokenId(state.loans, loanTokenAmount.id) + loanTokenByTokenId(state.loans, loanTokenAmount.id), ); const { isLight } = useThemeContext(); const canUseOperations = useLoanOperations(vault?.state); @@ -112,7 +112,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { }); const { amountToPay } = watch(); const collateralDUSD = vault?.collateralAmounts?.find( - ({ symbol }) => symbol === "DUSD" + ({ symbol }) => symbol === "DUSD", ); const collateralDUSDAmount = collateralDUSD?.amount ?? "0"; const [fee, setFee] = useState(new BigNumber(0.0001)); @@ -129,14 +129,14 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { if (routeParams.isPaybackDUSDUsingCollateral) { setValue( "amountToPay", - BigNumber.min(collateralDUSDAmount, loanTokenAmount.amount).toFixed(8) + BigNumber.min(collateralDUSDAmount, loanTokenAmount.amount).toFixed(8), ); } }, [loanTokenAmount, collateralDUSDAmount]); const interestPerBlock = useInterestPerBlock( new BigNumber(vault?.loanScheme.interestRate ?? NaN), - new BigNumber(loanToken?.interest ?? NaN) + new BigNumber(loanToken?.interest ?? NaN), ); const token = tokens?.find((t) => t.id === loanTokenAmount.id); const tokenBalance = @@ -152,21 +152,23 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { ? collateralFactor : undefined, undefined, - routeParams.isPaybackDUSDUsingCollateral === true ? "COLLATERAL" : undefined + routeParams.isPaybackDUSDUsingCollateral === true + ? "COLLATERAL" + : undefined, ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const getCollateralValue = (collateralValue: string) => { if (routeParams.isPaybackDUSDUsingCollateral) { // In case of DUSD payment using collateral return new BigNumber(collateralValue).minus( - new BigNumber(amountToPay).multipliedBy(loanTokenActivePriceInUSD) + new BigNumber(amountToPay).multipliedBy(loanTokenActivePriceInUSD), ); } return new BigNumber(collateralValue); @@ -177,10 +179,10 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { new BigNumber(vault?.loanValue ?? NaN), BigNumber.min( new BigNumber(amountToPay).isNaN() ? "0" : amountToPay, - loanTokenAmount.amount + loanTokenAmount.amount, ).multipliedBy(-1), new BigNumber(loanTokenActivePriceInUSD), - interestPerBlock + interestPerBlock, ); const navigateToConfirmScreen = async (): Promise => { @@ -202,7 +204,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { const onChangeFromAmount = async ( amount: string, - type: AmountButtonTypes + type: AmountButtonTypes, ): Promise => { const isMax = type === AmountButtonTypes.Max; const toastMessage = isMax @@ -214,7 +216,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { percent: type, }; showToast( - translate("screens/PaybackLoanScreen", toastMessage, toastOption) + translate("screens/PaybackLoanScreen", toastMessage, toastOption), ); await trigger("amountToPay"); }; @@ -238,7 +240,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { "screens/PaybackLoanScreen", routeParams.isPaybackDUSDUsingCollateral ? "I WANT TO PAY WITH DUSD COLLATERAL" - : "I WANT TO PAY" + : "I WANT TO PAY", )} @@ -266,7 +268,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { > @@ -276,7 +278,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { routeParams.isPaybackDUSDUsingCollateral ? BigNumber.min( collateralDUSDAmount, - loanTokenAmount.amount + loanTokenAmount.amount, ).toFixed(8) : "" } @@ -309,7 +311,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { }} placeholder="0.00" placeholderTextColor={getColor( - isLight ? "mono-light-v2-500" : "mono-dark-v2-500" + isLight ? "mono-light-v2-500" : "mono-dark-v2-500", )} testID="payback_input_text" editable={amountToPay !== undefined} @@ -323,7 +325,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { validate: { greaterThanZero: (value: string) => new BigNumber( - value !== undefined && value !== "" ? value : 0 + value !== undefined && value !== "" ? value : 0, ).isGreaterThan(0), notSufficientFunds: (value) => new BigNumber(tokenBalance).gte(value), @@ -335,7 +337,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { new BigNumber(amountToPay).isNaN() ? new BigNumber(0) : new BigNumber(amountToPay).multipliedBy( - loanTokenActivePriceInUSD + loanTokenActivePriceInUSD, ) } style={tailwind("text-sm")} @@ -344,6 +346,7 @@ export function PaybackLoanScreen({ navigation, route }: Props): JSX.Element { /> )} @@ -467,7 +470,7 @@ function TransactionDetailsSection({ }; const loanRemaining = BigNumber.max( new BigNumber(outstandingBalance).minus(amountToPay), - 0 + 0, ); return ( void; @@ -104,7 +116,8 @@ export interface PortfolioParamList { AddOrEditAddressBookScreen: { title: string; onSaveButtonPress: (address?: string) => void; - addressLabel?: LocalAddress; + addressLabel?: WhitelistedAddress; + addressDomainType?: DomainType; address?: string; isAddNew: boolean; }; @@ -146,7 +159,8 @@ export interface PortfolioParamList { }; listType: TokenListType; list: any; - onTokenPress: (item: SelectionToken) => {}; + onTokenPress: (item: SelectionToken) => void; + isConvert?: boolean; isFutureSwap?: boolean; isSearchDTokensOnly?: boolean; }; @@ -178,6 +192,7 @@ const PortfolioStack = createStackNavigator(); export function PortfolioNavigator(): JSX.Element { const navigation = useNavigation>(); const { isLight } = useThemeContext(); + const { isEvmFeatureEnabled } = useDomainContext(); const goToNetworkSelect = (): void => { navigation.navigate("NetworkSelectionScreenPortfolio"); }; @@ -211,6 +226,7 @@ export function PortfolioNavigator(): JSX.Element { source={ isLight ? GridBackgroundImageLight : GridBackgroundImageDark } + // eslint-disable-next-line react-native/no-inline-styles style={{ height: 220, width: "100%", @@ -218,7 +234,17 @@ export function PortfolioNavigator(): JSX.Element { contentFit="cover" /> ), - headerLeft: () => , + headerLeft: () => ( + + {isEvmFeatureEnabled && } + + + + ), headerLeftContainerStyle: tailwind("pl-5", { "pb-2": Platform.OS === "ios", "pb-1.5": Platform.OS !== "ios", @@ -341,7 +367,7 @@ export function PortfolioNavigator(): JSX.Element { headerRight: () => ( ), - headerTitle: translate("screens/ConvertScreen", "Convert DFI"), + headerTitle: translate("screens/ConvertScreen", "Convert"), }} /> @@ -477,7 +503,7 @@ export function PortfolioNavigator(): JSX.Element { ), @@ -516,7 +542,7 @@ export function PortfolioNavigator(): JSX.Element { ...screenOptions, headerTitle: translate( "screens/WithdrawFutureSwapScreen", - "Withdraw" + "Withdraw", ), headerRight: () => ( @@ -557,7 +583,7 @@ export function PortfolioNavigator(): JSX.Element { ...screenOptions, headerTitle: translate( "screens/ConfirmWithdrawFutureSwapScreen", - "Confirm" + "Confirm", ), headerRight: () => ( @@ -600,7 +626,7 @@ export function PortfolioNavigator(): JSX.Element { ), headerTitle: translate( "screens/TransactionDetailScreen", - "Transaction" + "Transaction", ), }} /> @@ -611,7 +637,7 @@ export function PortfolioNavigator(): JSX.Element { ...screenOptions, headerTitle: translate( "components/UtxoVsTokenFaq", - "About UTXO And Tokens" + "About UTXO And Tokens", ), }} /> diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx index 9ba4b9227c..3f072b6e4b 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/PortfolioScreen.tsx @@ -13,18 +13,18 @@ import { import { useDisplayBalancesContext } from "@contexts/DisplayBalancesContext"; import { useWalletContext } from "@shared-contexts/WalletContext"; import { - useWalletPersistenceContext, useThemeContext, + useWalletPersistenceContext, useWhaleApiClient, useWhaleRpcClient, } from "@waveshq/walletkit-ui"; import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"; import { StackScreenProps } from "@react-navigation/stack"; import { - ocean, dexPricesSelectorByDenomination, fetchDexPrice, fetchTokens, + ocean, tokensSelector, WalletToken, } from "@waveshq/walletkit-ui/dist/store"; @@ -72,6 +72,7 @@ import { BottomSheetHeader } from "@components/BottomSheetHeader"; import * as SplashScreen from "expo-splash-screen"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; import { bottomTabDefaultRoutes } from "@screens/AppNavigator/constants/DefaultRoutes"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { AddressSelectionButtonV2 } from "./components/AddressSelectionButtonV2"; import { ActionButtons } from "./components/ActionButtons"; import { @@ -90,6 +91,7 @@ import { } from "./components/TotalPortfolio"; import { useTokenPrice } from "./hooks/TokenPrice"; import { PortfolioParamList } from "./PortfolioNavigator"; +import { useEvmTokenBalances } from "./hooks/EvmTokenBalances"; type Props = StackScreenProps; @@ -99,17 +101,18 @@ export interface PortfolioRowToken extends WalletToken { export function PortfolioScreen({ navigation }: Props): JSX.Element { const { isLight } = useThemeContext(); + const { domain } = useDomainContext(); const isFocused = useIsFocused(); const height = useBottomTabBarHeight(); const client = useWhaleApiClient(); const whaleRpcClient = useWhaleRpcClient(); - const { address, addressLength } = useWalletContext(); + const { address } = useWalletContext(); const { denominationCurrency, setDenominationCurrency } = useDenominationCurrency(); const { getTokenPrice } = useTokenPrice(denominationCurrency); const prices = useSelector((state: RootState) => - dexPricesSelectorByDenomination(state.wallet, denominationCurrency) + dexPricesSelectorByDenomination(state.wallet, denominationCurrency), ); const { wallets } = useWalletPersistenceContext(); const lockedTokens = useTokenLockedBalance({ denominationCurrency }) as Map< @@ -122,15 +125,16 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { } = useDisplayBalancesContext(); const blockCount = useSelector((state: RootState) => state.block.count); const vaults = useSelector((state: RootState) => - activeVaultsSelector(state.loans) + activeVaultsSelector(state.loans), ); const dispatch = useAppDispatch(); const [refreshing, setRefreshing] = useState(false); const [isZeroBalance, setIsZeroBalance] = useState(true); const { hasFetchedToken, allTokens } = useSelector( - (state: RootState) => state.wallet + (state: RootState) => state.wallet, ); + const { hasFetchedEvmTokens } = useSelector((state: RootState) => state.evm); const ref = useRef(null); const logger = useLogger(); useScrollToTop(ref); @@ -146,7 +150,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { fetchFutureSwaps({ client: whaleRpcClient, address, - }) + }), ); dispatch(fetchExecutionBlock({ client: whaleRpcClient })); }); @@ -167,13 +171,13 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { fetchTokens({ client, address, - }) + }), ); dispatch( fetchVaults({ client, address, - }) + }), ); }); }; @@ -185,7 +189,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { fetchDexPrice({ client, denomination: denominationCurrency, - }) + }), ); }, [blockCount, denominationCurrency]); @@ -196,21 +200,22 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { }, [address, client, dispatch]); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); + const { evmTokens } = useEvmTokenBalances(); const { totalAvailableValue, dstTokens } = useMemo(() => { - return tokens.reduce( + return (domain === DomainType.EVM ? evmTokens : tokens).reduce( ( { totalAvailableValue, dstTokens, }: { totalAvailableValue: BigNumber; dstTokens: PortfolioRowToken[] }, - token + token, ) => { const usdAmount = getTokenPrice( token.symbol, new BigNumber(token.amount), - token.isLPS + token.isLPS, ); if (token.symbol === "DFI") { return { @@ -224,7 +229,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { } return { totalAvailableValue: totalAvailableValue.plus( - usdAmount.isNaN() ? 0 : usdAmount + usdAmount.isNaN() ? 0 : usdAmount, ), dstTokens: [ ...dstTokens, @@ -238,9 +243,9 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { { totalAvailableValue: new BigNumber(0), dstTokens: [], - } + }, ); - }, [prices, tokens]); + }, [prices, tokens, domain, evmTokens]); // add token that are 100% locked as collateral into dstTokens const combinedTokens = useMemo(() => { @@ -281,7 +286,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { const [filteredTokens, setFilteredTokens] = useState(combinedTokens); // portfolio tab items const onPortfolioButtonGroupChange = ( - portfolioButtonGroupTabKey: PortfolioButtonGroupTabKey + portfolioButtonGroupTabKey: PortfolioButtonGroupTabKey, ): void => { setDenominationCurrency(portfolioButtonGroupTabKey); }; @@ -327,7 +332,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { // Asset sort bottom sheet list const [assetSortType, setAssetSortType] = useState( - PortfolioSortType.HighestDenominationValue + PortfolioSortType.HighestDenominationValue, ); // to display selected sorted type text const [isSorted, setIsSorted] = useState(false); // to display acsending/descending icon const [showAssetSortBottomSheet, setShowAssetSortBottomSheet] = @@ -336,7 +341,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { (assetSortType: PortfolioSortType): PortfolioRowToken[] => { let sortTokensFunc: ( a: PortfolioRowToken, - b: PortfolioRowToken + b: PortfolioRowToken, ) => number; switch (assetSortType) { case PortfolioSortType.HighestDenominationValue: @@ -365,16 +370,21 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { return filteredTokens.sort(sortTokensFunc); }, - [filteredTokens, assetSortType, denominationCurrency] + [domain, filteredTokens, assetSortType, denominationCurrency], ); useEffect(() => { setAssetSortType(PortfolioSortType.HighestDenominationValue); // reset sorting state upon denominationCurrency change }, [denominationCurrency]); + // Reset button group in EVM domain + useEffect(() => { + setActiveButtonGroup(ButtonGroupTabKey.AllTokens); + }, [domain]); + // token tab items const [activeButtonGroup, setActiveButtonGroup] = useState( - ButtonGroupTabKey.AllTokens + ButtonGroupTabKey.AllTokens, ); const handleButtonFilter = useCallback( (buttonGroupTabKey: ButtonGroupTabKey) => { @@ -393,7 +403,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { }); setFilteredTokens(filterTokens); }, - [combinedTokens] + [combinedTokens], ); const totalLockedValue = useMemo(() => { @@ -403,7 +413,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { return [...lockedTokens.values()].reduce( (totalLockedValue: BigNumber, value: LockedBalance) => totalLockedValue.plus(value.tokenValue.isNaN() ? 0 : value.tokenValue), - new BigNumber(0) + new BigNumber(0), ); }, [lockedTokens, prices]); @@ -417,19 +427,21 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { (totalVaultLoansValue, loanToken) => { const tokenValue = getTokenPrice( loanToken.symbol, - new BigNumber(loanToken.amount) + new BigNumber(loanToken.amount), ); return totalVaultLoansValue.plus( - new BigNumber(tokenValue).isNaN() ? 0 : tokenValue + new BigNumber(tokenValue).isNaN() ? 0 : tokenValue, ); }, - new BigNumber(0) + new BigNumber(0), ); return totalLoansValue.plus( - new BigNumber(totalVaultLoansValue).isNaN() ? 0 : totalVaultLoansValue + new BigNumber(totalVaultLoansValue).isNaN() + ? 0 + : totalVaultLoansValue, ); }, - new BigNumber(0) + new BigNumber(0), ); }, [prices, vaults]); @@ -440,7 +452,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { useEffect(() => { setIsZeroBalance( - !tokens.some((token) => new BigNumber(token.amount).isGreaterThan(0)) + !tokens.some((token) => new BigNumber(token.amount).isGreaterThan(0)), ); }, [tokens]); @@ -513,15 +525,49 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { "bg-mono-light-v2-100": isLight, "bg-mono-dark-v2-100": !isLight, }), - headerRight: (): JSX.Element => { + header: (): JSX.Element => { return ( - dismissModal(false)} - testID="close_bottom_sheet_button" + - - + + + + + {domain} + + + {translate("screens/PortfolioScreen", "network")} + + + + dismissModal(false)} + testID="close_bottom_sheet_button" + > + + + ); }, }; @@ -530,7 +576,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { navigation.dispatch( CommonActions.reset({ routes: bottomTabDefaultRoutes, - }) + }), ); }; @@ -566,7 +612,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { }, }, ]; - }, [address, isLight]); + }, [address, isLight, domain]); // Hide splashscreen when first page is loaded to prevent white screen // It is wrapped on a timeout so it will execute once the JS stack is cleared up @@ -591,11 +637,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { dark={tailwind("bg-mono-dark-v2-00")} style={tailwind("px-5 flex flex-row items-center")} > - expandModal(false)} - /> + expandModal(false)} /> @@ -623,11 +665,14 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { /> - + + {domain === DomainType.DVM && ( + + )} {/* to show bottom sheet for asset sort */} {activeButtonGroup === ButtonGroupTabKey.AllTokens && ( )} - {!hasFetchedToken ? ( + {!hasFetchedToken || + (domain === DomainType.EVM && !hasFetchedEvmTokens) ? ( @@ -656,6 +703,7 @@ export function PortfolioScreen({ navigation }: Props): JSX.Element { onButtonGroupPress: handleButtonFilter, }} denominationCurrency={denominationCurrency} + isEvmDomain={domain === DomainType.EVM} /> )} {Platform.OS === "web" ? ( @@ -702,16 +750,17 @@ function AssetSortRow(props: { assetSortType: PortfolioSortType; denominationCurrency: string; onPress: () => void; + isEvmDomain: boolean; }): JSX.Element { const highestCurrencyValue = translate( "screens/PortfolioScreen", "Highest value ({{denominationCurrency}})", - { denominationCurrency: props.denominationCurrency } + { denominationCurrency: props.denominationCurrency }, ); const lowestCurrencyValue = translate( "screens/PortfolioScreen", "Lowest value ({{denominationCurrency}})", - { denominationCurrency: props.denominationCurrency } + { denominationCurrency: props.denominationCurrency }, ); const getDisplayedSortText = (text: PortfolioSortType): string => { if (text === PortfolioSortType.HighestDenominationValue) { @@ -724,7 +773,9 @@ function AssetSortRow(props: { return ( {translate("screens/PortfolioScreen", "ASSETS")} - - - {translate( - "screens/PortfolioScreen", - props.isSorted - ? getDisplayedSortText(props.assetSortType) - : "Sort by" - )} - - - + + {translate( + "screens/PortfolioScreen", + props.isSorted + ? getDisplayedSortText(props.assetSortType) + : "Sort by", + )} + + + + )} ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/assets/EmptyEvmPortfolioIcon.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/assets/EmptyEvmPortfolioIcon.tsx new file mode 100644 index 0000000000..e0c0a59456 --- /dev/null +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/assets/EmptyEvmPortfolioIcon.tsx @@ -0,0 +1,89 @@ +import Svg, { + Ellipse, + Path, + LinearGradient, + G, + Stop, + Defs, + Rect, + ClipPath, +} from "react-native-svg"; + +export function EmptyEvmPortfolioIcon(): JSX.Element { + const GElement = G as any; + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.test.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.test.tsx index 8d1699a45d..1b39090a95 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.test.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.test.tsx @@ -4,14 +4,22 @@ import { configureStore } from "@reduxjs/toolkit"; import { RootState } from "@store"; import { setTokenSymbol, wallet } from "@waveshq/walletkit-ui/dist/store"; import { futureSwaps } from "@store/futureSwap"; +import { StoreProvider } from "@contexts/StoreProvider"; import { ActionButtons } from "./ActionButtons"; jest.mock("@contexts/FeatureFlagContext"); +jest.mock("@contexts/DomainContext"); + jest.mock("@react-navigation/native", () => ({ useNavigation: jest.fn(), })); -describe("DFI Action Buttons", () => { +jest.mock("react-native/Libraries/Utilities/Platform", () => ({ + OS: "web", + select: () => jest.fn, +})); + +describe.skip("DFI Action Buttons", () => { it("should match snapshot for Action Buttons component", async () => { const initialState: Partial = { futureSwaps: { @@ -51,9 +59,11 @@ describe("DFI Action Buttons", () => { }); const rendered = render( - - - + + + + + , ); expect(rendered.toJSON()).toMatchSnapshot(); }); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.tsx index fa1eb8e089..18823667a7 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/ActionButtons.tsx @@ -17,10 +17,18 @@ import { getColor, tailwind } from "@tailwind"; import { translate } from "@translations"; import { ScrollView, Text, View } from "react-native"; import { useSelector } from "react-redux"; +import { useDomainContext, DomainType } from "@contexts/DomainContext"; import { getNativeIcon } from "@components/icons/assets"; import { useThemeContext } from "@waveshq/walletkit-ui"; import BigNumber from "bignumber.js"; +import { ConvertIcon } from "@components/icons/assets/ConvertIcon"; +import { ConvertDirection } from "@screens/enum"; import { PortfolioParamList } from "../PortfolioNavigator"; +import { + SelectionToken, + TokenListType, +} from "../../Dex/CompositeSwap/SwapTokenSelectionScreen"; +import { useTokenBalance } from "../hooks/TokenBalance"; export interface ActionButtonsProps { name: string; @@ -30,35 +38,115 @@ export interface ActionButtonsProps { onPress: () => void; testID: string; badge?: string | number; + isEvmDomain?: boolean; } export function ActionButtons(): JSX.Element { const { isFeatureAvailable } = useFeatureFlagContext(); + const { domain, isEvmFeatureEnabled } = useDomainContext(); + const isEvmDomain = domain === DomainType.EVM; + + const { dvmTokens, evmTokens } = useTokenBalance(); + const navigation = useNavigation>(); const futureSwaps = useSelector((state: RootState) => - futureSwapSelector(state) + futureSwapSelector(state), ); const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const hasDFIBalance = hasFetchedToken && new BigNumber(DFIUtxo.amount ?? 0).plus(DFIToken.amount ?? 0).gt(0); + const getConvertDirection = (tokenId: string) => { + if (domain === DomainType.DVM && tokenId === "0") { + return ConvertDirection.accountToUtxos; + } else if (domain === DomainType.DVM && tokenId === "0_utxo") { + return ConvertDirection.utxosToAccount; + } + + return domain === DomainType.EVM + ? ConvertDirection.evmToDvm + : ConvertDirection.dvmToEvm; + }; + + const navigateToTokenSelectionScreen = (listType: TokenListType): void => { + navigation.navigate("SwapTokenSelectionScreen", { + fromToken: { + symbol: undefined, + displaySymbol: undefined, + }, + listType: listType, + list: domain === DomainType.EVM ? evmTokens : dvmTokens, + onTokenPress: (item) => { + const defaultTargetToken = { + tokenId: + domain === DomainType.DVM + ? `${item.tokenId}_evm` + : item.tokenId.replace("_evm", ""), + available: new BigNumber(0), + token: { + ...item.token, + name: + domain === DomainType.DVM + ? `${item.token.name} for EVM` + : item.token.name, + domainType: DomainType.EVM, + }, + }; + + let targetToken: SelectionToken | undefined; + if (domain === DomainType.DVM && item.tokenId === "0_utxo") { + // If DFI UTXO -> choose DFI Token + targetToken = dvmTokens.find((token) => token.tokenId === "0"); + } else if (domain === DomainType.DVM && item.tokenId === "0") { + // If DFI Token -> no default + targetToken = undefined; + } else if (domain === DomainType.EVM) { + // If EVM -> choose DVM equivalent + targetToken = + dvmTokens.find( + (token) => token.tokenId === item.tokenId.replace("_evm", ""), + ) ?? defaultTargetToken; + } else if (domain === DomainType.DVM) { + // If DVM -> choose EVM equivalent + targetToken = + evmTokens.find( + (token) => token.tokenId === `${item.tokenId}_evm`, + ) ?? defaultTargetToken; + } + + navigation.navigate({ + name: "ConvertScreen", + params: { + sourceToken: item, + targetToken, + convertDirection: getConvertDirection(item.tokenId), + }, + merge: true, + }); + }, + isFutureSwap: false, + isSearchDTokensOnly: false, + }); + }; + return ( - {hasDFIBalance && ( + {hasDFIBalance && !isEvmDomain && ( navigation.navigate("Receive")} /> - {isFeatureAvailable("future_swap") && futureSwaps.length > 0 && ( + {!isEvmDomain && ( 9 ? "9+" : futureSwaps.length} - testID="future_swap_button" - onPress={() => navigation.navigate("FutureSwapScreen")} + testID="swap_tokens_button" + onPress={() => + navigation.navigate({ + name: "CompositeSwap", + params: {}, + merge: true, + }) + } /> )} - - navigation.navigate({ - name: "CompositeSwap", - params: {}, - merge: true, - }) - } - /> - {isFeatureAvailable("ocg_cfp_dfip") && ( + {isEvmFeatureEnabled && ( navigation.navigate("OCGProposalsScreen")} + name={translate("components/ActionButtons", "Convert")} + iconSize={28} + testID="convert_action_button" + onPress={() => { + navigateToTokenSelectionScreen(TokenListType.From); + }} + isEvmDomain /> )} - navigation.navigate("TransactionsScreen")} - /> + + {!isEvmDomain && ( + <> + {isFeatureAvailable("future_swap") && futureSwaps.length > 0 && ( + 9 ? "9+" : futureSwaps.length} + testID="future_swap_button" + onPress={() => navigation.navigate("FutureSwapScreen")} + /> + )} + + {isFeatureAvailable("ocg_cfp_dfip") && ( + navigation.navigate("OCGProposalsScreen")} + /> + )} + navigation.navigate("TransactionsScreen")} + /> + + )} ); @@ -141,17 +248,30 @@ function ActionButton(props: ActionButtonsProps): JSX.Element { dark={tailwind("bg-mono-dark-v2-00")} light={tailwind("bg-mono-light-v2-00")} style={tailwind( - "rounded-full w-15 h-15 items-center justify-center mx-2.5" + "rounded-full w-15 h-15 items-center justify-center mx-2.5", )} onPress={props.onPress} testID={props.testID} > {props.iconType === undefined ? ( - + <> + {props.isEvmDomain ? ( + + ) : ( + + )} + ) : ( { @@ -12,15 +13,15 @@ describe("Address List Edit Button", () => { addresses: { foo: { address: "foo", + evmAddress: "", label: "foo", - isMine: true, }, }, addressBook: { bar: { address: "bar", label: "bar", - isMine: false, + addressDomainType: DomainType.DVM, }, }, }, @@ -33,7 +34,7 @@ describe("Address List Edit Button", () => { const rendered = render( - + , ); expect(rendered.toJSON()).toMatchSnapshot(); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressRow.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressRow.tsx index 387d54d183..fbe213250f 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressRow.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressRow.tsx @@ -8,17 +8,27 @@ import { ThemedTouchableOpacity, ThemedViewV2, } from "@components/themed"; -import { RandomAvatar } from "@screens/AppNavigator/screens/Portfolio/components/RandomAvatar"; import { WalletTextInputV2 } from "@components/WalletTextInputV2"; import { Control, Controller } from "react-hook-form"; import { NetworkName } from "@defichain/jellyfish-network"; import { fromAddress } from "@defichain/jellyfish-address"; -import { LocalAddress } from "@store/userPreferences"; +import { + LocalAddress, + selectAllLabeledWalletAddress, + WhitelistedAddress, +} from "@store/userPreferences"; import { debounce } from "lodash"; import { useEffect, useMemo, useState } from "react"; import { useSelector } from "react-redux"; import { RootState } from "@store"; -import { useWalletAddress } from "@hooks/useWalletAddress"; +import { useWalletAddress, WalletAddressI } from "@hooks/useWalletAddress"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { + AddressType as JellyfishAddressType, + getAddressType, +} from "@waveshq/walletkit-core"; +import { RandomAvatar } from "@screens/AppNavigator/screens/Portfolio/components/RandomAvatar"; +import { AddressEvmTag } from "@components/AddressEvmTag"; export function AddressRow({ control, @@ -34,6 +44,9 @@ export function AddressRow({ onAddressType, showQrButton = true, onlyLocalAddress, + matchedAddress, + setMatchedAddress, + setAddressLabel, }: { control: Control; networkName: NetworkName; @@ -44,27 +57,34 @@ export function AddressRow({ inputFooter?: React.ReactElement; title: string; address: string; - onMatchedAddress?: (matchedAddress?: LocalAddress) => void; + onMatchedAddress?: ( + matchedAddress?: LocalAddress | WhitelistedAddress, + ) => void; onAddressType?: (addressType?: AddressType) => void; showQrButton?: boolean; onlyLocalAddress?: boolean; + matchedAddress?: LocalAddress | WhitelistedAddress | undefined; + setMatchedAddress?: (address?: LocalAddress | WhitelistedAddress) => void; + setAddressLabel?: React.Dispatch>; }): JSX.Element { const { fetchWalletAddresses } = useWalletAddress(); + const { domain } = useDomainContext(); const defaultValue = ""; const addressBook = useSelector( - (state: RootState) => state.userPreferences.addressBook + (state: RootState) => state.userPreferences.addressBook, ); - const walletAddress = useSelector( - (state: RootState) => state.userPreferences.addresses + const walletAddress = useSelector((state: RootState) => + selectAllLabeledWalletAddress(state.userPreferences), ); const [jellyfishWalletAddress, setJellyfishWalletAddresses] = useState< - string[] + WalletAddressI[] >([]); - const [matchedAddress, setMatchedAddress] = useState(); const [addressType, setAddressType] = useState(); + const [validEvmAddress, setValidEvmAddress] = useState(false); + const validLocalAddress = useMemo(() => { if (address === "") { return true; @@ -75,53 +95,75 @@ export function AddressRow({ return true; }, [onlyLocalAddress, addressType, address]); + const addressObj = jellyfishWalletAddress.find( + (e: WalletAddressI) => e.dvm === address || e.evm === address, + ); + + const displayAddressLabel = + matchedAddress?.label !== "" + ? matchedAddress?.label + : addressObj?.generatedLabel; + const debounceMatchAddress = debounce(() => { - if ( - address !== undefined && - addressBook !== undefined && - addressBook[address] !== undefined - ) { - setMatchedAddress(addressBook[address]); - setAddressType(AddressType.Whitelisted); - } else if ( - address !== undefined && - walletAddress !== undefined && - walletAddress[address] !== undefined - ) { - setMatchedAddress(walletAddress[address]); - setAddressType(AddressType.WalletAddress); - } else if ( - address !== undefined && - jellyfishWalletAddress.includes(address) - ) { - // wallet address that does not have a label - setMatchedAddress({ - address, - label: "", - isMine: true, - }); - setAddressType(AddressType.WalletAddress); - } else { - setMatchedAddress(undefined); - if (onlyLocalAddress) { - setAddressType(undefined); + // Check if address input field is not empty + if (address !== undefined && setMatchedAddress !== undefined) { + if (addressBook !== undefined && addressBook[address] !== undefined) { + // Whitelisted Addresses + setMatchedAddress(addressBook[address]); + setAddressType(AddressType.Whitelisted); + return; + } + + // Your Address - Labelled + if (walletAddress !== undefined && walletAddress[address] !== undefined) { + setMatchedAddress(walletAddress[address]); + setAddressType(AddressType.WalletAddress); + return; + } + + if (addressObj) { + // Your addresses - Unlabelled + setMatchedAddress({ + address: addressObj.dvm, + evmAddress: addressObj.evm, + label: "", + }); + setAddressType(AddressType.WalletAddress); } else { - setAddressType( - fromAddress(address, networkName) !== undefined - ? AddressType.OthersButValid - : undefined - ); + setMatchedAddress(undefined); // Unsaved valid DVM address + if (onlyLocalAddress) { + setAddressType(undefined); + } else if ( + getAddressType(address, networkName) === JellyfishAddressType.ETH + ) { + // Unsaved and valid EVM address + setAddressType(AddressType.OthersButValid); + setValidEvmAddress(true); + } else { + setValidEvmAddress(false); + setAddressType( + fromAddress(address, networkName) !== undefined + ? AddressType.OthersButValid + : undefined, + ); + } } } }, 200); + useEffect(() => { + if (setAddressLabel !== undefined) { + setAddressLabel(displayAddressLabel); + } + }, [displayAddressLabel]); + useEffect(() => { debounceMatchAddress(); }, [address, addressBook]); useEffect(() => { - void fetchWalletAddresses().then((walletAddresses) => - setJellyfishWalletAddresses(walletAddresses) + fetchWalletAddresses().then((walletAddresses) => + setJellyfishWalletAddresses(walletAddresses), ); }, [fetchWalletAddresses]); @@ -215,7 +257,7 @@ export function AddressRow({ > {translate( "screens/SendScreen", - "Invalid address. Make sure the address is correct to avoid irrecoverable losses" + "Invalid address. Make sure the address is correct to avoid irrecoverable losses", )} )} @@ -226,77 +268,122 @@ export function AddressRow({ required: true, validate: { isValidAddress: (address) => - fromAddress(address, networkName) !== undefined && - (!onlyLocalAddress || - jellyfishWalletAddress.includes(address) || - (walletAddress !== undefined && - walletAddress[address] !== undefined)), + // Check if its either a valid EVM/DVM address && + !!getAddressType(address, networkName) && + // EVM -> EVM domain transfer is not allowed + !( + getAddressType(address, networkName) === + JellyfishAddressType.ETH && domain === DomainType.EVM + ), }, }} /> - {addressType !== undefined && ( - - {addressType === AddressType.OthersButValid ? ( - <> - - - {translate("screens/SendScreen", "Verified")} - - - ) : ( - addressType !== undefined && - validLocalAddress && ( - - {addressType === AddressType.WalletAddress && ( - - - - )} + + {addressType !== undefined && ( + <> + {/* Verified tag for unsaved but verified DVM/EVM address */} + {addressType === AddressType.OthersButValid && + !( + domain === DomainType.EVM && + getAddressType(address, networkName) === + JellyfishAddressType.ETH + ) && ( + <> + + + {translate("screens/SendScreen", "Verified {{text}}", { + text: validEvmAddress + ? "MetaChain (EVM) address" + : "DVM address", + })} + + + )} - - {matchedAddress?.label !== "" - ? matchedAddress?.label - : matchedAddress.address} - - - ) - )} - - )} + {/* Whitelisted and Yours Addresses */} + {addressType !== AddressType.OthersButValid && + validLocalAddress && ( + <> + {/* Checks if selected address is a Whitelisted EVM address */} + {(matchedAddress as WhitelistedAddress)?.addressDomainType === + DomainType.EVM || + // Check if selected address from Your Addresses is EVM address + getAddressType(address, networkName) === + JellyfishAddressType.ETH ? ( + + <> + {addressType === AddressType.WalletAddress && ( + + + + )} + + {displayAddressLabel} + + + + ) : ( + // Whitelisted address - DVM + + {addressType === AddressType.WalletAddress && ( + + + + )} + + {displayAddressLabel} + + + )} + + )} + + )} + ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButton.test.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButton.test.tsx index 3b51ccc184..2866c4a36a 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButton.test.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButton.test.tsx @@ -3,6 +3,7 @@ import { RootState } from "@store"; import { userPreferences } from "@store/userPreferences"; import { render } from "@testing-library/react-native"; import { Provider } from "react-redux"; +import { DomainType } from "@contexts/DomainContext"; import { AddressSelectionButton } from "./AddressSelectionButton"; describe("Address Selection Button", () => { @@ -13,15 +14,15 @@ describe("Address Selection Button", () => { addresses: { foo: { address: "foo", + evmAddress: "", label: "foo", - isMine: true, }, }, addressBook: { bar: { address: "bar", label: "bar", - isMine: false, + addressDomainType: DomainType.DVM, }, }, }, @@ -39,7 +40,7 @@ describe("Address Selection Button", () => { onPress={onPress} hasCount /> - + , ); expect(rendered.toJSON()).toMatchSnapshot(); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButtonV2.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButtonV2.tsx index 6f046c97fa..d81b9d506f 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButtonV2.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/AddressSelectionButtonV2.tsx @@ -5,19 +5,55 @@ import { } from "@components/themed"; import { tailwind } from "@tailwind"; import { useAddressLabel } from "@hooks/useAddressLabel"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { useWalletContext } from "@shared-contexts/WalletContext"; +import { useSelector } from "react-redux"; +import { RootState } from "@store"; +import { useEffect, useState } from "react"; +import { useWalletAddress, WalletAddressI } from "@hooks/useWalletAddress"; +import { useLogger } from "@shared-contexts/NativeLoggingProvider"; import { RandomAvatar } from "./RandomAvatar"; interface AddressSelectionButtonProps { - address: string; - addressLength: number; onPress?: () => void; disabled?: boolean; } export function AddressSelectionButtonV2( - props: AddressSelectionButtonProps + props: AddressSelectionButtonProps, ): JSX.Element { - const addressLabel = useAddressLabel(props.address); + const { domain } = useDomainContext(); + const { address, evmAddress } = useWalletContext(); + const displayAddress = domain === DomainType.EVM ? evmAddress : address; + const activeLabel = useAddressLabel(displayAddress); + const { fetchWalletAddresses } = useWalletAddress(); + + const userPreferences = useSelector( + (state: RootState) => state.userPreferences, + ); + const labeledAddresses = userPreferences.addresses; + const logger = useLogger(); + + const [availableAddresses, setAvailableAddresses] = useState< + WalletAddressI[] + >([]); + + // Getting addresses + const fetchAddresses = async (): Promise => { + const addresses = await fetchWalletAddresses(); + setAvailableAddresses(addresses); + }; + + const activeAddress = availableAddresses.find(({ dvm }) => dvm === address); + const displayAddressLabel = + activeLabel === null + ? activeAddress?.generatedLabel + : labeledAddresses?.[address]?.label; + + useEffect(() => { + fetchAddresses().catch(logger.error); + }, [address]); + return ( - + - {addressLabel != null ? addressLabel : props.address} + {displayAddressLabel} ); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressBook.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressBook.tsx deleted file mode 100644 index b96d4ec009..0000000000 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressBook.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import { View } from "@components"; -import { - ThemedFlatList, - ThemedIcon, - ThemedText, - ThemedTouchableOpacity, - ThemedView, -} from "@components/themed"; -import { translate } from "@translations"; -import React, { memo, useCallback, useMemo, useState } from "react"; -import { Platform, TouchableOpacity } from "react-native"; -import { tailwind } from "@tailwind"; -import { BottomSheetFlatList } from "@gorhom/bottom-sheet"; -import { useNetworkContext, useThemeContext } from "@waveshq/walletkit-ui"; -import { useSelector } from "react-redux"; -import { RootState } from "@store"; -import { - hasTxQueued, - hasOceanTXQueued, -} from "@waveshq/walletkit-ui/dist/store"; -import { NavigationProp, useNavigation } from "@react-navigation/native"; -import { BottomSheetWithNavRouteParam } from "@components/BottomSheetWithNav"; -import { - LabeledAddress, - setAddressBook, - setUserPreferences, -} from "@store/userPreferences"; -import { useAppDispatch } from "@hooks/useAppDispatch"; -import { RandomAvatar } from "./RandomAvatar"; - -interface BottomSheetAddressBookProps { - address: string; - onAddressSelect: (address: string) => void; - onCloseButtonPress: () => void; - navigateToScreen: { - screenName: string; - }; -} - -export const BottomSheetAddressBook = ( - props: BottomSheetAddressBookProps -): React.MemoExoticComponent<() => JSX.Element> => - memo(() => { - const { isLight } = useThemeContext(); - const flatListComponents = { - mobile: BottomSheetFlatList, - web: ThemedFlatList, - }; - const FlatList = - Platform.OS === "web" - ? flatListComponents.web - : flatListComponents.mobile; - const dispatch = useAppDispatch(); - const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) - ); - const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) - ); - const [isEditing, setIsEditing] = useState(false); - const navigation = - useNavigation>(); - const { network } = useNetworkContext(); - const userPreferences = useSelector( - (state: RootState) => state.userPreferences - ); - const addressBook = userPreferences.addressBook; - - const addresses = useMemo((): string[] => { - if (addressBook === undefined) { - return []; - } - - return Object.keys(addressBook); - }, [addressBook]); - - const FooterComponent = useMemo(() => { - return ( - { - navigation.navigate({ - name: props.navigateToScreen.screenName, - params: { - title: "Add new address", - isAddressBook: true, - index: addresses.length + 1, - onSaveButtonPress: (labelAddress: LabeledAddress) => { - dispatch(setAddressBook(labelAddress)).then(() => { - const addresses = { ...addressBook, ...labelAddress }; - dispatch( - setUserPreferences({ - network, - preferences: { - ...userPreferences, - addressBook: addresses, - }, - }) - ); - }); - navigation.goBack(); - setIsEditing(false); - }, - }, - merge: true, - }); - }} - testID="add_new_address" - > - - - - - - {translate( - "components/BottomSheetAddressBook", - "ADD NEW ADDRESS" - )} - - - - - ); - }, [addresses, addressBook]); - - const onChangeAddress = (address: string): void => { - if (hasPendingJob || hasPendingBroadcastJob) { - return; - } - props.onAddressSelect(address); - }; - - const HeaderComponent = useMemo(() => { - return ( - - - - {translate("components/BottomSheetAddressBook", "Address book")} - - - - - - - - - - ); - }, [isEditing, addresses]); - - const AddressListItem = useCallback( - // eslint-disable-next-line react/no-unused-prop-types - ({ item, index }: { item: string; index: number }): JSX.Element => { - return ( - { - onChangeAddress(item); - }} - testID={`address_row_${index}`} - disabled={hasPendingJob || hasPendingBroadcastJob} - > - - - - {addressBook?.[item]?.label != null && - addressBook?.[item]?.label !== "" && ( - - {addressBook[item]?.label} - - )} - - {item} - - - - - ); - }, - [isEditing, addressBook] - ); - - return ( - item} - stickyHeaderIndices={[0]} - style={tailwind({ - "bg-gray-800": !isLight, - "bg-white": isLight, - })} - data={addresses} - renderItem={AddressListItem} - ListHeaderComponent={HeaderComponent} - ListFooterComponent={FooterComponent} - /> - ); - }); - -function WalletCounterDisplay({ - addressLength, -}: { - addressLength: number; -}): JSX.Element { - return ( - - {translate( - "components/BottomSheetAddressBook", - "{{length}} ADDRESS(ES)", - { length: addressLength } - )} - - ); -} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetail.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetail.tsx deleted file mode 100644 index b11263efd9..0000000000 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetail.tsx +++ /dev/null @@ -1,498 +0,0 @@ -import { View } from "@components"; -import { - ThemedFlatList, - ThemedIcon, - ThemedText, - ThemedTouchableOpacity, - ThemedView, -} from "@components/themed"; -import { translate } from "@translations"; -import React, { memo, useCallback, useEffect, useState } from "react"; -import { Platform, TouchableOpacity } from "react-native"; -import { tailwind } from "@tailwind"; -import { openURL } from "@api/linking"; -import { useDeFiScanContext } from "@shared-contexts/DeFiScanContext"; -import { IconButton } from "@components/IconButton"; -import { useToast } from "react-native-toast-notifications"; -import { debounce } from "lodash"; -import * as Clipboard from "expo-clipboard"; -import { - MAX_ALLOWED_ADDRESSES, - useWalletContext, -} from "@shared-contexts/WalletContext"; -import { useLogger } from "@shared-contexts/NativeLoggingProvider"; -import { BottomSheetFlatList } from "@gorhom/bottom-sheet"; -import { useThemeContext, useNetworkContext } from "@waveshq/walletkit-ui"; -import { - wallet as walletReducer, - hasTxQueued, - hasOceanTXQueued, -} from "@waveshq/walletkit-ui/dist/store"; -import { useSelector } from "react-redux"; -import { loans } from "@store/loans"; -import { RootState } from "@store"; -import { NavigationProp, useNavigation } from "@react-navigation/native"; -import { BottomSheetWithNavRouteParam } from "@components/BottomSheetWithNav"; -import { - LabeledAddress, - setAddresses, - setUserPreferences, -} from "@store/userPreferences"; -import { useAddressLabel } from "@hooks/useAddressLabel"; -import { useAppDispatch } from "@hooks/useAppDispatch"; -import { useWalletAddress } from "@hooks/useWalletAddress"; -import { AddressListEditButton } from "./AddressListEditButton"; -import { RandomAvatar } from "./RandomAvatar"; - -interface BottomSheetAddressDetailProps { - address: string; - addressLabel: string; - onReceiveButtonPress: () => void; - onTransactionsButtonPress: () => void; - onCloseButtonPress: () => void; - navigateToScreen: { - screenName: string; - }; -} - -export const BottomSheetAddressDetail = ( - props: BottomSheetAddressDetailProps -): React.MemoExoticComponent<() => JSX.Element> => - memo(() => { - const { isLight } = useThemeContext(); - const flatListComponents = { - mobile: BottomSheetFlatList, - web: ThemedFlatList, - }; - const FlatList = - Platform.OS === "web" - ? flatListComponents.web - : flatListComponents.mobile; - const { - addressLength, - setIndex, - wallet, - activeAddressIndex, - discoverWalletAddresses, - } = useWalletContext(); - const toast = useToast(); - const [showToast, setShowToast] = useState(false); - const TOAST_DURATION = 2000; - const [availableAddresses, setAvailableAddresses] = useState([]); - const [canCreateAddress, setCanCreateAddress] = useState(false); - const logger = useLogger(); - const { fetchWalletAddresses } = useWalletAddress(); - const dispatch = useAppDispatch(); - const blockCount = useSelector((state: RootState) => state.block.count); - const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) - ); - const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) - ); - const [isEditing, setIsEditing] = useState(false); - const navigation = - useNavigation>(); - const { network } = useNetworkContext(); - const userPreferences = useSelector( - (state: RootState) => state.userPreferences - ); - const labeledAddresses = userPreferences.addresses; - const activeLabel = useAddressLabel(props.address); - - const onActiveAddressPress = useCallback( - debounce(() => { - if (showToast) { - return; - } - setShowToast(true); - setTimeout(() => setShowToast(false), TOAST_DURATION); - }, 500), - [showToast] - ); - - useEffect(() => { - if (showToast) { - Clipboard.setString(props.address); - toast.show(translate("components/toaster", "Copied"), { - type: "wallet_toast", - placement: "top", - duration: TOAST_DURATION, - }); - } else { - toast.hideAll(); - } - }, [showToast, props.address]); - - // Getting addresses - const fetchAddresses = async (): Promise => { - const addresses = await fetchWalletAddresses(); - setAvailableAddresses(addresses); - await isNextAddressUsable(); - }; - - const isNextAddressUsable = async (): Promise => { - // incremented 1 to check if next account in the wallet is usable. - const next = addressLength + 1; - const isUsable = await wallet.isUsable(next); - setCanCreateAddress(isUsable && MAX_ALLOWED_ADDRESSES > next); - }; - - useEffect(() => { - fetchAddresses().catch(logger.error); - }, [wallet, addressLength]); - - useEffect(() => { - isNextAddressUsable().catch(logger.error); - }, [blockCount]); - - const CreateAddress = useCallback(() => { - if (!canCreateAddress || isEditing) { - return <>; - } - - return ( - { - await onChangeAddress(addressLength + 1); - }} - testID="create_new_address" - > - - - - - - {translate( - "components/BottomSheetAddressDetail", - "CREATE WALLET ADDRESS" - )} - - - - - ); - }, [canCreateAddress, addressLength, isEditing]); - - const onChangeAddress = async (index: number): Promise => { - if ( - hasPendingJob || - hasPendingBroadcastJob || - index === activeAddressIndex - ) { - return; - } - - dispatch(walletReducer.actions.setHasFetchedToken(false)); - dispatch(loans.actions.setHasFetchedVaultsData(false)); - await setIndex(index); - props.onCloseButtonPress(); - }; - - const AddressListItem = useCallback( - // eslint-disable-next-line react/no-unused-prop-types - ({ item, index }: { item: string; index: number }): JSX.Element => { - return ( - { - if (isEditing) { - navigation.navigate({ - name: props.navigateToScreen.screenName, - params: { - title: "Edit address label", - isAddressBook: false, - address: item, - addressLabel: - labeledAddresses != null ? labeledAddresses[item] : "", - index: index + 1, - type: "edit", - onSaveButtonPress: (labelAddress: LabeledAddress) => { - const addresses = { - ...labeledAddresses, - ...labelAddress, - }; - dispatch(setAddresses(addresses)).then(() => { - dispatch( - setUserPreferences({ - network, - preferences: { - ...userPreferences, - addresses, - }, - }) - ); - }); - navigation.goBack(); - setIsEditing(false); - }, - }, - merge: true, - }); - } else { - await onChangeAddress(index); - } - }} - testID={`address_row_${index}`} - disabled={hasPendingJob || hasPendingBroadcastJob} - > - - - - {labeledAddresses?.[item]?.label != null && - labeledAddresses?.[item]?.label !== "" && ( - - {labeledAddresses[item]?.label} - - )} - - {item} - - - {isEditing ? ( - - ) : item === props.address ? ( - - ) : ( - - )} - - - ); - }, - [isEditing, labeledAddresses] - ); - - const AddressDetail = useCallback(() => { - return ( - - - - - - - - {activeLabel != null && ( - - - {activeLabel} - - - )} - - - - - - - - setIsEditing(!isEditing)} - /> - - - ); - }, [props, addressLength, isEditing, activeLabel]); - - return ( - item} - stickyHeaderIndices={[0]} - style={tailwind({ - "bg-gray-800": !isLight, - "bg-white": isLight, - })} - data={availableAddresses} - renderItem={AddressListItem} - ListHeaderComponent={AddressDetail} - ListFooterComponent={CreateAddress} - /> - ); - }); - -function ActiveAddress({ - address, - onPress, -}: { - address: string; - onPress: () => void; -}): JSX.Element { - const { getAddressUrl } = useDeFiScanContext(); - return ( - - - - {address} - - - await openURL(getAddressUrl(address))} - style={tailwind("mb-2 ml-1 bg-transparent")} - > - - - - ); -} - -function AddressDetailAction({ - onReceivePress, - onTransactionsButtonPress, -}: { - onReceivePress: () => void; - onTransactionsButtonPress: () => void; -}): JSX.Element { - return ( - - - - - ); -} - -function WalletCounterDisplay({ - addressLength, -}: { - addressLength: number; -}): JSX.Element { - return ( - - {translate( - "components/BottomSheetAddressDetail", - "{{length}} ADDRESS(ES)", - { length: addressLength + 1 } - )} - - ); -} - -function DiscoverWalletAddress({ - onPress, -}: { - onPress: () => void; -}): JSX.Element { - return ( - - - - ); -} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetailV2.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetailV2.tsx index 3ba77913dd..3f9e33f474 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetailV2.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/BottomSheetAddressDetailV2.tsx @@ -20,11 +20,11 @@ import { } from "@shared-contexts/WalletContext"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; import { BottomSheetFlatList } from "@gorhom/bottom-sheet"; -import { useThemeContext, useNetworkContext } from "@waveshq/walletkit-ui"; +import { useNetworkContext, useThemeContext } from "@waveshq/walletkit-ui"; import { - wallet as walletReducer, - hasTxQueued, hasOceanTXQueued, + hasTxQueued, + wallet as walletReducer, } from "@waveshq/walletkit-ui/dist/store"; import { useSelector } from "react-redux"; import { loans } from "@store/loans"; @@ -36,11 +36,12 @@ import { setAddresses, setUserPreferences, } from "@store/userPreferences"; -import { useAddressLabel } from "@hooks/useAddressLabel"; import { useAppDispatch } from "@hooks/useAppDispatch"; import { openURL } from "@api/linking"; import { ThemedFlatListV2 } from "@components/themed/ThemedFlatListV2"; -import { useWalletAddress } from "@hooks/useWalletAddress"; +import { useWalletAddress, WalletAddressI } from "@hooks/useWalletAddress"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { useAddressLabel } from "@hooks/useAddressLabel"; import { RandomAvatar } from "./RandomAvatar"; interface BottomSheetAddressDetailProps { @@ -56,7 +57,7 @@ interface BottomSheetAddressDetailProps { } export const BottomSheetAddressDetailV2 = ( - props: BottomSheetAddressDetailProps + props: BottomSheetAddressDetailProps, ): React.MemoExoticComponent<() => JSX.Element> => memo(() => { const { isLight } = useThemeContext(); @@ -78,42 +79,45 @@ export const BottomSheetAddressDetailV2 = ( const toast = useToast(); const [showToast, setShowToast] = useState(false); const TOAST_DURATION = 2000; - const [availableAddresses, setAvailableAddresses] = useState([]); + const [availableAddresses, setAvailableAddresses] = useState< + WalletAddressI[] + >([]); const [canCreateAddress, setCanCreateAddress] = useState(false); const { fetchWalletAddresses } = useWalletAddress(); const logger = useLogger(); const dispatch = useAppDispatch(); + const { domain } = useDomainContext(); const blockCount = useSelector((state: RootState) => state.block.count); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const navigation = useNavigation>(); const { network } = useNetworkContext(); const userPreferences = useSelector( - (state: RootState) => state.userPreferences + (state: RootState) => state.userPreferences, ); const labeledAddresses = userPreferences.addresses; const activeLabel = useAddressLabel(props.address); const { getAddressUrl } = useDeFiScanContext(); const onActiveAddressPress = useCallback( - debounce(() => { + debounce((addressToCopy: string) => { if (showToast) { return; } + Clipboard.setString(addressToCopy); setShowToast(true); setTimeout(() => setShowToast(false), TOAST_DURATION); }, 500), - [showToast] + [showToast], ); useEffect(() => { if (showToast) { - Clipboard.setString(props.address); toast.show(translate("components/toaster", "Address copied"), { type: "wallet_toast", placement: "top", @@ -122,7 +126,7 @@ export const BottomSheetAddressDetailV2 = ( } else { toast.hideAll(); } - }, [showToast, props.address]); + }, [showToast]); // Getting addresses const fetchAddresses = async (): Promise => { @@ -164,7 +168,7 @@ export const BottomSheetAddressDetailV2 = ( > {translate( "components/BottomSheetAddressDetail", - "Create wallet address" + "Create wallet address", )} @@ -179,7 +183,6 @@ export const BottomSheetAddressDetailV2 = ( ) { return; } - dispatch(walletReducer.actions.setHasFetchedToken(false)); dispatch(loans.actions.setHasFetchedVaultsData(false)); await setIndex(index); @@ -188,18 +191,27 @@ export const BottomSheetAddressDetailV2 = ( }; const AddressListItem = useCallback( - // eslint-disable-next-line react/no-unused-prop-types - ({ item, index }: { item: string; index: number }): JSX.Element => { - const isSelected = item === props.address; - const hasLabel = - labeledAddresses?.[item]?.label != null && - labeledAddresses?.[item]?.label !== ""; + ({ + item, + index, + }: { + // eslint-disable-next-line react/no-unused-prop-types + item: WalletAddressI; + // eslint-disable-next-line react/no-unused-prop-types + index: number; + }): JSX.Element => { + const isSelected = item.dvm === props.address; + const displayAddress = domain === DomainType.EVM ? item.evm : item.dvm; + + // if no existing address label, then display label from generatedAddress key + const displayAddressLabel = + labeledAddresses?.[item.dvm]?.label ?? item.generatedLabel; return ( - + - {hasLabel && ( - - - {labeledAddresses[item]?.label} - - {isSelected && ( - - )} - - )} - {isSelected && !hasLabel && ( + + {displayAddressLabel} + + {isSelected && ( )} + + await openURL(getAddressUrl(item))} + onPress={async () => + await openURL(getAddressUrl(displayAddress)) + } disabled={!isSelected} style={tailwind( - "border-0 flex flex-1 flex-row items-center" + "border-0 flex flex-1 flex-row items-center", )} > - {item} + {displayAddress} {isSelected && ( { @@ -306,7 +308,7 @@ export const BottomSheetAddressDetailV2 = ( ...userPreferences, addresses, }, - }) + }), ); }); navigation.goBack(); @@ -315,7 +317,7 @@ export const BottomSheetAddressDetailV2 = ( merge: true, }); }} - testID={`address_edit_indicator_${item}`} + testID={`address_edit_indicator_${displayAddress}`} > ); }, - [labeledAddresses] + [labeledAddresses, domain], ); const AddressDetailHeader = useCallback(() => { + const activeAddress = availableAddresses.find( + ({ dvm }) => dvm === props.address, + ); + const displayAddressLabel = + activeLabel === null + ? activeAddress?.generatedLabel + : labeledAddresses?.[props.address]?.label; + + const activeDomainAddress = + domain === DomainType.DVM ? activeAddress?.dvm : activeAddress?.evm; return ( - {activeLabel != null && ( - - - {activeLabel} - - - )} + + + {displayAddressLabel} + + onActiveAddressPress(activeDomainAddress ?? "")} /> @@ -364,11 +375,11 @@ export const BottomSheetAddressDetailV2 = ( ); - }, [props, addressLength, activeLabel]); + }, [props, addressLength, activeLabel, domain, availableAddresses]); return ( item} + keyExtractor={(item) => item.dvm} stickyHeaderIndices={[0]} style={tailwind({ "bg-mono-dark-v2-100": !isLight, diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/CreateOrEditAddressLabelForm.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/CreateOrEditAddressLabelForm.tsx index 6f0f5b1f46..f2251c5e41 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/CreateOrEditAddressLabelForm.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/CreateOrEditAddressLabelForm.tsx @@ -1,36 +1,23 @@ -import { memo, useCallback, useEffect, useState } from "react"; +import { memo, useEffect, useState } from "react"; import { StackScreenProps } from "@react-navigation/stack"; import { BottomSheetWithNavRouteParam } from "@components/BottomSheetWithNav"; -import { - ThemedScrollViewV2, - ThemedText, - ThemedTextV2, -} from "@components/themed"; +import { ThemedScrollViewV2, ThemedTextV2 } from "@components/themed"; import { BottomSheetScrollView } from "@gorhom/bottom-sheet"; import { Platform, View } from "react-native"; import { tailwind } from "@tailwind"; import { translate } from "@translations"; -import { WalletTextInput } from "@components/WalletTextInput"; import { LabeledAddress, LocalAddress } from "@store/userPreferences"; -import { fromAddress } from "@defichain/jellyfish-address"; -import { - useNetworkContext, - useThemeContext, - useWalletNodeContext, -} from "@waveshq/walletkit-ui"; -import { useSelector } from "react-redux"; -import { RootState } from "@store"; -import { authentication, Authentication } from "@store/authentication"; -import { MnemonicStorage } from "@api/wallet/mnemonic_storage"; -import { useLogger } from "@shared-contexts/NativeLoggingProvider"; -import { useAppDispatch } from "@hooks/useAppDispatch"; +import { useThemeContext } from "@waveshq/walletkit-ui"; import { WalletTextInputV2 } from "@components/WalletTextInputV2"; import { SubmitButtonGroup } from "@components/SubmitButtonGroup"; +import { useWalletAddress, WalletAddressI } from "@hooks/useWalletAddress"; +import { useSelector } from "react-redux"; +import { RootState } from "@store"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { RandomAvatar } from "./RandomAvatar"; export interface CreateOrEditAddressLabelFormProps { title: string; - isAddressBook: boolean; address?: string; addressLabel?: LocalAddress; onSaveButtonPress: (labelAddress: LabeledAddress) => void; @@ -43,12 +30,15 @@ type Props = StackScreenProps< export const CreateOrEditAddressLabelForm = memo( ({ route, navigation }: Props): JSX.Element => { - // const { isLight } = useThemeContext() - const { title, isAddressBook, address, addressLabel, onSaveButtonPress } = - route.params; + const { title, address, addressLabel, onSaveButtonPress } = route.params; const { isLight } = useThemeContext(); + const { domain } = useDomainContext(); + const [walletAddress, setWalletAddress] = useState([]); + const { fetchWalletAddresses } = useWalletAddress(); + const walletAddressFromStore = useSelector( + (state: RootState) => state.userPreferences.addresses, + ); const [labelInput, setLabelInput] = useState(addressLabel?.label); - const [addressInput, setAddressInput] = useState(); const bottomSheetComponents = { mobile: BottomSheetScrollView, web: ThemedScrollViewV2, @@ -57,15 +47,15 @@ export const CreateOrEditAddressLabelForm = memo( Platform.OS === "web" ? bottomSheetComponents.web : bottomSheetComponents.mobile; - const { networkName } = useNetworkContext(); - const addressBook = useSelector( - (state: RootState) => state.userPreferences.addressBook - ); const [labelInputErrorMessage, setLabelInputErrorMessage] = useState(""); - const [addressInputErrorMessage, setAddressInputErrorMessage] = - useState(""); const [labelInputLength, setLabelInputLength] = useState(0); + useEffect(() => { + fetchWalletAddresses().then((walletAddresses) => { + setWalletAddress(walletAddresses); + }); + }, [fetchWalletAddresses]); + useEffect(() => { if (labelInput !== undefined) { setLabelInputLength(labelInput.trim().length); @@ -73,47 +63,45 @@ export const CreateOrEditAddressLabelForm = memo( }, [labelInput]); const validateLabelInput = (input: string): boolean => { - if (input !== undefined) { + const trimmedInput = input.trim(); + if (trimmedInput !== undefined) { if (input.trim().length > 40) { setLabelInputErrorMessage("Invalid label. Maximum of 40 characters."); return false; } - if (isAddressBook && input.trim() === "") { - setLabelInputErrorMessage("Please enter an address label"); + if (trimmedInput === "") { + setLabelInputErrorMessage("Label cannot be empty."); return false; } - } - setLabelInputErrorMessage(""); - return true; - }; + // check if label exists in address book + if ( + walletAddress.some( + (item) => + item.generatedLabel === trimmedInput && item.dvm !== address, + ) + ) { + setLabelInputErrorMessage("Use a unique wallet label."); + return false; + } - const validateAddressInput = (input: string): boolean => { - const decodedAddress = fromAddress(input, networkName); - if (decodedAddress === undefined) { - setAddressInputErrorMessage("Please enter a valid address"); - return false; - } - if (addressBook?.[input.trim()] !== undefined) { - setAddressInputErrorMessage( - "This address already exists in your address book, please enter a different address" - ); - return false; + // Check walletAddressFromStore object + if ( + Object.values(walletAddressFromStore).some( + (item) => item.label === trimmedInput && item.address !== address, + ) + ) { + setLabelInputErrorMessage("Use a unique wallet label"); + return false; + } } - setAddressInputErrorMessage(""); - return true; - }; - const handleSubmit = async (): Promise => { - if (!isAddressBook) { - handleEditSubmit(); - } else { - handleCreateSubmit(); - } + setLabelInputErrorMessage(""); + return true; }; - const handleEditSubmit = (): void => { + const handleEditSubmit = async (): Promise => { if ( labelInput === undefined || address === undefined || @@ -123,69 +111,32 @@ export const CreateOrEditAddressLabelForm = memo( } onSaveButtonPress({ [address]: { - address, + address: address, + evmAddress: getEVMAddress(address), label: labelInput.trim(), - isMine: true, }, }); }; - // Passcode prompt on create - const dispatch = useAppDispatch(); - const { - data: { type: encryptionType }, - } = useWalletNodeContext(); - const isEncrypted = encryptionType === "MNEMONIC_ENCRYPTED"; - const logger = useLogger(); - const handleCreateSubmit = useCallback(() => { - if ( - !isEncrypted || - addressInput === undefined || - labelInput === undefined || - !validateLabelInput(labelInput) || - !validateAddressInput(addressInput) - ) { - return; + const getEVMAddress = (address: string) => { + const storedWalletAddress = walletAddressFromStore[ + address + ] as LocalAddress; + if (storedWalletAddress && storedWalletAddress.evmAddress) { + return storedWalletAddress.evmAddress; } - - const auth: Authentication = { - consume: async (passphrase) => await MnemonicStorage.get(passphrase), - onAuthenticated: async () => { - onSaveButtonPress({ - [addressInput]: { - address: addressInput, - label: labelInput.trim(), - isMine: false, - }, - }); - }, - onError: (e) => logger.error(e), - message: translate("screens/Settings", "Enter passcode to continue"), - loading: translate("screens/Settings", "Verifying access"), - }; - dispatch(authentication.actions.prompt(auth)); - }, [dispatch, isEncrypted, addressInput, labelInput, onSaveButtonPress]); + // to support backward compatibility for already saved address + const addressObj = walletAddress.find((a) => a.dvm === address); + return addressObj?.evm ?? ""; + }; const isSaveDisabled = (): boolean => { - if ( - isAddressBook && - (addressInput === undefined || - labelInput === undefined || - labelInputErrorMessage !== "" || - addressInputErrorMessage !== "") - ) { - return true; - } - if ( - !isAddressBook && - (labelInput === undefined || - labelInput === addressLabel?.label || - labelInputErrorMessage !== "") - ) { - return true; - } - - return false; + return ( + labelInput === undefined || + labelInput === "" || + labelInput === addressLabel?.label || + labelInputErrorMessage !== "" + ); }; return ( @@ -205,7 +156,12 @@ export const CreateOrEditAddressLabelForm = memo( {translate("components/CreateOrEditAddressLabelForm", title)} - {address !== undefined && } + {address !== undefined && ( + + )} { setLabelInput(""); - if (isAddressBook) { - validateLabelInput(""); - } else { - setLabelInputErrorMessage(""); - } + setLabelInputErrorMessage(""); }} placeholder={translate( "components/CreateOrEditAddressLabelForm", - "Enter label" + "Enter label", )} style={tailwind("h-9 w-6/12 flex-grow")} hasBottomSheet @@ -241,7 +193,7 @@ export const CreateOrEditAddressLabelForm = memo( type: "error", text: translate( "components/CreateOrEditAddressLabelForm", - labelInputErrorMessage + labelInputErrorMessage, ), }} testID="address_book_label_input" @@ -255,105 +207,48 @@ export const CreateOrEditAddressLabelForm = memo( {translate( "components/CreateOrEditAddressLabelForm", "{{length}}/40 characters", - { length: labelInputLength.toString() } + { length: labelInputLength.toString() }, )} )} - {isAddressBook && ( - <> - - {translate("components/CreateOrEditAddressLabelForm", "ADDRESS")} - - - - )} - navigation.goBack()} - onSubmit={handleSubmit} + onSubmit={handleEditSubmit} displayCancelBtn title="save_address_label" /> ); - } + }, ); -function AddressDisplay({ address }: { address: string }): JSX.Element { +function AddressDisplay({ + address, + label, +}: { + address: string; + label: string; +}): JSX.Element { return ( - {address} + {label} ); } - -function AddressInput({ - addressInput, - setAddressInput, - validateAddressInput, - addressInputErrorMessage, -}: { - addressInput?: string; - setAddressInput: (val?: string) => void; - validateAddressInput: (val: string) => boolean; - addressInputErrorMessage: string; -}): JSX.Element { - return ( - { - setAddressInput(text); - validateAddressInput(text); - }} - onClearButtonPress={() => { - setAddressInput(""); - validateAddressInput(""); - }} - placeholder={translate( - "components/CreateOrEditAddressLabelForm", - "Enter address" - )} - style={tailwind("w-6/12 flex-grow")} - hasBottomSheet - valid={addressInputErrorMessage === ""} - inlineText={{ - type: "error", - text: translate( - "components/CreateOrEditAddressLabelForm", - addressInputErrorMessage - ), - }} - testID="address_book_address_input" - /> - ); -} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx index 16a9fa3908..5c5f11e026 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.test.tsx @@ -6,9 +6,14 @@ import { configureStore } from "@reduxjs/toolkit"; import { block } from "@waveshq/walletkit-ui/dist/store/block"; import { loans } from "@store/loans"; import { LoanVaultState } from "@defichain/whale-api-client/dist/api/loan"; +import { evm } from "@store/evm"; import { DFIBalanceCard } from "./DFIBalanceCard"; jest.mock("../../../../../contexts/DisplayBalancesContext"); +jest.mock("@contexts/DomainContext"); +jest.mock("@contexts/EVMProvider"); +jest.mock("@contexts/CustomServiceProvider"); + jest.mock("@react-navigation/native", () => ({ useNavigation: jest.fn(), useIsFocused: jest.fn(), @@ -108,6 +113,11 @@ describe("DFI Balance Card", () => { loanSchemes: [], loanTokens: [], }, + evm: { + evmWalletDetails: null, + evmTokenBalances: [], + hasFetchedEvmTokens: true, + }, }; const store = configureStore({ preloadedState: initialState, @@ -115,6 +125,7 @@ describe("DFI Balance Card", () => { wallet: wallet.reducer, block: block.reducer, loans: loans.reducer, + evm: evm.reducer, }, }); const component = ( diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx index 237a6cc514..fa9f9b331d 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/DFIBalanceCard.tsx @@ -16,8 +16,10 @@ import { useTokenPrice } from "@screens/AppNavigator/screens/Portfolio/hooks/Tok import { TextSkeletonLoaderV2 } from "@components/TextSkeletonLoaderV2"; import BigNumber from "bignumber.js"; import { translate } from "@translations"; +import { useDomainContext, DomainType } from "@contexts/DomainContext"; import { TokenNameText } from "./TokenNameText"; import { TokenAmountText } from "./TokenAmountText"; +import { useEvmTokenBalances } from "../hooks/EvmTokenBalances"; interface DFIBalaceCardProps { denominationCurrency: string; @@ -26,25 +28,37 @@ interface DFIBalaceCardProps { export function DFIBalanceCard({ denominationCurrency, }: DFIBalaceCardProps): JSX.Element { + const { domain } = useDomainContext(); + const { evmTokens } = useEvmTokenBalances(); + const evmDFIToken = evmTokens.find(({ id }) => id === "0_evm"); const navigation = useNavigation>(); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const DFIUnified = useSelector((state: RootState) => - unifiedDFISelector(state.wallet) + unifiedDFISelector(state.wallet), ); const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); + const { hasFetchedEvmTokens } = useSelector((state: RootState) => state.evm); const { getTokenPrice } = useTokenPrice(denominationCurrency); // input based on selected denomination from portfolio tab + const isEvmDomain = domain === DomainType.EVM; + const tokenAmount = isEvmDomain + ? new BigNumber(evmDFIToken?.amount ?? 0) + : new BigNumber(DFIUnified.amount ?? 0); const usdAmount = getTokenPrice( DFIUnified.symbol, - new BigNumber(DFIUnified.amount), - DFIUnified.isLPS + tokenAmount, + DFIUnified.isLPS, ); const DFIIcon = getNativeIcon("_UTXO"); + const EvmDFIIcon = getNativeIcon("EvmDFI"); + const isPositiveBalance = isEvmDomain + ? new BigNumber(evmDFIToken?.amount ?? 0).gt(0) + : new BigNumber(DFIUtxo.amount ?? 0).plus(DFIToken.amount ?? 0).gt(0); return ( @@ -55,20 +69,33 @@ export function DFIBalanceCard({ onPress={() => navigation.navigate({ name: "TokenDetailScreen", - params: { token: DFIUnified, usdAmount }, + params: { + token: { + ...DFIUnified, + amount: tokenAmount, + usdAmount, + ...(isEvmDomain && { + name: `${DFIUnified.name} for EVM`, + displaySymbol: "DFI", + id: "0_evm", + }), + }, + }, merge: true, }) } activeOpacity={0.7} - disabled={ - !new BigNumber(DFIUtxo.amount ?? 0).plus(DFIToken.amount ?? 0).gt(0) - } + disabled={!isPositiveBalance} > - + {!isEvmDomain ? ( + + ) : ( + + )} @@ -77,9 +104,9 @@ export function DFIBalanceCard({ "pt-0.5": Platform.OS === "android", })} > - {hasFetchedToken ? ( + {hasFetchedToken || (isEvmDomain && hasFetchedEvmTokens) ? ( - {hasFetchedToken && - !new BigNumber(DFIUtxo.amount ?? 0) - .plus(DFIToken.amount ?? 0) - .gt(0) && } + {hasFetchedToken && !isPositiveBalance && !isEvmDomain && } ); @@ -148,7 +172,7 @@ function GetDFIBtn(): JSX.Element { > {translate("screens/GetDFIScreen", "Get DFI now!")} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx index b3dfd59892..85aabe9a43 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx @@ -6,6 +6,7 @@ import { RootState } from "@store"; import { useSelector } from "react-redux"; import { Platform } from "react-native"; import { translate } from "@translations"; +import { useDomainContext, DomainType } from "@contexts/DomainContext"; import { PortfolioParamList } from "../PortfolioNavigator"; import { PortfolioRowToken } from "../PortfolioScreen"; import { EmptyTokensScreen } from "./EmptyTokensScreen"; @@ -17,6 +18,7 @@ import { EmptyCryptoIcon } from "../assets/EmptyCryptoIcon"; import { EmptyLPTokenIcon } from "../assets/EmptyLPTokenIcon"; import { EmptyDTokenIcon } from "../assets/EmptyDTokenIcon"; import { EmptyPortfolioIcon } from "../assets/EmptyPortfolioIcon"; +import { EmptyEvmPortfolioIcon } from "../assets/EmptyEvmPortfolioIcon"; interface PortfolioCardProps { isZeroBalance: boolean; @@ -28,6 +30,7 @@ interface PortfolioCardProps { setActiveButtonGroup: (key: ButtonGroupTabKey) => void; }; denominationCurrency: string; + isEvmDomain: boolean; } export function PortfolioCard({ @@ -36,12 +39,16 @@ export function PortfolioCard({ navigation, buttonGroupOptions, denominationCurrency, + isEvmDomain, }: PortfolioCardProps): JSX.Element { const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); - + const { domain } = useDomainContext(); // return empty portfolio if no DFI and other tokens if (isZeroBalance) { - const screenDetails = getEmptyScreenDetails(ButtonGroupTabKey.AllTokens); + const screenDetails = getEmptyScreenDetails( + ButtonGroupTabKey.AllTokens, + domain, + ); return ; } @@ -52,7 +59,8 @@ export function PortfolioCard({ buttonGroupOptions?.activeButtonGroup !== "ALL_TOKENS" ) { const screenDetails = getEmptyScreenDetails( - buttonGroupOptions?.activeButtonGroup + buttonGroupOptions?.activeButtonGroup, + domain, ); return ; } @@ -65,12 +73,16 @@ export function PortfolioCard({ onPress={() => navigation.navigate({ name: "TokenDetailScreen", - params: { token: item, usdAmount: item.usdAmount }, + params: { + token: item, + usdAmount: item.usdAmount, + }, merge: true, }) } token={item} denominationCurrency={denominationCurrency} + isEvmDomain={isEvmDomain} /> ))} @@ -81,10 +93,12 @@ function PortfolioItemRow({ token, onPress, denominationCurrency, + isEvmDomain, }: { token: PortfolioRowToken; onPress: () => void; denominationCurrency: string; + isEvmDomain?: boolean; }): JSX.Element { const testID = `portfolio_row_${token.id}`; @@ -98,7 +112,12 @@ function PortfolioItemRow({ > - + JSX.Element; title: string; subtitle: string; @@ -134,7 +156,7 @@ function getEmptyScreenDetails(type?: ButtonGroupTabKey): { title: translate("components/EmptyPortfolio", "No crypto found"), subtitle: translate( "components/EmptyPortfolio", - "Add crypto to get started" + "Add crypto to get started", ), }; case ButtonGroupTabKey.LPTokens: @@ -143,7 +165,7 @@ function getEmptyScreenDetails(type?: ButtonGroupTabKey): { title: translate("components/EmptyPortfolio", "No LP tokens found"), subtitle: translate( "components/EmptyPortfolio", - "Add liquidity to get started" + "Add liquidity to get started", ), }; case ButtonGroupTabKey.dTokens: @@ -152,18 +174,27 @@ function getEmptyScreenDetails(type?: ButtonGroupTabKey): { title: translate("components/EmptyPortfolio", "No dTokens found"), subtitle: translate( "components/EmptyPortfolio", - "Mint dTokens to get started" + "Mint dTokens to get started", ), }; case ButtonGroupTabKey.AllTokens: default: return { - icon: EmptyPortfolioIcon, + icon: + domain === DomainType.DVM + ? EmptyPortfolioIcon + : EmptyEvmPortfolioIcon, title: translate("components/EmptyPortfolio", "Empty portfolio"), - subtitle: translate( - "components/EmptyPortfolio", - "Add DFI and other tokens to get started" - ), + subtitle: + domain === DomainType.DVM + ? translate( + "components/EmptyPortfolio", + "Add DFI and other tokens to get started", + ) + : translate( + "components/EmptyPortfolio", + "Add to your balance by converting DFI to the EVM layer", + ), }; } } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TokenBreakdownDetailsV2.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TokenBreakdownDetailsV2.tsx index 84c7882388..7534d70bdd 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TokenBreakdownDetailsV2.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TokenBreakdownDetailsV2.tsx @@ -34,7 +34,7 @@ interface TokenBreakdownDetailProps { } export function TokenBreakdownDetailsV2( - props: TokenBreakdownDetailProps + props: TokenBreakdownDetailProps, ): JSX.Element { const { denominationCurrency } = useDenominationCurrency(); const lockedToken = (useTokenLockedBalance({ @@ -46,17 +46,17 @@ export function TokenBreakdownDetailsV2( }; const loanTokens = useSelector((state: RootState) => state.loans.loanTokens); const collateralTokens = useSelector( - (state: RootState) => state.loans.collateralTokens + (state: RootState) => state.loans.collateralTokens, ); const hasLockedBalance = useMemo((): boolean => { return ( collateralTokens.some( (collateralToken) => - collateralToken.token.displaySymbol === props.token.displaySymbol + collateralToken.token.displaySymbol === props.token.displaySymbol, ) || loanTokens.some( (loanToken) => - loanToken.token.displaySymbol === props.token.displaySymbol + loanToken.token.displaySymbol === props.token.displaySymbol, ) ); }, [props.token]); @@ -65,7 +65,7 @@ export function TokenBreakdownDetailsV2( // LP token calculations const { poolpairs: pairs } = useSelector((state: RootState) => state.wallet); const poolPairData = pairs.find( - (pr) => pr.data.symbol === (props.token as AddressToken).symbol + (pr) => pr.data.symbol === (props.token as AddressToken).symbol, ); const mappedPair = poolPairData?.data; const toRemove = new BigNumber(1) @@ -81,7 +81,7 @@ export function TokenBreakdownDetailsV2( const getUSDValue = ( amount: BigNumber, symbol: string, - isLPs: boolean = false + isLPs: boolean = false, ): BigNumber => { return getTokenPrice(symbol, amount, isLPs); }; @@ -166,6 +166,7 @@ export function TokenBreakdownDetailsV2( {/* To display options for DFI UTXO and Token */} {props.token.displaySymbol === "DFI" && + props.token.id !== "0_evm" && props.dfiUtxo !== undefined && props.dfiToken !== undefined && ( @@ -211,8 +212,8 @@ export function TokenBreakdownDetailsV2( getTokenPrice( props.token.symbol, new BigNumber(props.token.amount), - true - ) + true, + ), )} label="" hasFetchedToken={props.hasFetchedToken} @@ -233,7 +234,7 @@ export function TokenBreakdownDetailsV2( label={translate( "components/DFIBalanceCard", "Tokens in {{token}}", - { token: props.pair.tokenA.displaySymbol } + { token: props.pair.tokenA.displaySymbol }, )} hasFetchedToken={props.hasFetchedToken} /> @@ -242,8 +243,8 @@ export function TokenBreakdownDetailsV2( amount={getPrecisedCurrencyValue( getUSDValue( new BigNumber(tokenATotal), - props.pair.tokenA.symbol - ) + props.pair.tokenA.symbol, + ), )} label="" hasFetchedToken={props.hasFetchedToken} @@ -263,14 +264,14 @@ export function TokenBreakdownDetailsV2( label={translate( "components/DFIBalanceCard", "Tokens in {{token}}", - { token: props.pair.tokenB.displaySymbol } + { token: props.pair.tokenB.displaySymbol }, )} hasFetchedToken={props.hasFetchedToken} /> ; + isEvmToken?: boolean; } export function TokenIcon(props: TokenIconProps): JSX.Element { - const { token, testID, size, iconBStyle } = props; + const { token, testID, size, iconBStyle, isEvmToken } = props; if (token.isLPS === true) { const [tokenA, tokenB] = token.displaySymbol.split("-"); return ( @@ -26,6 +29,14 @@ export function TokenIcon(props: TokenIconProps): JSX.Element { /> ); } - const Icon = getNativeIcon(token.displaySymbol); - return ; + const Icon = + token.id === "0_evm" + ? getNativeIcon("DFI (EVM)") + : getNativeIcon(token.displaySymbol); + const evmIconSize = isEvmToken ? size - 4 : size; + return ( + + + + ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.test.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.test.tsx index 65759c0cbd..b3c2b5b11d 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.test.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.test.tsx @@ -9,6 +9,7 @@ import { loans } from "@store/loans"; import { PortfolioButtonGroupTabKey, TotalPortfolio } from "./TotalPortfolio"; jest.mock("@contexts/DisplayBalancesContext"); +jest.mock("@contexts/DomainContext"); describe("DFI Total Portfolio Card", () => { it("should match snapshot", async () => { diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx index a54d54e673..9b630bef2a 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/TotalPortfolio.tsx @@ -10,6 +10,7 @@ import { useSelector } from "react-redux"; import { Platform, TouchableOpacity } from "react-native"; import { useEffect, useState } from "react"; import { TextSkeletonLoaderV2 } from "@components/TextSkeletonLoaderV2"; +import { useDomainContext, DomainType } from "@contexts/DomainContext"; import { getPrecisedCurrencyValue, getPrecisedTokenValue, @@ -43,22 +44,26 @@ interface PortfolioButtonGroup { export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); + const { domain } = useDomainContext(); + const isEvmDomain = domain === DomainType.EVM; const { hasFetchedVaultsData } = useSelector( - (state: RootState) => state.loans + (state: RootState) => state.loans, ); const [isExpanded, setIsExpanded] = useState(false); const denominationCurrency = props.denominationCurrency; // for 'BTC' or 'DFI' denomination - const totalPortfolioValue = BigNumber.max( - 0, - new BigNumber(props.totalAvailableValue) - .plus(props.totalLockedValue) - .minus(props.totalLoansValue) - ); + const totalPortfolioValue = isEvmDomain + ? new BigNumber(props.totalAvailableValue) + : BigNumber.max( + 0, + new BigNumber(props.totalAvailableValue) + .plus(props.totalLockedValue) + .minus(props.totalLoansValue), + ); const [activeButtonGroup, setActiveButtonGroup] = useState(); const onCurrencySwitch = (): void => { const activeIndex = props.portfolioButtonGroup.findIndex( - (tab) => tab.id === props.denominationCurrency + (tab) => tab.id === props.denominationCurrency, ); let nextIndex = activeIndex + 1; if (activeIndex === props.portfolioButtonGroup.length - 1) { @@ -70,8 +75,8 @@ export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { useEffect(() => { setActiveButtonGroup( props.portfolioButtonGroup.find( - (button) => button.id === props.denominationCurrency - ) + (button) => button.id === props.denominationCurrency, + ), ); }, [props.denominationCurrency]); @@ -101,7 +106,7 @@ export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { - setIsExpanded(!isExpanded)} - style={tailwind("")} - testID="toggle_portfolio" - > - - + {!isEvmDomain && ( + setIsExpanded(!isExpanded)} + style={tailwind("")} + testID="toggle_portfolio" + > + + + )} ) : ( @@ -151,7 +158,7 @@ export function TotalPortfolio(props: TotalPortfolioProps): JSX.Element { /> )} - {isExpanded && ( + {isExpanded && !isEvmDomain && ( + + + + + + + + Convert + + + + ([]); + const [allTokensWithAddress, setAllTokensWithAddress] = + useState({}); + const blockCount = useSelector((state: RootState) => state.block.count); + const { network } = useNetworkContext(); + const { evmUrl } = useCustomServiceProviderContext(); + const { provider } = useEVMProvider(); + const logger = useLogger(); + const isFocused = useIsFocused(); + + const { allTokens } = useSelector((state: RootState) => state.wallet); + const tokenIds = Object.keys(allTokens).reduce((current: string[], key) => { + const token = allTokens[key]; + if (token.id !== "0" && token.isDAT && !token.isLPS) { + return [...current, token.id]; + } + return current; + }, []); + const { evmWalletDetails, evmTokenBalances } = useSelector( + (state: RootState) => state.evm, + ); + const dispatch = useAppDispatch(); + + const getEvmTokens = async () => { + const dfiToken: WalletToken = { + id: "0_evm", + symbol: "DFI", + symbolKey: "DFI", + isDAT: true, + isLPS: false, + isLoanToken: false, + amount: "0", + name: "DeFiChain for EVM", + displaySymbol: "DFI", + avatarSymbol: "DFI", + }; + try { + const evmDfiBalance = utils.formatEther( + evmWalletDetails?.coin_balance ?? "0", + ); + dfiToken.amount = evmDfiBalance; + setEvmTokens( + evmTokenBalances.reduce( + (current: WalletToken[], each) => { + const tokenAddress = each?.token?.address; + const tokenDetails = allTokensWithAddress[tokenAddress] ?? null; + if (tokenDetails) { + return [ + ...current, + { + id: `${tokenDetails.id}_evm`, + symbol: tokenDetails.symbol, + symbolKey: tokenDetails.symbolKey, + isDAT: tokenDetails.isDAT, + isLPS: tokenDetails.isLPS, + isLoanToken: tokenDetails.isLoanToken, + name: `${tokenDetails.name || tokenDetails.symbol} for EVM`, + displaySymbol: tokenDetails.displaySymbol, + avatarSymbol: tokenDetails.symbol, + amount: utils.formatUnits(each.value, each?.token?.decimals), + }, + ]; + } + return current; + }, + [dfiToken], + ), + ); + } catch (e) { + logger.error(e); + setEvmTokens([dfiToken]); + } + }; + + useEffect(() => { + if (isFocused) { + batch(() => { + dispatch( + fetchEvmWalletDetails({ evmUrl, network, evmAddress, provider }), + ); + dispatch( + fetchEvmTokenBalances({ + evmUrl, + network, + evmAddress, + provider, + tokenIds, + }), + ); + }); + } + }, [network, evmAddress, blockCount, isFocused, provider]); + + useEffect(() => { + setAllTokensWithAddress( + Object.keys(allTokens).reduce((current, each) => { + const tokenDetails = allTokens[each]; + const key = getAddressFromDST20TokenId(tokenDetails.id); + return Object.assign(current, { [key]: tokenDetails }); + }, {}), + ); + }, [allTokens]); + + useEffect(() => { + getEvmTokens(); + }, [evmWalletDetails]); + + return { evmTokens }; +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts new file mode 100644 index 0000000000..528ccbf7f7 --- /dev/null +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/TokenBalance.ts @@ -0,0 +1,103 @@ +import { useSelector } from "react-redux"; +import BigNumber from "bignumber.js"; +import { RootState } from "@store"; +import { WalletToken, tokensSelector } from "@waveshq/walletkit-ui/dist/store"; +import { useMemo } from "react"; +import { DomainType } from "@contexts/DomainContext"; +import { useEvmTokenBalances } from "./EvmTokenBalances"; + +export interface DomainToken { + tokenId: string; + available: BigNumber; + token: { + name: string; + displaySymbol: string; + displayTextSymbol: string; + symbol: string; + isLPS?: boolean; + domainType: DomainType; + }; + factor?: string; + reserve?: string; +} + +export function useTokenBalance(): { + dvmTokens: DomainToken[]; + evmTokens: DomainToken[]; +} { + const tokens = useSelector((state: RootState) => + tokensSelector(state.wallet), + ); + + const { evmTokens } = useEvmTokenBalances(); + const mapDomainToken = (token: WalletToken) => { + return { + tokenId: token.id, + available: new BigNumber(token.amount), + token: { + name: token.name, + displaySymbol: token.symbol, + displayTextSymbol: token.symbol, + symbol: token.symbol, + isLPS: token.isLPS, + domainType: DomainType.EVM, + }, + }; + }; + const { dvmTokens } = useMemo(() => { + return tokens.reduce( + ( + { dvmTokens }: { dvmTokens: DomainToken[] }, + token, + ): { dvmTokens: DomainToken[] } => { + if (token.isLPS || token.id === "0_unified") { + return { dvmTokens }; + } + + return { + dvmTokens: [ + ...dvmTokens, + { + tokenId: token.id, + available: getConvertibleAmount( + token.id === "0_utxo", + new BigNumber(token.amount), + ), + token: { + name: token.name, + displaySymbol: token.displaySymbol, + displayTextSymbol: + token.id === "0" + ? "DFI" + : token.id === "0_utxo" + ? "UTXO" + : token.displaySymbol, + symbol: token.symbol, + isLPS: false, + domainType: DomainType.DVM, + }, + }, + ], + }; + }, + { + dvmTokens: [], + }, + ); + }, [tokens]); + + return { + dvmTokens, + evmTokens: evmTokens.map(mapDomainToken), + }; +} + +function getConvertibleAmount(isUtxo: boolean, amount: BigNumber): BigNumber { + if (isUtxo) { + const utxoToReserve = "0.1"; + const leftover = new BigNumber(amount).minus(new BigNumber(utxoToReserve)); + return leftover.isLessThan(0) ? new BigNumber(0) : leftover; + } + + return amount; +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/AddOrEditAddressBookScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/AddOrEditAddressBookScreen.tsx index 05ee7b7376..0b4813caf3 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/AddOrEditAddressBookScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/AddOrEditAddressBookScreen.tsx @@ -7,8 +7,7 @@ import { ThemedTouchableOpacityV2, ThemedViewV2, } from "@components/themed"; -import { fromAddress } from "@defichain/jellyfish-address"; -import { useWalletAddress } from "@hooks/useWalletAddress"; +import { WalletAddressI, useWalletAddress } from "@hooks/useWalletAddress"; import { useAppDispatch } from "@hooks/useAppDispatch"; import { StackScreenProps } from "@react-navigation/stack"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; @@ -27,7 +26,9 @@ import { ButtonV2 } from "@components/ButtonV2"; import { useDeFiScanContext } from "@shared-contexts/DeFiScanContext"; import { useToast } from "react-native-toast-notifications"; import { debounce } from "lodash"; +import { AddressType, getAddressType } from "@waveshq/walletkit-core"; import * as Clipboard from "expo-clipboard"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { SettingsParamList } from "../../Settings/SettingsNavigator"; type Props = StackScreenProps; @@ -36,27 +37,50 @@ export function AddOrEditAddressBookScreen({ route, navigation, }: Props): JSX.Element { - const { title, onSaveButtonPress, address, addressLabel, isAddNew } = - route.params; + const { isEvmFeatureEnabled } = useDomainContext(); + const { + title, + onSaveButtonPress, + address, + addressDomainType, + addressLabel, + isAddNew, + } = route.params; const [labelInput, setLabelInput] = useState(addressLabel?.label); const [addressInput, setAddressInput] = useState(address); const [isEditable, setIsEditable] = useState(isAddNew); const { networkName } = useNetworkContext(); const addressBook = useSelector( - (state: RootState) => state.userPreferences.addressBook + (state: RootState) => state.userPreferences.addressBook, ); const [labelInputErrorMessage, setLabelInputErrorMessage] = useState(""); const [addressInputErrorMessage, setAddressInputErrorMessage] = useState(""); const { fetchWalletAddresses } = useWalletAddress(); + // array of all wallet addresses const [walletAddress, setWalletAddress] = useState([]); + const AddressDomains = [ + { + label: "DeFiChain (DVM)", + value: DomainType.DVM, + }, + { + label: "MetaChain (EVM)", + value: DomainType.EVM, + }, + ]; + + const [selectedAddressDomainType, setSelectedAddressDomainType] = useState( + addressDomainType ?? DomainType.DVM, + ); + const validateLabelInput = (input: string): boolean => { if ( input.trim() === "" || (input !== undefined && input.trim().length > 40) ) { setLabelInputErrorMessage( - "Required field. Please enter a label. Maximum of 40 characters." + "Required field. Please enter a label. Maximum of 40 characters.", ); return false; } @@ -77,11 +101,18 @@ export function AddOrEditAddressBookScreen({ }; const validateAddressInput = (input: string): boolean => { - const decodedAddress = fromAddress(input, networkName); - if (decodedAddress === undefined) { + const addressType = getAddressType(input, networkName); + if ( + addressType === undefined || + (selectedAddressDomainType === DomainType.DVM && + addressType === AddressType.ETH) || + (selectedAddressDomainType === DomainType.EVM && + addressType !== AddressType.ETH) + ) { setAddressInputErrorMessage("Please enter a valid address"); return false; } + if ( (addressBook?.[input.trim()] !== undefined && (isAddNew || (!isAddNew && input.trim() !== address))) || @@ -90,7 +121,7 @@ export function AddOrEditAddressBookScreen({ // check for unique address when adding new, or only when new address is different from current during edit // or when address exists in local address setAddressInputErrorMessage( - "This address already exists in your address book, please enter a different address" + "This address already exists in your address book, please enter a different address", ); return false; } @@ -142,8 +173,8 @@ export function AddOrEditAddressBookScreen({ const editedAddress = { [addressInput]: { address: addressInput, + addressDomainType: selectedAddressDomainType, label: labelInput, - isMine: false, isFavourite: addressLabel?.isFavourite, }, }; @@ -166,18 +197,18 @@ export function AddOrEditAddressBookScreen({ isAddNew ? "Add address to address book?\n{{address}}" : "Update address label for\n{{address}}", - { address: addressInput } + { address: addressInput }, ), message: translate("screens/Settings", "Enter passcode to continue"), loading: translate( "screens/AddOrEditAddressBookScreen", isAddNew ? "It may take a few seconds to save" - : "It may take a few seconds to update" + : "It may take a few seconds to update", ), successMessage: translate( "screens/AddOrEditAddressBookScreen", - isAddNew ? "Address saved!" : "Address label updated!" + isAddNew ? "Address saved!" : "Address label updated!", ), }; dispatch(authentication.actions.prompt(auth)); @@ -197,21 +228,21 @@ export function AddOrEditAddressBookScreen({ onError: (e) => logger.error(e), title: translate( "screens/AddOrEditAddressBookScreen", - "Are you sure you want to delete the address?" + "Are you sure you want to delete the address?", ), message: translate("screens/Settings", "Enter passcode to continue"), loading: translate( "screens/AddOrEditAddressBookScreen", - "It may take a few seconds to delete" + "It may take a few seconds to delete", ), successMessage: translate( "screens/AddOrEditAddressBookScreen", - "Address deleted!" + "Address deleted!", ), }; dispatch(authentication.actions.prompt(auth)); }, - [navigation, dispatch, isEncrypted] + [navigation, dispatch, isEncrypted], ); useLayoutEffect(() => { @@ -226,13 +257,19 @@ export function AddOrEditAddressBookScreen({ return; } validateAddressInput(addressInput); - }, [addressInput]); + }, [addressInput, selectedAddressDomainType]); useEffect(() => { let isSubscribed = true; - void fetchWalletAddresses().then((walletAddress) => { + fetchWalletAddresses().then((walletAddress: WalletAddressI[]) => { if (isSubscribed) { - setWalletAddress(walletAddress); + const allWalletAddresses = walletAddress.reduce( + (allAddress: string[], each: WalletAddressI) => { + return [...allAddress, ...Object.values(each)]; + }, + [], + ); + setWalletAddress(allWalletAddresses); } }); return () => { @@ -245,6 +282,71 @@ export function AddOrEditAddressBookScreen({ contentContainerStyle={tailwind("px-5 pb-16")} style={tailwind("flex-1")} > + {isEvmFeatureEnabled && ( + + + + {AddressDomains.map((addressDomain, index) => { + const isChecked = + selectedAddressDomainType === addressDomain.value; + return ( + { + setSelectedAddressDomainType(addressDomain.value); + }} + testID={`address_book_address_type_${addressDomain.value}${ + isChecked ? "_checked" : "" + }`} + > + + + {translate( + "screens/AddOrEditAddressBookScreen", + addressDomain.label, + )} + + + ); + })} + + + )} + {isAddNew ? ( {translate( "screens/AddOrEditAddressBookScreen", - "Maximum of 40 characters." + "Maximum of 40 characters.", )} )} @@ -369,7 +471,7 @@ export function AddOrEditAddressBookScreen({ light={tailwind("bg-mono-light-v2-00")} dark={tailwind("bg-mono-dark-v2-00 ")} style={tailwind( - "border-0 p-4.5 flex-row justify-center rounded-lg-v2 mt-6" + "border-0 p-4.5 flex-row justify-center rounded-lg-v2 mt-6", )} testID="delete_address" onPress={async () => await onDelete(address)} @@ -377,7 +479,7 @@ export function AddOrEditAddressBookScreen({ {translate( "screens/AddOrEditAddressBookScreen", - "Delete address" + "Delete address", )} @@ -388,7 +490,7 @@ export function AddOrEditAddressBookScreen({ > {translate( "screens/ServiceProviderScreen", - "This will delete the whitelisted address\nfrom your address book." + "This will delete the whitelisted address\nfrom your address book.", )} @@ -397,7 +499,7 @@ export function AddOrEditAddressBookScreen({ disabled={isSaveDisabled()} label={translate( "screens/AddOrEditAddressBookScreen", - isAddNew ? "Save address" : "Save changes" + isAddNew ? "Save address" : "Save changes", )} onPress={handleSubmit} testID="save_address_label" @@ -422,7 +524,7 @@ function CopyAddressComponent(props: { address: string }): JSX.Element { setShowToast(true); setTimeout(() => setShowToast(false), TOAST_DURATION); }, 500), - [showToast] + [showToast], ); useEffect(() => { @@ -453,7 +555,7 @@ function CopyAddressComponent(props: { address: string }): JSX.Element { > ; @@ -61,21 +64,36 @@ export enum ButtonGroupTabKey { } export function AddressBookScreen({ route, navigation }: Props): JSX.Element { - const { selectedAddress, onAddressSelect, disabledTab } = route.params; + const { selectedAddress, onAddressSelect, disabledTab, addressDomainType } = + route.params; const { isLight } = useThemeContext(); const { network } = useNetworkContext(); + const { isEvmFeatureEnabled } = useDomainContext(); const dispatch = useAppDispatch(); + // condition to hide icon if not from send page + const isAddressSelectDisabled = + selectedAddress !== undefined && onAddressSelect !== undefined; const userPreferencesFromStore = useSelector( - (state: RootState) => state.userPreferences + (state: RootState) => state.userPreferences, ); - const addressBook: LocalAddress[] = useSelector((state: RootState) => - selectAddressBookArray(state.userPreferences) + const whitelistedAddresses: WhitelistedAddress[] = useSelector( + (state: RootState) => selectAddressBookArray(state.userPreferences), ); + + const addressBook = useMemo(() => { + return whitelistedAddresses?.filter((addr) => { + return ( + isEvmFeatureEnabled || + (!isEvmFeatureEnabled && addr.addressDomainType === DomainType.DVM) + ); + }); + }, [whitelistedAddresses]); + const walletAddressFromStore: LocalAddress[] = useSelector( - (state: RootState) => selectLocalWalletAddressArray(state.userPreferences) + (state: RootState) => selectLocalWalletAddressArray(state.userPreferences), ); // not all wallet address are stored in userPreference const [walletAddress, setWalletAddress] = useState( - walletAddressFromStore + walletAddressFromStore, ); // combine labeled wallet address with jellyfish's api wallet const [isSearchFocus, setIsSearchFocus] = useState(false); const { headerStyle }: StackNavigationOptions = useNavigatorScreenOptions(); @@ -84,7 +102,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { const searchRef = createRef(); const { fetchWalletAddresses } = useWalletAddress(); const [filteredAddressBook, setFilteredAddressBook] = - useState(addressBook); + useState(addressBook); const [filteredWalletAddress, setFilteredWalletAddress] = useState(walletAddress); @@ -105,31 +123,36 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { const [activeButtonGroup, setActiveButtonGroup] = useState( disabledTab === ButtonGroupTabKey.Whitelisted ? ButtonGroupTabKey.YourAddress - : ButtonGroupTabKey.Whitelisted + : ButtonGroupTabKey.Whitelisted, ); useEffect(() => { // combine redux store and jellyfish wallet let isSubscribed = true; - void fetchWalletAddresses().then((walletAddresses) => { + fetchWalletAddresses().then((walletAddresses) => { if (isSubscribed) { const addresses: LocalAddress[] = []; - walletAddresses.forEach((address) => { + walletAddresses.forEach((address: WalletAddressI) => { const storedWalletAddress = walletAddressFromStore.find( - (a) => a.address === address + (a) => a.address === address.dvm, ); - if (selectedAddress === address) { + + if (selectedAddress === address.dvm) { // change tab if selected address is from your addresses setActiveButtonGroup(ButtonGroupTabKey.YourAddress); } if (storedWalletAddress === undefined) { addresses.push({ - address, - label: "", - isMine: true, + address: address.dvm, + evmAddress: address.evm, + label: address.generatedLabel, }); } else { - addresses.push(storedWalletAddress); + addresses.push({ + ...storedWalletAddress, + // to support backward compatibility for already saved address + evmAddress: storedWalletAddress.evmAddress ?? address.evm, + }); } }); setWalletAddress(addresses); @@ -150,25 +173,27 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { address.label .toLowerCase() .includes(searchString?.trim().toLowerCase()) || - address.address.includes(searchString?.trim().toLowerCase()) - ) + address.address.includes(searchString?.trim().toLowerCase()), + ), ); setFilteredWalletAddress( - sortByFavourite(walletAddress).filter( - (address) => + walletAddress.filter( + (address: LocalAddress) => address.label .toLowerCase() .includes(searchString?.trim().toLowerCase()) || - address.address.includes(searchString?.trim().toLowerCase()) - ) + address.address.includes(searchString?.trim().toLowerCase()) || + address.evmAddress.includes(searchString?.trim().toLowerCase()), + // || (address.label === ""), + ) as LocalAddress[], ); }, 200), - [addressBook, walletAddress, searchString, activeButtonGroup] + [addressBook, walletAddress, searchString, activeButtonGroup], ); // Favourite const onFavouriteAddress = async ( - localAddress: LocalAddress + localAddress: WhitelistedAddress, ): Promise => { const labeledAddress = { [localAddress.address]: { @@ -182,16 +207,34 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { dispatch(userPreferences.actions.addToAddressBook(labeledAddress)); }; - const sortByFavourite = (localAddresses: LocalAddress[]): LocalAddress[] => { - return [...localAddresses].sort((curr, next) => { - if (curr.isFavourite === true) { - return -1; - } - if (next.isFavourite === true) { - return 1; - } - return 0; - }); + const sortByFavourite = ( + localAddresses: WhitelistedAddress[], + ): WhitelistedAddress[] => { + return [...localAddresses] + .sort((curr, next) => { + if (curr.isFavourite === true) { + return -1; + } + if (next.isFavourite === true) { + return 1; + } + return 0; + }) + .sort((curr, next) => { + if ( + isAddressSelectDisabled && + curr.addressDomainType === addressDomainType + ) { + return -1; + } + if ( + isAddressSelectDisabled && + next.addressDomainType === addressDomainType + ) { + return 1; + } + return 0; + }); }; useEffect(() => { @@ -201,7 +244,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { setUserPreferences({ network, preferences: userPreferencesFromStore, - }) + }), ); }; updateLocalStorage().catch(Logging.error); @@ -213,13 +256,18 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { filterAddress(searchString); return; } - if (activeButtonGroup === ButtonGroupTabKey.Whitelisted) { setFilteredAddressBook(sortByFavourite(addressBook)); } else { - setFilteredWalletAddress(sortByFavourite(walletAddress)); + setFilteredWalletAddress(walletAddress); } - }, [addressBook, walletAddress, searchString, activeButtonGroup]); + }, [ + addressBook, + walletAddress, + searchString, + activeButtonGroup, + addressDomainType, + ]); useEffect(() => { navigation.setOptions({ @@ -231,132 +279,241 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { }); }, []); - const AddressListItem = useCallback( + const WhitelistedAddressItem = useCallback( ({ selectedAddress, onAddressSelect, ...props }: { - item: LocalAddress; + item: WhitelistedAddress; index: number; testIDSuffix: string; selectedAddress?: string; onAddressSelect?: (address: string) => void; }): JSX.Element => { const { item, index, testIDSuffix } = props; - // condition to hide icon from send page - const enableAddressSelect = - selectedAddress !== undefined && onAddressSelect !== undefined; - const onChangeAddress = (address: string): void => { - if (enableAddressSelect) { - onAddressSelect(address); + const isDisabledToSelect = + isAddressSelectDisabled && + activeButtonGroup === ButtonGroupTabKey.Whitelisted && + (item as WhitelistedAddress).addressDomainType === addressDomainType && + addressDomainType === DomainType.EVM; // disable address selection if its from the same EVM domain + + const onChangeAddress = (addressDetail: WhitelistedAddress): void => { + if (onAddressSelect) { + onAddressSelect(addressDetail.address); + } + }; + + const onDFIAddressClick = async () => { + if (activeButtonGroup === ButtonGroupTabKey.Whitelisted) { + setSearchString(""); + setIsSearchFocus(false); + navigation.navigate({ + name: "AddOrEditAddressBookScreen", + params: { + title: "Address Details", + isAddNew: false, + address: item.address, + addressDomainType: (item as WhitelistedAddress).addressDomainType, + addressLabel: item, + onSaveButtonPress: () => {}, + }, + merge: true, + }); + } else { + await openURL(getAddressUrl(item.address)); } }; + return ( { - onChangeAddress(item.address); - }} + disabled={isDisabledToSelect} + onPress={async () => onChangeAddress(item)} > - {item.isMine ? ( - - - - ) : ( - await onFavouriteAddress(item)} - testID={`address_row_star_${index}_${testIDSuffix}`} - disabled={enableAddressSelect} - > - {item.isFavourite === true ? ( - - ) : ( - - )} - - )} { - if (activeButtonGroup === ButtonGroupTabKey.Whitelisted) { - setSearchString(""); - setIsSearchFocus(false); - navigation.navigate({ - name: "AddOrEditAddressBookScreen", - params: { - title: "Address Details", - isAddNew: false, - address: item.address, - addressLabel: item, - onSaveButtonPress: () => {}, - }, - merge: true, - }); - } else { - await openURL(getAddressUrl(item.address)); - } - }} - testID={`address_action_${item.address}`} - style={tailwind("flex flex-row items-center flex-auto")} - disabled={enableAddressSelect} + style={tailwind("mr-4")} + onPress={async () => + await onFavouriteAddress(item as WhitelistedAddress) + } + testID={`address_row_star_${index}_${testIDSuffix}`} + disabled={isAddressSelectDisabled} > + {item.isFavourite ? ( + + ) : ( + + )} + + + {item.label !== "" && ( - - {item.label} - + + + {item.label} + + {(item as WhitelistedAddress).addressDomainType === + DomainType.EVM && ( + + )} + )} - - {item.address} - - - {!enableAddressSelect && ( - onChangeAddress(item)} /> + {/* for EVM address */} + + {!isAddressSelectDisabled && ( + + + )} - + ); }, - [filteredAddressBook, filteredWalletAddress, activeButtonGroup] + [filteredAddressBook, filteredWalletAddress, activeButtonGroup], + ); + + const YourAddressListItem = useCallback( + ({ + selectedAddress, + onAddressSelect, + ...props + }: { + item: LocalAddress; + index: number; + testIDSuffix: string; + selectedAddress?: string; + onAddressSelect?: (address: string) => void; + }): JSX.Element => { + const { item, index, testIDSuffix } = props; + + const onChangeAddress = (addressDetail: string): void => { + if (onAddressSelect) { + onAddressSelect(addressDetail); + } + }; + + const onDFIAddressClick = async () => { + await openURL(getAddressUrl(item.address)); + }; + + return ( + // Your Address card + onChangeAddress(item.address)} + disabled={isEvmFeatureEnabled} + > + + + + + + + + {item.label} + + + + + + {/* DVM address card */} + { + onChangeAddress(item.address); + }} + isAddressSelectEnabled={false} + /> + {/* EVM address card */} + {isEvmFeatureEnabled && ( + { + onChangeAddress(item.evmAddress); + }} + isAddressSelectEnabled={false} + /> + )} + + + + + + ); + }, + [filteredAddressBook, filteredWalletAddress, activeButtonGroup], ); const goToAddAddressForm = (): void => { @@ -365,6 +522,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { params: { title: "Add Address", isAddNew: true, + addressDomainType, onSaveButtonPress: (address?: string) => { if (onAddressSelect !== undefined && address !== undefined) { onAddressSelect(address); @@ -381,7 +539,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { light={tailwind("bg-mono-light-v2-00 border-mono-light-v2-100")} dark={tailwind("bg-mono-dark-v2-00 border-mono-dark-v2-100")} style={tailwind( - "flex flex-col items-center pt-1 rounded-b-2xl border-b" + "flex flex-col items-center pt-1 rounded-b-2xl border-b", )} > @@ -414,7 +572,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { : { "border-mono-light-v2-00": isLight, "border-mono-dark-v2-00": !isLight, - } + }, ), ]} inputStyle={{ @@ -423,7 +581,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { }} placeholder={translate( "screens/AddressBookScreen", - "Search address book" + "Search address book", )} showClearButton={searchString !== ""} onClearInput={() => { @@ -450,7 +608,7 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { dark={tailwind("bg-mono-dark-v2-900")} testID="add_new_address" style={tailwind( - "flex h-10 w-10 flex-row items-center justify-center rounded-full" + "flex h-10 w-10 flex-row items-center justify-center rounded-full", )} > @@ -494,29 +652,41 @@ export function AddressBookScreen({ route, navigation }: Props): JSX.Element { ) : ( <> + {/* Search address */} {!isSearchFocus && searchString?.trim().length === 0 && ( )} - {(activeButtonGroup === ButtonGroupTabKey.Whitelisted - ? filteredAddressBook - : filteredWalletAddress - ).map((item: LocalAddress, index: number) => ( - - ))} + + {/* wWhitelisted address tab */} + {activeButtonGroup === ButtonGroupTabKey.Whitelisted && + filteredAddressBook.map( + (item: WhitelistedAddress, index: number) => ( + + ), + )} + + {/* Your address tab */} + {activeButtonGroup === ButtonGroupTabKey.YourAddress && + filteredWalletAddress.map((item: LocalAddress, index: number) => ( + + ))} )} @@ -533,6 +703,7 @@ function EmptyDisplay({ onPress }: { onPress: () => void }): JSX.Element { > void }): JSX.Element { > {translate( "screens/AddressBookScreen", - "Add your preferred / commonly-used address." + "Add your preferred / commonly-used address.", )} ); } + +function WhitelistedAddressLink({ + disabled, + onClick, + address, + displayIcon, + testIDSuffix, +}: { + disabled: boolean; + onClick: () => Promise; + address: string; + displayIcon: boolean; + testIDSuffix: string; +}) { + return ( + + + {address} + + {!disabled && displayIcon && ( + + + + )} + + ); +} + +function YourAddressLink({ + disabled, + onClick, + address, + isEvmAddress, + testIDSuffix, + isAddressSelectEnabled, +}: { + disabled?: boolean; + onClick: () => Promise; + address: string; + isEvmAddress?: boolean; + testIDSuffix: string; + isAddressSelectEnabled: boolean; +}) { + return ( + + + + {address} + + {isEvmAddress && } + + {isAddressSelectEnabled && ( + + )} + + ); +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx index b93e1e85c4..c5e8278818 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx @@ -3,7 +3,7 @@ import { ThemedScrollViewV2, ThemedViewV2 } from "@components/themed"; import { NavigationProp, useNavigation } from "@react-navigation/native"; import { StackScreenProps } from "@react-navigation/stack"; import BigNumber from "bignumber.js"; -import { Dispatch, useEffect, useState } from "react"; +import { Dispatch, useEffect, useMemo, useState } from "react"; import { useSelector } from "react-redux"; import { RootState } from "@store"; import { @@ -26,34 +26,36 @@ import { View } from "react-native"; import { useWalletContext } from "@shared-contexts/WalletContext"; import { useAddressLabel } from "@hooks/useAddressLabel"; import { NumberRowV2 } from "@components/NumberRowV2"; +import { ConvertDirection, ScreenName } from "@screens/enum"; import { - ConvertTokenUnit, - getDisplayUnit, -} from "@screens/AppNavigator/screens/Portfolio/screens/ConvertScreen"; -import { ScreenName } from "@screens/enum"; -import { ConversionMode } from "./ConvertScreen"; + TransferDomainToken, + transferDomainCrafter, +} from "@api/transaction/transfer_domain"; +import { useNetworkContext } from "@waveshq/walletkit-ui"; +import { NetworkName } from "@defichain/jellyfish-network"; +import { useEVMProvider } from "@contexts/EVMProvider"; import { PortfolioParamList } from "../PortfolioNavigator"; type Props = StackScreenProps; export function ConvertConfirmationScreen({ route }: Props): JSX.Element { const { - sourceUnit, - sourceBalance, - targetUnit, - targetBalance, - mode, amount, + convertDirection, fee, + sourceToken, + targetToken, originScreen, } = route.params; - const { address } = useWalletContext(); + const { networkName } = useNetworkContext(); + const { address, evmAddress } = useWalletContext(); + const { provider, chainId } = useEVMProvider(); const addressLabel = useAddressLabel(address); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const dispatch = useAppDispatch(); const [isSubmitting, setIsSubmitting] = useState(false); @@ -68,22 +70,81 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element { }; }, []); + const [fromLhs, toLhs] = useMemo(() => { + const dvmText = translate( + "screens/ConvertConfirmScreen", + "Resulting Tokens", + ); + const utxoText = translate( + "screens/ConvertConfirmScreen", + "Resulting UTXO", + ); + const evmText = translate( + "screens/ConvertConfirmScreen", + "Resulting Tokens (EVM)", + ); + + switch (convertDirection) { + case ConvertDirection.accountToUtxos: + return [dvmText, utxoText]; + case ConvertDirection.utxosToAccount: + return [utxoText, dvmText]; + case ConvertDirection.dvmToEvm: + return [dvmText, evmText]; + case ConvertDirection.evmToDvm: + return [evmText, dvmText]; + default: + return [evmText, dvmText]; + } + }, [convertDirection]); + async function onSubmit(): Promise { if (hasPendingJob || hasPendingBroadcastJob) { return; } setIsSubmitting(true); - await constructSignedConversionAndSend( - { - mode, - amount, - }, - dispatch, - () => { - onTransactionBroadcast(isOnPage, navigation.dispatch); - }, - logger - ); + + if ( + [ + ConvertDirection.accountToUtxos, + ConvertDirection.utxosToAccount, + ].includes(convertDirection) + ) { + await constructSignedConversionAndSend( + { + convertDirection, + amount, + }, + dispatch, + () => { + onTransactionBroadcast(isOnPage, navigation.dispatch); + }, + logger, + ); + } else { + const nonce = provider + ? await provider.getTransactionCount(evmAddress) + : 0; + await constructSignedTransferDomain( + { + amount, + convertDirection, + sourceToken, + targetToken, + networkName, + chainId, + nonce, + evmAddress, + dvmAddress: address, + }, + dispatch, + () => { + onTransactionBroadcast(isOnPage, navigation.dispatch); + }, + logger, + ); + } + setIsSubmitting(false); } @@ -93,7 +154,7 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element { title: translate("screens/Settings", "Cancel transaction"), message: translate( "screens/Settings", - "By cancelling, you will lose any changes you made for your transaction." + "By cancelling, you will lose any changes you made for your transaction.", ), buttons: [ { @@ -107,7 +168,7 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element { navigation.navigate( originScreen === ScreenName.DEX_screen ? ScreenName.DEX_screen - : ScreenName.PORTFOLIO_screen + : ScreenName.PORTFOLIO_screen, ); }, }, @@ -126,20 +187,31 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element { { unit: translate( "screens/ConvertScreen", - getDisplayUnit(targetUnit) + `${targetToken.displayTextSymbol}${ + convertDirection === ConvertDirection.dvmToEvm ? " (EVM)" : "" + }`, ), - } + }, )} amount={amount} testID="text_convert_amount" - iconA="_UTXO" - fromAddress={address} + iconA={ + targetToken.tokenId === "0_evm" + ? "DFI (EVM)" + : targetToken.displaySymbol + } + fromAddress={ + convertDirection === ConvertDirection.evmToDvm + ? evmAddress + : address + } fromAddressLabel={addressLabel} + isEvmToken={convertDirection === ConvertDirection.dvmToEvm} /> , onBroadcast: () => void, - logger: NativeLoggingProps + logger: NativeLoggingProps, ): Promise { try { dispatch( transactionQueue.actions.push( - dfiConversionCrafter(amount, mode, onBroadcast, () => {}) - ) + dfiConversionCrafter(amount, convertDirection, onBroadcast, () => {}), + ), ); } catch (e) { logger.error(e); } } -function getResultingValue( - desireUnit: string, - fee: BigNumber, - balanceA: BigNumber, - unitA: string, - balanceB: BigNumber, - unitB: string -): string { - const balance = desireUnit === unitA ? balanceA : balanceB; - const unit = desireUnit === unitA ? unitA : unitB; +async function constructSignedTransferDomain( + { + amount, + convertDirection, + sourceToken, + targetToken, + networkName, + chainId, + dvmAddress, + evmAddress, + nonce, + }: { + convertDirection: ConvertDirection; + sourceToken: TransferDomainToken; + targetToken: TransferDomainToken; + amount: BigNumber; + networkName: NetworkName; + chainId?: number; + dvmAddress: string; + evmAddress: string; + nonce: number; + }, + dispatch: Dispatch, + onBroadcast: () => void, + logger: NativeLoggingProps, +): Promise { + try { + dispatch( + transactionQueue.actions.push( + transferDomainCrafter({ + amount, + convertDirection, + sourceToken, + targetToken, + networkName, + onBroadcast, + onConfirmation: () => {}, + chainId, + dvmAddress, + evmAddress, + nonce, + }), + ), + ); + } catch (e) { + logger.error(e); + } +} +function getResultingValue({ + balance, + convertDirection, + fee, +}: { + balance: BigNumber; + convertDirection: ConvertDirection; + fee: BigNumber; +}): string { return BigNumber.max( - balance.minus(unit === ConvertTokenUnit.UTXO ? fee : 0), - 0 + balance.minus( + convertDirection === ConvertDirection.accountToUtxos ? fee : 0, + ), + 0, ).toFixed(8); } -function getResultingPercentage( - desireUnit: string, - balanceA: BigNumber, - unitA: string, - balanceB: BigNumber -): string { - const amount = desireUnit === unitA ? balanceA : balanceB; +function getResultingPercentage({ + balanceA, + balanceB, +}: { + balanceA: BigNumber; + balanceB: BigNumber; +}): string { const totalAmount = balanceA.plus(balanceB); - return new BigNumber(amount).div(totalAmount).multipliedBy(100).toFixed(2); + return new BigNumber(balanceB).div(totalAmount).multipliedBy(100).toFixed(2); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertScreen.tsx index 6df72b199a..b2f69e2c28 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertScreen.tsx @@ -1,4 +1,3 @@ -import { AddressToken } from "@defichain/whale-api-client/dist/api/address"; import { NavigationProp, useNavigation } from "@react-navigation/native"; import { StackScreenProps } from "@react-navigation/stack"; import BigNumber from "bignumber.js"; @@ -24,7 +23,6 @@ import { import { getColor, tailwind } from "@tailwind"; import { translate } from "@translations"; import { useLogger } from "@shared-contexts/NativeLoggingProvider"; -import { getNativeIcon } from "@components/icons/assets"; import { ButtonV2 } from "@components/ButtonV2"; import { AmountButtonTypes, @@ -33,57 +31,69 @@ import { import { useToast } from "react-native-toast-notifications"; import { NumericFormat as NumberFormat } from "react-number-format"; import { getNumberFormatValue } from "@api/number-format-value"; +import { ConvertDirection } from "@screens/enum"; +import { + TokenDropdownButton, + TokenDropdownButtonStatus, +} from "@components/TokenDropdownButton"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { getNativeIcon } from "@components/icons/assets"; +import { EVMLinearGradient } from "@components/EVMLinearGradient"; import { PortfolioParamList } from "../PortfolioNavigator"; -import { TokenListType } from "../../Dex/CompositeSwap/SwapTokenSelectionScreen"; +import { + TokenListType, + SelectionToken, +} from "../../Dex/CompositeSwap/SwapTokenSelectionScreen"; import { useTokenPrice } from "../hooks/TokenPrice"; +import { DomainToken, useTokenBalance } from "../hooks/TokenBalance"; -export type ConversionMode = "utxosToAccount" | "accountToUtxos"; type Props = StackScreenProps; -interface ConversionIO extends AddressToken { - unit: ConvertTokenUnit; -} - enum InlineTextStatus { Default, Warning, Error, } -export enum ConvertTokenUnit { - UTXO = "UTXO", - Token = "Token", -} - export function ConvertScreen(props: Props): JSX.Element { const { getTokenPrice } = useTokenPrice(); const { isLight } = useThemeContext(); + const { domain, isEvmFeatureEnabled } = useDomainContext(); const client = useWhaleApiClient(); const logger = useLogger(); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const toast = useToast(); const TOAST_DURATION = 2000; // global state const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const navigation = useNavigation>(); - const [mode, setMode] = useState(props.route.params.mode); - const [sourceToken, setSourceToken] = useState(); - const [targetToken, setTargetToken] = useState(); + const [convertDirection, setConvertDirection] = useState( + props.route.params.convertDirection, + ); + const [sourceToken, setSourceToken] = useState( + props.route.params.sourceToken, + ); + const [targetToken, setTargetToken] = useState( + props.route.params.targetToken, + ); + const [convAmount, setConvAmount] = useState("0"); const [fee, setFee] = useState(new BigNumber(0.0001)); const [amount, setAmount] = useState(""); const [inlineTextStatus, setInlineTextStatus] = useState( - InlineTextStatus.Default + InlineTextStatus.Default, ); + const { dvmTokens, evmTokens } = useTokenBalance(); + useEffect(() => { client.fee .estimate() @@ -92,54 +102,82 @@ export function ConvertScreen(props: Props): JSX.Element { }, []); useEffect(() => { - const [source, target] = getDFIBalances(mode, tokens); - setSourceToken(source); - setTargetToken(target); - const sourceNum = new BigNumber( - source?.amount !== undefined && source.amount !== "" ? source.amount : 0 - ); const conversionNum = new BigNumber(amount).isNaN() ? new BigNumber(0) : new BigNumber(amount); const conversion = conversionNum.toString(); setConvAmount(conversion); - if (conversionNum.gt(sourceNum)) { + + if (conversionNum.gt(sourceToken.available)) { setInlineTextStatus(InlineTextStatus.Error); } else if ( - isUtxoToAccount(mode) && - !sourceNum.isZero() && - conversionNum.toFixed(8) === sourceNum.toFixed(8) + convertDirection === ConvertDirection.utxosToAccount && + !sourceToken.available.isZero() && + conversionNum.toFixed(8) === sourceToken.available.toFixed(8) ) { setInlineTextStatus(InlineTextStatus.Warning); } else { setInlineTextStatus(InlineTextStatus.Default); } - }, [mode, JSON.stringify(tokens), amount]); + }, [convertDirection, JSON.stringify(tokens), amount]); + + useEffect(() => { + let updatedConvertDirection: ConvertDirection = convertDirection; + + if (sourceToken.tokenId === "0_utxo" && targetToken?.tokenId === "0") { + updatedConvertDirection = ConvertDirection.utxosToAccount; + } else if ( + sourceToken.tokenId === "0" && + targetToken?.tokenId === "0_utxo" + ) { + updatedConvertDirection = ConvertDirection.accountToUtxos; + } else if ( + sourceToken.token.domainType === DomainType.DVM && + targetToken?.token.domainType === DomainType.EVM + ) { + updatedConvertDirection = ConvertDirection.dvmToEvm; + } else if ( + sourceToken.token.domainType === DomainType.EVM && + targetToken?.token.domainType === DomainType.DVM + ) { + updatedConvertDirection = ConvertDirection.evmToDvm; + } + + setConvertDirection(updatedConvertDirection); + }, [sourceToken, targetToken]); - if (sourceToken === undefined || targetToken === undefined) { + if (sourceToken === undefined) { return <>; } - function convert(sourceToken: ConversionIO, targetToken: ConversionIO): void { - if (hasPendingJob || hasPendingBroadcastJob) { + function convert(sourceToken: DomainToken, targetToken?: DomainToken): void { + if (hasPendingJob || hasPendingBroadcastJob || targetToken === undefined) { return; } navigation.navigate({ name: "ConvertConfirmationScreen", params: { - sourceUnit: sourceToken.unit, - sourceBalance: BigNumber.maximum( - new BigNumber(sourceToken.amount).minus(convAmount), - 0 - ), - targetUnit: targetToken.unit, - targetBalance: BigNumber.maximum( - new BigNumber(targetToken.amount).plus(convAmount), - 0 - ), - mode, amount: new BigNumber(amount), + convertDirection, fee, + sourceToken: { + tokenId: sourceToken.tokenId, + displaySymbol: sourceToken.token.displaySymbol, + balance: BigNumber.maximum( + new BigNumber(sourceToken.available).minus(convAmount), + 0, + ), + displayTextSymbol: sourceToken.token.displayTextSymbol, + }, + targetToken: { + tokenId: targetToken.tokenId, + displaySymbol: targetToken.token.displaySymbol, + balance: BigNumber.maximum( + new BigNumber(targetToken.available).plus(convAmount), + 0, + ), + displayTextSymbol: targetToken.token.displayTextSymbol, + }, }, merge: true, }); @@ -147,10 +185,10 @@ export function ConvertScreen(props: Props): JSX.Element { function onPercentagePress(amount: string, type: AmountButtonTypes): void { setAmount(amount); - showToast(type); + showToast(type, domain); } - function showToast(type: AmountButtonTypes): void { + function showToast(type: AmountButtonTypes, domain: DomainType): void { if (sourceToken === undefined) { return; } @@ -163,7 +201,9 @@ export function ConvertScreen(props: Props): JSX.Element { const toastOption = { unit: translate( "screens/ConvertScreen", - getDisplayUnit(sourceToken.unit) + `${sourceToken.token.displayTextSymbol}${ + domain === DomainType.EVM ? " (EVM)" : "" + }`, ), percent: type, }; @@ -175,15 +215,152 @@ export function ConvertScreen(props: Props): JSX.Element { } function onTogglePress(): void { - setMode(isUtxoToAccount(mode) ? "accountToUtxos" : "utxosToAccount"); + if (!targetToken || !sourceToken) { + return; + } + setSourceToken(targetToken); + setTargetToken(sourceToken); setAmount(""); } + function getListByDomain(listType: TokenListType): DomainToken[] { + if (listType === TokenListType.To) { + const evmDFIToken = evmTokens.find(({ tokenId }) => tokenId === "0_evm"); + const defaultEvmTargetToken = { + tokenId: `${sourceToken.tokenId}_evm`, + available: new BigNumber(evmDFIToken?.available ?? 0), + token: { + ...sourceToken.token, + displaySymbol: "DFI", + displayTextSymbol: "DFI", + name: `${sourceToken.token.name} for EVM`, + domainType: DomainType.EVM, + }, + }; + + if (domain === DomainType.DVM) { + if (sourceToken.tokenId === "0") { + return isEvmFeatureEnabled + ? [ + defaultEvmTargetToken, + ...dvmTokens.filter((token) => token.tokenId === "0_utxo"), + ] + : dvmTokens.filter((token) => token.tokenId === "0_utxo"); + } else if (sourceToken.tokenId === "0_utxo") { + return dvmTokens.filter((token) => token.tokenId === "0"); + } else { + return isEvmFeatureEnabled ? [defaultEvmTargetToken] : []; + } + } else if (domain === DomainType.EVM && sourceToken.tokenId === "0_evm") { + return isEvmFeatureEnabled ? [defaultEvmTargetToken] : []; + } + } + + return domain === DomainType.DVM ? dvmTokens : evmTokens; + } + + function onTokenSelect(item: SelectionToken, listType: TokenListType): void { + let updatedConvertDirection = convertDirection; + if ( + sourceToken.tokenId === "0" && + listType === TokenListType.To && + item.tokenId === "0_utxo" + ) { + // If from:DFI-DVM -> to: accountToUtxos + updatedConvertDirection = ConvertDirection.accountToUtxos; + } else if ( + sourceToken.tokenId === "0_utxo" && + listType === TokenListType.To && + item.tokenId === "0" + ) { + // If from:DFI-UTXO -> to: utxosToAccount + updatedConvertDirection = ConvertDirection.utxosToAccount; + } else if ( + sourceToken.tokenId === "0" && + listType === TokenListType.To && + item.tokenId === "0_evm" + ) { + updatedConvertDirection = ConvertDirection.dvmToEvm; + } + + let updatedTargetToken: SelectionToken | undefined; + const defaultTargetToken = { + tokenId: + domain === DomainType.DVM + ? `${item.tokenId}_evm` + : item.tokenId.replace("_evm", ""), + available: new BigNumber(0), + token: { + ...item.token, + name: + domain === DomainType.DVM + ? `${item.token.name} for EVM` + : item.token.name, + domainType: DomainType.EVM, + }, + }; + + if (listType === TokenListType.From) { + /* Move to a hook since it's used in portfolio page and convert screen */ + if (domain === DomainType.DVM && item.tokenId === "0_utxo") { + // If DFI UTXO -> choose DFI Token + updatedTargetToken = + dvmTokens.find((token) => token.tokenId === "0") ?? + defaultTargetToken; + } else if (domain === DomainType.DVM && item.tokenId === "0") { + // If DFI Token -> no default + updatedTargetToken = undefined; + } else if (domain === DomainType.EVM) { + // If EVM -> choose DVM equivalent + updatedTargetToken = + dvmTokens.find( + (token) => token.tokenId === item.tokenId.replace("_evm", ""), + ) ?? defaultTargetToken; + } else if (domain === DomainType.DVM) { + // If DVM -> choose EVM equivalent + updatedTargetToken = + evmTokens.find((token) => token.tokenId === `${item.tokenId}_evm`) ?? + defaultTargetToken; + } + /* End of what will be moved into a hook */ + } else { + updatedTargetToken = item; + } + + navigation.navigate({ + name: "ConvertScreen", + params: { + sourceToken: listType === TokenListType.From ? item : sourceToken, + targetToken: updatedTargetToken, + convertDirection: updatedConvertDirection, + }, + key: updatedTargetToken?.tokenId, + merge: true, + }); + } + + function navigateToTokenSelectionScreen(listType: TokenListType): void { + navigation.navigate("SwapTokenSelectionScreen", { + fromToken: { + symbol: sourceToken.token.symbol, + displaySymbol: sourceToken.token.displaySymbol, + }, + listType: listType, + list: getListByDomain(listType), + onTokenPress: (item) => { + onTokenSelect(item, listType); + }, + isFutureSwap: false, + isConvert: true, + isSearchDTokensOnly: false, + }); + } + return ( - + + {isEvmFeatureEnabled && ( + { + navigateToTokenSelectionScreen(TokenListType.From); + }} + status={TokenDropdownButtonStatus.Enabled} + /> + )} + {!isEvmFeatureEnabled && ( + + )} @@ -287,9 +484,9 @@ export function ConvertScreen(props: Props): JSX.Element { ? "A small amount of UTXO is reserved for fees" : "", { - amount: new BigNumber(sourceToken.amount).toFixed(8), - unit: getDisplayUnit(sourceToken.unit), - } + amount: new BigNumber(sourceToken.available).toFixed(8), + unit: sourceToken.token.displaySymbol, + }, )} @@ -299,7 +496,10 @@ export function ConvertScreen(props: Props): JSX.Element { light={tailwind("border-mono-light-v2-300")} style={tailwind("border-b-0.5 flex-1 h-1/2")} /> - + - {translate("screens/ConvertScreen", "TO RECEIVE")} + {translate("screens/ConvertScreen", "TO CONVERT")} @@ -343,8 +543,13 @@ export function ConvertScreen(props: Props): JSX.Element { /> - - - - - - {canConvert(convAmount, sourceToken.amount) && ( - - {`${translate( - "screens/ConvertScreen", - "Review full details in the next screen" - )}`} - + {sourceToken.tokenId === "0" && isEvmFeatureEnabled && ( + { + navigateToTokenSelectionScreen(TokenListType.To); + }} + status={TokenDropdownButtonStatus.Enabled} + /> + )} + {((sourceToken.tokenId !== "0" && targetToken) || + (!isEvmFeatureEnabled && targetToken)) && ( + )} + + {targetToken !== undefined && ( + + + {canConvert(convAmount, sourceToken.available) && ( + + {translate( + "screens/ConvertScreen", + "Review full details in the next screen", + )} + + )} + + )} tk.id === "0_utxo") as AddressToken) - : (tokens.find((tk) => tk.id === "0") as AddressToken); - const sourceUnit = isUtxoToAccount(mode) - ? ConvertTokenUnit.UTXO - : ConvertTokenUnit.Token; - - const target: AddressToken = isUtxoToAccount(mode) - ? (tokens.find((tk) => tk.id === "0") as AddressToken) - : (tokens.find((tk) => tk.id === "0_utxo") as AddressToken); - const targetUnit = isUtxoToAccount(mode) - ? ConvertTokenUnit.Token - : ConvertTokenUnit.UTXO; - - return [ - { - ...source, - unit: sourceUnit, - amount: getConvertibleUtxoAmount(mode, source), - }, - { - ...target, - unit: targetUnit, - }, - ]; -} - -function ConvertToggleButton(props: { onPress: () => void }): JSX.Element { +function ConvertToggleButton(props: { + isDisabled: boolean; + onPress: () => void; +}): JSX.Element { return ( @@ -474,7 +675,7 @@ function ConvertToggleButton(props: { onPress: () => void }): JSX.Element { function ConversionResultCard(props: { unit: string; - oriTargetAmount: string; + oriTargetAmount: BigNumber; totalTargetAmount: string; }): JSX.Element { return ( @@ -491,9 +692,9 @@ function ConversionResultCard(props: { light={tailwind("text-mono-light-v2-500")} dark={tailwind("text-mono-dark-v2-500")} > - {`${translate("screens/ConvertScreen", "Available {{unit}}", { + {translate("screens/ConvertScreen", "Available {{unit}}", { unit: translate("screens/ConvertScreen", props.unit), - })}`} + })} - {`${translate("screens/ConvertScreen", "Resulting {{unit}}", { + {translate("screens/ConvertScreen", "Resulting {{unit}}", { unit: translate("screens/ConvertScreen", props.unit), - })}`} + })} {props.symbol !== undefined && Icon !== undefined && ( - <> - + + - - + {props.unit} - + )} ); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/EvmFeatureFaq.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/EvmFeatureFaq.tsx new file mode 100644 index 0000000000..9abead7e22 --- /dev/null +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/EvmFeatureFaq.tsx @@ -0,0 +1,97 @@ +import { ThemedScrollViewV2, ThemedTextV2 } from "@components/themed"; +import { + AccordionContent, + WalletAccordionV2, +} from "@components/WalletAccordionV2"; +import { tailwind } from "@tailwind"; +import { translate } from "@translations"; + +export function EvmFeatureFaq(): JSX.Element { + const faqContent: AccordionContent[] = [ + { + title: translate( + "components/EvmFeatureFaq", + "What tokens are supported between DVM and EVM bidirectionally?", + ), + content: [ + { + text: translate( + "components/EvmFeatureFaq", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.", + ), + type: "paragraph", + }, + ], + }, + { + title: translate( + "components/EvmFeatureFaq", + "How can I access the MetaChain layer from the Light Wallet?", + ), + content: [ + { + text: translate( + "components/EvmFeatureFaq", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.", + ), + type: "paragraph", + }, + ], + }, + { + title: translate( + "components/EvmFeatureFaq", + "Why would I need to move dTokens from DVM to EVM?", + ), + content: [ + { + text: translate( + "components/EvmFeatureFaq", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.", + ), + type: "paragraph", + }, + ], + }, + { + title: translate( + "components/EvmFeatureFaq", + "How can I move dTokens from DVM to EVM?", + ), + content: [ + { + text: translate( + "components/EvmFeatureFaq", + 'You can do it through either the "Convert" or "Send" functions on Light Wallet. The "Convert" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe "Send" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.', + ), + type: "paragraph", + }, + ], + }, + ]; + + return ( + + + {translate( + "components/EvmFeatureFaq", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.", + )} + + + + + ); +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/CFPDetailScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/CFPDetailScreen.tsx index 00a457c237..d1d2bf4ca5 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/CFPDetailScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/CFPDetailScreen.tsx @@ -32,6 +32,8 @@ import { useWhaleApiClient } from "@waveshq/walletkit-ui/dist/contexts"; import { OCGProposalType } from "@screens/AppNavigator/screens/Portfolio/screens/OCG/OCGProposalsScreen"; import { AddressRow } from "@screens/AppNavigator/screens/Portfolio/components/AddressRow"; import { ButtonGroupTabKey } from "@screens/AppNavigator/screens/Portfolio/screens/AddressBookScreen"; +import { DomainType } from "@contexts/DomainContext"; +import { ConvertDirection } from "@screens/enum"; export function CFPDetailScreen(): JSX.Element { const logger = useLogger(); @@ -47,16 +49,16 @@ export function CFPDetailScreen(): JSX.Element { const [isUrlValid, setUrlValid] = useState(false); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const { isConversionRequired, conversionAmount } = useConversion({ @@ -107,7 +109,7 @@ export function CFPDetailScreen(): JSX.Element { navigation.goBack(); await trigger("address"); }, - [navigation] + [navigation], ); function onContinuePress() { @@ -136,7 +138,7 @@ export function CFPDetailScreen(): JSX.Element { if (isConversionRequired) { queueConvertTransaction( { - mode: "accountToUtxos", + mode: ConvertDirection.accountToUtxos, amount: conversionAmount, }, dispatch, @@ -157,7 +159,7 @@ export function CFPDetailScreen(): JSX.Element { params, merge: true, }); - } + }, ); } else { navigation.navigate("OCGConfirmScreen", params); @@ -183,7 +185,7 @@ export function CFPDetailScreen(): JSX.Element { @@ -207,7 +209,7 @@ export function CFPDetailScreen(): JSX.Element { "screens/OCGDetailScreen", titleStatus.shouldShowError ? "Title exceeds max character limit of 128." - : "Make sure that the name added here is the same as from the one posted in GitHub or Reddit." + : "Make sure that the name added here is the same as from the one posted in GitHub or Reddit.", ), style: tailwind("pl-5", { "text-red-v2": titleStatus.shouldShowError, @@ -226,7 +228,7 @@ export function CFPDetailScreen(): JSX.Element { onChangeText={setAmount} title={translate( "screens/OCGDetailScreen", - "AMOUNT REQUESTED IN DFI" + "AMOUNT REQUESTED IN DFI", )} placeholder="0.00 DFI" inputContainerStyle={tailwind("py-4.5")} @@ -249,6 +251,7 @@ export function CFPDetailScreen(): JSX.Element { name: "AddressBookScreen", params: { selectedAddress: getValues("address"), + addressDomainType: DomainType.DVM, onAddressSelect, disabledTab: ButtonGroupTabKey.Whitelisted, }, @@ -278,7 +281,7 @@ export function CFPDetailScreen(): JSX.Element { > {translate( "screens/OCGDetailScreen", - "Review full proposal details in the next screen" + "Review full proposal details in the next screen", )} setCycle( - Math.min(Math.floor(Number(cycle) + 1), maxCycle).toString() + Math.min(Math.floor(Number(cycle) + 1), maxCycle).toString(), ) } onRemove={() => setCycle( - Math.max(Math.floor(Number(cycle) - 1), minCycle).toString() + Math.max(Math.floor(Number(cycle) - 1), minCycle).toString(), ) } leftDisabled={Number(cycle) <= minCycle} @@ -383,6 +386,6 @@ function getCFPFee(requestedAmount?: BigNumber): BigNumber { const CFP_MIN_FEE = 10; const amount = requestedAmount ?? new BigNumber(0); return new BigNumber( - Math.max(amount.multipliedBy(0.01).toNumber(), CFP_MIN_FEE) + Math.max(amount.multipliedBy(0.01).toNumber(), CFP_MIN_FEE), ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/DFIPDetailScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/DFIPDetailScreen.tsx index 6b12d5752b..94b0e6a50a 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/DFIPDetailScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/OCG/DFIPDetailScreen.tsx @@ -27,6 +27,7 @@ import { useLogger } from "@shared-contexts/NativeLoggingProvider"; import { useWhaleApiClient } from "@waveshq/walletkit-ui/dist/contexts"; import { EnvironmentNetwork } from "@waveshq/walletkit-core"; import { OCGProposalType } from "@screens/AppNavigator/screens/Portfolio/screens/OCG/OCGProposalsScreen"; +import { ConvertDirection } from "@screens/enum"; export function DFIPDetailScreen(): JSX.Element { const logger = useLogger(); @@ -40,16 +41,16 @@ export function DFIPDetailScreen(): JSX.Element { const proposalFee = getDFIPFee(network); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const { isConversionRequired, conversionAmount } = useConversion({ inputToken: { @@ -108,7 +109,7 @@ export function DFIPDetailScreen(): JSX.Element { if (isConversionRequired) { queueConvertTransaction( { - mode: "accountToUtxos", + mode: ConvertDirection.accountToUtxos, amount: conversionAmount, }, dispatch, @@ -129,7 +130,7 @@ export function DFIPDetailScreen(): JSX.Element { params, merge: true, }); - } + }, ); } else { navigation.navigate("OCGConfirmScreen", params); @@ -157,7 +158,7 @@ export function DFIPDetailScreen(): JSX.Element { "screens/OCGDetailScreen", titleStatus.shouldShowError ? "Title exceeds max character limit of 128." - : "Make sure that the name added here is the same as from the one posted in GitHub or Reddit." + : "Make sure that the name added here is the same as from the one posted in GitHub or Reddit.", ), style: tailwind("pl-5", { "text-red-v2": titleStatus.shouldShowError, @@ -184,7 +185,7 @@ export function DFIPDetailScreen(): JSX.Element { > {translate( "screens/OCGDetailScreen", - "Review full proposal details in the next screen" + "Review full proposal details in the next screen", )} ({ setStringAsync: jest.fn(), })); diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ReceiveScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ReceiveScreen.tsx index 85ca211127..168858ec4b 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ReceiveScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ReceiveScreen.tsx @@ -17,10 +17,11 @@ import { useLogger, } from "@shared-contexts/NativeLoggingProvider"; import { debounce } from "lodash"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; export async function onShare( address: string, - logger: NativeLoggingProps + logger: NativeLoggingProps, ): Promise { try { await Share.share({ @@ -33,10 +34,12 @@ export async function onShare( export function ReceiveScreen(): JSX.Element { const logger = useLogger(); - const { address } = useWalletContext(); + const { address, evmAddress } = useWalletContext(); const [showToast, setShowToast] = useState(false); const toast = useToast(); + const { domain } = useDomainContext(); const TOAST_DURATION = 2000; + const receiveAddress = domain === DomainType.EVM ? evmAddress : address; const copyToClipboard = useCallback( debounce(() => { @@ -46,7 +49,7 @@ export function ReceiveScreen(): JSX.Element { setShowToast(true); setTimeout(() => setShowToast(false), TOAST_DURATION); }, 500), - [showToast] + [showToast], ); useEffect(() => { @@ -59,7 +62,7 @@ export function ReceiveScreen(): JSX.Element { } else { toast.hideAll(); } - }, [showToast, address]); + }, [showToast, receiveAddress]); return ( {translate( "screens/ReceiveScreen", - "Use QR or Wallet address to receive any tokens (DST) or DFI" + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI", )} - + @@ -99,14 +102,14 @@ export function ReceiveScreen(): JSX.Element { style={tailwind("font-normal-v2 text-sm text-center pb-12 px-5")} testID="address_text" > - {address} + {receiveAddress} { copyToClipboard(); - await Clipboard.setStringAsync(address); + await Clipboard.setStringAsync(receiveAddress); }} testID="copy_button" > @@ -119,7 +122,7 @@ export function ReceiveScreen(): JSX.Element { dark={tailwind("border-mono-dark-v2-300")} light={tailwind("border-mono-light-v2-300")} style={tailwind( - "py-4 mx-5 flex-row justify-center items-center border-b" + "py-4 mx-5 flex-row justify-center items-center border-b", )} > { - await onShare(address, logger); + await onShare(receiveAddress, logger); }} testID="share_button" > diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx index 4b35a0ed21..e2ecddfc61 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx @@ -32,7 +32,7 @@ import { import { useAppDispatch } from "@hooks/useAppDispatch"; import { useAddressLabel } from "@hooks/useAddressLabel"; import { View } from "@components"; -import { ScreenName } from "@screens/enum"; +import { ConvertDirection, ScreenName } from "@screens/enum"; import { ThemedActivityIndicatorV2, ThemedIcon, @@ -44,12 +44,20 @@ import { import { SummaryTitle } from "@components/SummaryTitle"; import { NumberRowV2 } from "@components/NumberRowV2"; import { SubmitButtonGroup } from "@components/SubmitButtonGroup"; +import { transferDomainSigner } from "@api/transaction/transfer_domain"; +import { + getAddressType, + AddressType as JellyfishAddressType, +} from "@waveshq/walletkit-core"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { useEVMProvider } from "@contexts/EVMProvider"; import { PortfolioParamList } from "../PortfolioNavigator"; type Props = StackScreenProps; export function SendConfirmationScreen({ route }: Props): JSX.Element { - const { address } = useWalletContext(); + const { domain } = useDomainContext(); + const { address, evmAddress } = useWalletContext(); const addressLabel = useAddressLabel(address); const network = useNetworkContext(); const { @@ -62,15 +70,18 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { toAddressLabel, addressType, originScreen, + matchedAddress, } = route.params; const logger = useLogger(); + const isEvmDomain = domain === DomainType.EVM; const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const dispatch = useAppDispatch(); + const { provider, chainId } = useEVMProvider(); const [isSubmitting, setIsSubmitting] = useState(false); const navigation = useNavigation>(); const [isOnPage, setIsOnPage] = useState(true); @@ -90,18 +101,22 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { return; } setIsSubmitting(true); + const nonce = provider ? await provider.getTransactionCount(evmAddress) : 0; await send( { address: destination, token, amount, + domain, + chainId, + nonce, networkName: network.networkName, }, dispatch, () => { onTransactionBroadcast(isOnPage, navigation.dispatch); }, - logger + logger, ); setIsSubmitting(false); } @@ -112,7 +127,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { title: translate("screens/Settings", "Cancel transaction"), message: translate( "screens/Settings", - "By cancelling, you will lose any changes you made for your transaction." + "By cancelling, you will lose any changes you made for your transaction.", ), buttons: [ { @@ -126,7 +141,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { navigation.navigate( originScreen === ScreenName.DEX_screen ? ScreenName.DEX_screen - : ScreenName.PORTFOLIO_screen + : ScreenName.PORTFOLIO_screen, ); }, }, @@ -142,13 +157,15 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { amount={amount} title={translate("screens/SendConfirmationScreen", "You are sending")} testID="text_send_amount" - iconA={tokenADisplaySymbol} + iconA={token.id === "0_evm" ? "DFI (EVM)" : tokenADisplaySymbol} iconB={tokenBDisplaySymbol} - fromAddress={address} + fromAddress={isEvmDomain ? evmAddress : address} + isEvmToken={isEvmDomain} fromAddressLabel={addressLabel} toAddress={destination} toAddressLabel={toAddressLabel} addressType={addressType} + matchedAddress={matchedAddress} /> {conversion?.isConversionRequired === true && ( @@ -164,7 +181,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { lhs={{ value: translate( "screens/SendConfirmationScreen", - "Amount to convert" + "Amount to convert", ), testID: "amount_to_convert", themedProps: { @@ -184,7 +201,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { /> {conversion?.isConverted !== true && ( @@ -221,7 +238,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { containerStyle={{ style: tailwind( "flex-row items-start w-full bg-transparent border-t-0.5 pt-5", - { "mt-8": conversion?.isConversionRequired !== true } + { "mt-8": conversion?.isConversionRequired !== true }, ), light: tailwind("bg-transparent border-mono-light-v2-300"), dark: tailwind("bg-transparent border-mono-dark-v2-300"), @@ -229,7 +246,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { lhs={{ value: translate( "screens/SendConfirmationScreen", - "Transaction fee" + "Transaction fee", ), testID: "transaction_fee", themedProps: { @@ -250,7 +267,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element { {translate( "screens/SendConfirmationScreen", - "I acknowledge that sending LP tokens to addresses that are not DeFiChain compatible wallets may result in irreversible loss of funds." + "I acknowledge that sending LP tokens to addresses that are not DeFiChain compatible wallets may result in irreversible loss of funds.", )} @@ -346,62 +363,81 @@ interface SendForm { amount: BigNumber; address: string; token: WalletToken; + domain: DomainType; + nonce: number; + chainId?: number; networkName: NetworkName; } async function send( - { address, token, amount, networkName }: SendForm, + { address, token, amount, domain, networkName, nonce, chainId }: SendForm, dispatch: Dispatch, onBroadcast: () => void, - logger: NativeLoggingProps + logger: NativeLoggingProps, ): Promise { try { - const to = DeFiAddress.from(networkName, address).getScript(); - - const signer = async ( - account: WhaleWalletAccount - ): Promise => { - const script = await account.getScript(); - const builder = account.withTransactionBuilder(); - - let signed: TransactionSegWit; - if (token.symbol === "DFI") { - /* if (amount.gte(token.amount)) signed = await builder.utxo.sendAll(to) - else */ - signed = await builder.utxo.send(amount, to, script); - } else { - signed = await builder.account.accountToAccount( - { - from: script, - to: [ - { - script: to, - balances: [ - { - token: +token.id, - amount, - }, - ], - }, - ], - }, - script - ); - } - return new CTransactionSegWit(signed); - }; - + const jellyfishAddressType = getAddressType(address, networkName); + const isDvmToDvmSend = + domain === DomainType.DVM && + jellyfishAddressType !== JellyfishAddressType.ETH; + const fromDisplaySymbol = token.id.includes("_evm") + ? `${token.displaySymbol} (EVM)` + : token.displaySymbol; dispatch( transactionQueue.actions.push({ - sign: signer, + sign: async (account: WhaleWalletAccount) => { + if (isDvmToDvmSend) { + return await dvmToDvmSendSigner( + account, + token, + amount, + address, + networkName, + ); + } else { + const sendDirection = + domain === DomainType.DVM + ? ConvertDirection.dvmToEvm + : ConvertDirection.evmToDvm; + const isEvmToDvm = sendDirection === ConvertDirection.evmToDvm; + const tokenId = token.id === "0_unified" ? "0" : token.id; + const sourceTokenId = + isEvmToDvm && !tokenId.includes("_evm") + ? `${tokenId}_evm` + : tokenId; + const targetTokenId = + !isEvmToDvm && !tokenId.includes("_evm") + ? `${tokenId}_evm` + : tokenId; + const dvmAddress = isEvmToDvm + ? address + : await account.getAddress(); + const evmAddress = isEvmToDvm + ? await account.getEvmAddress() + : address; + + return await transferDomainSigner({ + account, + sourceTokenId, + targetTokenId, + amount, + dvmAddress, + evmAddress, + networkName, + nonce, + chainId, + convertDirection: sendDirection, + }); + } + }, title: translate( "screens/SendConfirmationScreen", "Sending {{amount}} {{displaySymbol}} to {{toAddress}}", { amount: amount.toFixed(8), - displaySymbol: token.displaySymbol, + displaySymbol: fromDisplaySymbol, toAddress: address, - } + }, ), drawerMessages: { preparing: translate("screens/OceanInterface", "Preparing to send…"), @@ -410,22 +446,60 @@ async function send( "Sending {{amount}} {{displaySymbol}}", { amount: amount.toFixed(8), - displaySymbol: token.displaySymbol, - } + displaySymbol: fromDisplaySymbol, + }, ), complete: translate( "screens/OceanInterface", "{{amount}} {{displaySymbol}} sent", { amount: amount.toFixed(8), - displaySymbol: token.displaySymbol, - } + displaySymbol: fromDisplaySymbol, + }, ), }, onBroadcast, - }) + }), ); } catch (e) { logger.error(e); } } + +async function dvmToDvmSendSigner( + account: WhaleWalletAccount, + token: WalletToken, + amount: BigNumber, + address: string, + networkName: NetworkName, +): Promise { + const to = DeFiAddress.from(networkName, address).getScript(); + const script = await account.getScript(); + const builder = account.withTransactionBuilder(); + + let signed: TransactionSegWit; + if (token.symbol === "DFI") { + /* if (amount.gte(token.amount)) signed = await builder.utxo.sendAll(to) + else */ + signed = await builder.utxo.send(amount, to, script); + } else { + signed = await builder.account.accountToAccount( + { + from: script, + to: [ + { + script: to, + balances: [ + { + token: +token.id, + amount, + }, + ], + }, + ], + }, + script, + ); + } + return new CTransactionSegWit(signed); +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendScreen.tsx index 7a60cdbf93..f0b2546d53 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendScreen.tsx @@ -20,7 +20,7 @@ import { tokensSelector, WalletToken, } from "@waveshq/walletkit-ui/dist/store"; -import { LocalAddress } from "@store/userPreferences"; +import { LocalAddress, WhitelistedAddress } from "@store/userPreferences"; import { useDisplayUtxoWarning } from "@hooks/wallet/DisplayUtxoWarning"; import { queueConvertTransaction, @@ -42,6 +42,12 @@ import { import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { AddressRow } from "@screens/AppNavigator/screens/Portfolio/components/AddressRow"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { ConvertDirection } from "@screens/enum"; +import { + AddressType as AddressCategory, + getAddressType as getAddressCategory, +} from "@waveshq/walletkit-core"; import { useTokenPrice } from "../hooks/TokenPrice"; import { ActiveUSDValueV2 } from "../../Loans/VaultDetail/components/ActiveUSDValueV2"; import { PortfolioParamList } from "../PortfolioNavigator"; @@ -65,6 +71,7 @@ export interface BottomSheetToken { export function SendScreen({ route, navigation }: Props): JSX.Element { const dispatch = useAppDispatch(); const logger = useLogger(); + const { isEvmFeatureEnabled } = useDomainContext(); const { networkName } = useNetworkContext(); const client = useWhaleApiClient(); const { isLight } = useThemeContext(); @@ -76,27 +83,31 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { const bottomInset = useSafeAreaInsets().bottom; const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); + const { domain } = useDomainContext(); const [token, setToken] = useState(route.params?.token); - const [matchedAddress, setMatchedAddress] = useState(); + const [matchedAddress, setMatchedAddress] = useState< + LocalAddress | WhitelistedAddress + >(); const [fee, setFee] = useState(new BigNumber(0.0001)); const [transactionCardStatus, setTransactionCardStatus] = useState( - TransactionCardStatus.Default + TransactionCardStatus.Default, ); + const [addressLabel, setAddressLabel] = useState(""); // form const { control, setValue, formState, getValues, trigger, watch } = useForm({ @@ -104,20 +115,33 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { }); const { address } = watch(); const amountToSend = getValues("amount"); + const isEvmAddress = + getAddressCategory(getValues("address"), networkName) === + AddressCategory.ETH; + const [addressType, setAddressType] = useState(); + const getInputTokenType = () => { + if (token?.id === "0_unified") { + if (isEvmAddress) { + return "token"; + } + return "utxo"; + } + return "others"; + }; const { isConversionRequired, conversionAmount } = useConversion({ inputToken: { - type: token?.id === "0_unified" ? "utxo" : "others", + type: getInputTokenType(), amount: new BigNumber(amountToSend), }, - deps: [amountToSend, JSON.stringify(token)], + deps: [amountToSend, JSON.stringify(token), isEvmAddress], }); const reservedDFI = 0.1; const isReservedUtxoUsed = getDisplayUtxoWarningStatus( new BigNumber(amountToSend), - token?.displaySymbol ?? "" + token?.displaySymbol ?? "", ); const amountInputRef = useRef(); @@ -141,6 +165,25 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { light: tailwind("text-red-v2"), }; status = TransactionCardStatus.Error; + } else if (isEvmAddress && !isEvmFeatureEnabled) { + infoText = + "Transferring non-DAT tokens or LP tokens to an EVM address is not enabled"; + themedProps = { + dark: tailwind("text-red-v2"), + light: tailwind("text-red-v2"), + }; + status = TransactionCardStatus.Error; + } else if ( + isEvmAddress && + (token?.isDAT === false || token?.isLPS === true) + ) { + infoText = + "Transferring non-DAT tokens or LP tokens to an EVM address is not supported"; + themedProps = { + dark: tailwind("text-red-v2"), + light: tailwind("text-red-v2"), + }; + status = TransactionCardStatus.Error; } else if ( token?.isLPS === true && new BigNumber(amountToSend).isGreaterThan(0) @@ -173,7 +216,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { style: tailwind("text-xs mt-2 ml-5 font-normal-v2"), }, }; - }, [token, isReservedUtxoUsed, amountToSend]); + }, [token, isReservedUtxoUsed, amountToSend, address]); useEffect(() => { setToken(route.params.token); @@ -201,10 +244,10 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { setToken({ ...t, amount: - t.displaySymbol === "DFI" + t.displaySymbol === "DFI" && t.id !== "0_evm" ? BigNumber.max( new BigNumber(t.amount).minus(reservedDFI), - 0 + 0, ).toFixed(8) : t.amount, }); @@ -238,7 +281,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { navigation.goBack(); await trigger("address"); }, - [navigation] + [navigation], ); async function onSubmit(): Promise { @@ -258,14 +301,17 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { amount: new BigNumber(values.amount), amountInUsd: amountInUSDValue, fee, - toAddressLabel: matchedAddress?.label, + toAddressLabel: addressLabel, addressType, + matchedAddress, }; if (isConversionRequired) { queueConvertTransaction( { - mode: "accountToUtxos", + mode: isEvmAddress + ? ConvertDirection.utxosToAccount + : ConvertDirection.accountToUtxos, amount: conversionAmount, }, dispatch, @@ -296,7 +342,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { params, merge: true, }); - } + }, ); } else { navigation.navigate({ @@ -318,7 +364,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { contentContainerStyle={tailwind("pt-6 pb-8")} testID="send_screen" style={tailwind( - `${isLight ? "bg-mono-light-v2-100" : "bg-mono-dark-v2-100"}` + `${isLight ? "bg-mono-light-v2-100" : "bg-mono-dark-v2-100"}`, )} extraScrollHeight={-BOTTOM_NAV_HEIGHT - bottomInset} > @@ -326,7 +372,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { {translate( "screens/SendScreen", - "Select a token you want to send to get started" + "Select a token you want to send to get started", )} )} @@ -341,7 +387,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { render={({ field: { onChange, value } }) => ( new BigNumber( - value !== undefined && value !== "" ? value : 0 + value !== undefined && value !== "" ? value : 0, ).isGreaterThan(0), }, }} @@ -389,7 +435,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { }} onAmountChange={async ( amount: string, - type: AmountButtonTypes + type: AmountButtonTypes, ) => { showToast(type); setValue("amount", amount, { shouldDirty: true }); @@ -411,6 +457,7 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { name: "AddressBookScreen", params: { selectedAddress: getValues("address"), + addressDomainType: domain, onAddressSelect, }, merge: true, @@ -439,6 +486,9 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { address={address} onMatchedAddress={setMatchedAddress} onAddressType={setAddressType} + matchedAddress={matchedAddress} + setMatchedAddress={setMatchedAddress} + setAddressLabel={setAddressLabel} /> )} @@ -454,11 +504,11 @@ export function SendScreen({ route, navigation }: Props): JSX.Element { {isConversionRequired ? translate( "screens/SendScreen", - "By continuing, the required amount of DFI will be converted" + "By continuing, the required amount of DFI will be converted", ) : translate( "screens/SendScreen", - "Review full details in the next screen" + "Review full details in the next screen", )} )} @@ -494,6 +544,7 @@ function AmountCard({ onPress, onAmountChange, }: AmountForm): JSX.Element { + const { domain } = useDomainContext(); const maxAmount = BigNumber.max(token.amount, 0); return ( <> @@ -514,7 +565,7 @@ function AmountCard({ > diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx index 2c8a12d44c..d92d7a6674 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx @@ -13,7 +13,10 @@ import { unifiedDFISelector, WalletToken, } from "@waveshq/walletkit-ui/dist/store"; -import { useDeFiScanContext } from "@shared-contexts/DeFiScanContext"; +import { + getMetaScanTokenUrl, + useDeFiScanContext, +} from "@shared-contexts/DeFiScanContext"; import { PoolPairData } from "@defichain/whale-api-client/dist/api/poolpairs"; import { View } from "@components"; import { @@ -29,14 +32,17 @@ import { RootState } from "@store"; import { ButtonV2 } from "@components/ButtonV2"; import { InfoTextLinkV2 } from "@components/InfoTextLink"; import { ThemedTouchableListItem } from "@components/themed/ThemedTouchableListItem"; +import { ConvertDirection } from "@screens/enum"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; +import { useNetworkContext } from "@waveshq/walletkit-ui"; import { PortfolioParamList } from "../PortfolioNavigator"; -import { ConversionMode } from "./ConvertScreen"; import { useTokenPrice } from "../hooks/TokenPrice"; import { useDenominationCurrency } from "../hooks/PortfolioCurrency"; import { TokenBreakdownDetailsV2 } from "../components/TokenBreakdownDetailsV2"; import { getPrecisedTokenValue } from "../../Auctions/helpers/precision-token-value"; import { PortfolioButtonGroupTabKey } from "../components/TotalPortfolio"; import { TokenIcon } from "../components/TokenIcon"; +import { useTokenBalance } from "../hooks/TokenBalance"; interface TokenActionItems { title: string; @@ -50,7 +56,7 @@ interface TokenActionItems { type Props = StackScreenProps; const usePoolPairToken = ( - tokenParam: WalletToken + tokenParam: WalletToken, ): { pair?: PoolPairData; token: WalletToken; @@ -58,7 +64,7 @@ const usePoolPairToken = ( } => { const pairs = useSelector((state: RootState) => state.wallet.poolpairs); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); // state @@ -104,28 +110,32 @@ const usePoolPairToken = ( export function TokenDetailScreen({ route, navigation }: Props): JSX.Element { const { denominationCurrency } = useDenominationCurrency(); + const { domain } = useDomainContext(); + const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); const { getTokenPrice } = useTokenPrice(denominationCurrency); // input based on selected denomination from portfolio tab const DFIUnified = useSelector((state: RootState) => - unifiedDFISelector(state.wallet) + unifiedDFISelector(state.wallet), ); const availableValue = getTokenPrice( DFIUnified.symbol, - new BigNumber(DFIUnified.amount) + new BigNumber(DFIUnified.amount), ); const DFIToken = useSelector((state: RootState) => - DFITokenSelector(state.wallet) + DFITokenSelector(state.wallet), ); const DFIUtxo = useSelector((state: RootState) => - DFIUtxoSelector(state.wallet) + DFIUtxoSelector(state.wallet), ); const { pair, token, swapTokenDisplaySymbol } = usePoolPairToken( - route.params.token + route.params.token, ); + const { dvmTokens, evmTokens } = useTokenBalance(); + // usdAmount for crypto tokens, undefined for DFI token const { usdAmount } = route.params.token; - + const isEvmDomain = domain === DomainType.EVM; const onNavigateLiquidity = ({ destination, pair, @@ -180,21 +190,24 @@ export function TokenDetailScreen({ route, navigation }: Props): JSX.Element { token={token} border usdAmount={usdAmount ?? new BigNumber(0)} + isEvmDomain={isEvmDomain} /> - - {token.symbol === "DFI" && ( + {!isEvmDomain && ( + + )} + {token.symbol === "DFI" && token.id !== "0_evm" && ( navigation.navigate("Receive")} testID="receive_button" - title={`${translate("screens/TokenDetailScreen", "Receive")}`} + title={translate("screens/TokenDetailScreen", "Receive")} /> )} - {token.symbol === "DFI" && ( + {token.symbol === "DFI" && token.id !== "0_evm" && ( + { + const convertDirection: ConvertDirection = + token.id === "0_utxo" + ? ConvertDirection.utxosToAccount + : ConvertDirection.accountToUtxos; + + const utxoToken = dvmTokens.find( + (token) => token.tokenId === "0_utxo", + ); + const dfiToken = dvmTokens.find( + (token) => token.tokenId === "0", + ); + const [sourceToken, targetToken] = + convertDirection === ConvertDirection.utxosToAccount + ? [utxoToken, dfiToken] + : [dfiToken, utxoToken]; + + navigation.navigate({ + name: "ConvertScreen", + params: { + sourceToken, + targetToken, + convertDirection, + }, + merge: true, + }); + }} + testID="convert_button" + title={translate( + "screens/TokenDetailScreen", + "Convert to {{symbol}}", + { symbol: "Token/UTXO" }, + )} + /> + )} + + {token.id === "0_evm" && ( { - const mode: ConversionMode = - token.id === "0_utxo" ? "utxosToAccount" : "accountToUtxos"; + const convertDirection: ConvertDirection = + domain === DomainType.DVM + ? ConvertDirection.dvmToEvm + : ConvertDirection.evmToDvm; + + const evmToken = evmTokens.find( + (token) => token.tokenId === "0_evm", + ); + const dfiToken = dvmTokens.find( + (token) => token.tokenId === "0", + ); + const [sourceToken, targetToken] = + convertDirection === ConvertDirection.evmToDvm + ? [evmToken, dfiToken] + : [dfiToken, evmToken]; + navigation.navigate({ name: "ConvertScreen", - params: { mode }, + params: { + sourceToken, + targetToken, + convertDirection, + }, merge: true, }); }} testID="convert_button" - title={`${translate( + title={translate( "screens/TokenDetailScreen", "Convert to {{symbol}}", - { symbol: `${token.id === "0_utxo" ? "Token" : "UTXO"}` } - )}`} + { symbol: "Token" }, + )} /> )} {token.isLPS && pair !== undefined && ( @@ -289,7 +366,7 @@ export function TokenDetailScreen({ route, navigation }: Props): JSX.Element { testID="remove_liquidity_button" title={translate( "screens/TokenDetailScreen", - "Remove liquidity" + "Remove liquidity", )} /> )} @@ -325,13 +402,13 @@ export function TokenDetailScreen({ route, navigation }: Props): JSX.Element { testID="add_liquidity_button" label={translate( "screens/TokenDetailScreen", - "Add liquidity" + "Add liquidity", )} /> )} - {token.symbol === "DFI" && ( + {token.symbol === "DFI" && !isEvmDomain && ( @@ -370,28 +447,24 @@ function TokenSummary(props: { token: WalletToken; border?: boolean; usdAmount: BigNumber; + isEvmDomain?: boolean; }): JSX.Element { const { denominationCurrency } = useDenominationCurrency(); const { getTokenUrl } = useDeFiScanContext(); + const { network } = useNetworkContext(); const onTokenUrlPressed = async (): Promise => { const id = - props.token.id === "0_utxo" || props.token.id === "0_unified" + props.token.id === "0_utxo" || + props.token.id === "0_unified" || + props.token.id === "0_evm" ? 0 : props.token.id; - const url = getTokenUrl(id); + const url = props.token.id.includes("_evm") + ? getMetaScanTokenUrl(network, props.token.id) + : getTokenUrl(id); await Linking.openURL(url); }; - const DFIUnified = useSelector((state: RootState) => - unifiedDFISelector(state.wallet) - ); - const { getTokenPrice } = useTokenPrice(denominationCurrency); // input based on selected denomination from portfolio tab - const dfiUsdAmount = getTokenPrice( - DFIUnified.symbol, - new BigNumber(DFIUnified.amount), - DFIUnified.isLPS - ); - return ( @@ -420,7 +495,7 @@ function TokenSummary(props: { dark={tailwind("text-mono-dark-v2-700")} style={tailwind("text-sm font-normal-v2")} > - {props.token.name} + {props.token.name || props.token.symbol} ( )} thousandSeparator - value={ - props.token.symbol === "DFI" - ? getPrecisedTokenValue(dfiUsdAmount) - : getPrecisedTokenValue(props.usdAmount) - } + value={getPrecisedTokenValue(props.usdAmount)} /> )} diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenSelectionScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenSelectionScreen.tsx index 2fa8b1dfe9..215de23ffa 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenSelectionScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenSelectionScreen.tsx @@ -27,10 +27,12 @@ import { SkeletonLoaderScreen, } from "@components/SkeletonLoader"; import { ListRenderItemInfo } from "@shopify/flash-list"; +import { DomainType, useDomainContext } from "@contexts/DomainContext"; import { PortfolioParamList } from "../PortfolioNavigator"; import { ActiveUSDValueV2 } from "../../Loans/VaultDetail/components/ActiveUSDValueV2"; import { TokenIcon } from "../components/TokenIcon"; import { TokenNameText } from "../components/TokenNameText"; +import { useEvmTokenBalances } from "../hooks/EvmTokenBalances"; export interface TokenSelectionItem extends BottomSheetToken { usdAmount: BigNumber; @@ -51,25 +53,37 @@ export interface BottomSheetToken { export function TokenSelectionScreen(): JSX.Element { const { isLight } = useThemeContext(); + const { domain } = useDomainContext(); const navigation = useNavigation>(); const tokens = useSelector((state: RootState) => - tokensSelector(state.wallet) + tokensSelector(state.wallet), ); + const { evmTokens } = useEvmTokenBalances(); + const { hasFetchedToken } = useSelector((state: RootState) => state.wallet); + const { hasFetchedEvmTokens } = useSelector((state: RootState) => state.evm); const [searchString, setSearchString] = useState(""); const { getTokenPrice } = useTokenPrice(); const debouncedSearchTerm = useDebounce(searchString, 250); const [isSearchFocus, setIsSearchFocus] = useState(false); const searchRef = useRef(); + const isEvmDomain = domain === DomainType.EVM; + + const filteredTokensByDomain = isEvmDomain ? evmTokens : tokens; - const tokensWithBalance = getTokensWithBalance(tokens, getTokenPrice); + const tokensWithBalance = getTokensWithBalance( + filteredTokensByDomain, + getTokenPrice, + ); const filteredTokensWithBalance = useMemo(() => { return filterTokensBySearchTerm(tokensWithBalance, debouncedSearchTerm); }, [tokensWithBalance, debouncedSearchTerm]); - if (hasFetchedToken && tokensWithBalance.length === 0) { - return ; + const hasFetchedDvmEvmTokens = + hasFetchedToken || (isEvmDomain && hasFetchedEvmTokens); + if (hasFetchedDvmEvmTokens && tokensWithBalance.length === 0) { + return ; } return ( @@ -84,11 +98,14 @@ export function TokenSelectionScreen(): JSX.Element { return ( { navigation.navigate({ name: "SendScreen", params: { - token: tokens.find((t) => item.tokenId === t.id), + token: filteredTokensByDomain.find( + (t) => t.id === item.tokenId, + ), }, merge: true, }); @@ -118,7 +135,7 @@ export function TokenSelectionScreen(): JSX.Element { }} placeholder={translate( "screens/TokenSelectionScreen", - "Search token" + "Search token", )} showClearButton={debouncedSearchTerm !== ""} onClearInput={() => { @@ -138,7 +155,7 @@ export function TokenSelectionScreen(): JSX.Element { ref={searchRef} /> - {(!hasFetchedToken || debouncedSearchTerm.trim() === "") && ( + {(!hasFetchedDvmEvmTokens || debouncedSearchTerm.trim() === "") && ( )} - {hasFetchedToken && debouncedSearchTerm.trim() !== "" && ( + {hasFetchedDvmEvmTokens && debouncedSearchTerm.trim() !== "" && ( )} - {!hasFetchedToken && ( + {!hasFetchedDvmEvmTokens && ( @@ -202,7 +221,9 @@ function TokenSelectionRow({ token={{ isLPS: item.token.isLPS, displaySymbol: item.token.displaySymbol, + id: item.tokenId, }} + isEvmToken={isEvmDomain} size={36} /> ; + isEvmDomain: boolean; }): JSX.Element { return ( @@ -268,15 +291,17 @@ function EmptyAsset({ > {translate( "screens/TokenSelectionScreen", - "Add assets to get started" + "Add assets to get started", )} - navigation.navigate("GetDFIScreen" as any)} - styleProps="w-full mb-14 pb-1" - label={translate("screens/GetDFIScreen", "Get DFI")} - /> + {!isEvmDomain && ( + navigation.navigate("GetDFIScreen" as any)} + styleProps="w-full mb-14 pb-1" + label={translate("screens/GetDFIScreen", "Get DFI")} + /> + )} ); } @@ -286,19 +311,20 @@ function getTokensWithBalance( getTokenPrice: ( symbol: string, amount: BigNumber, - isLPS?: boolean | undefined - ) => BigNumber + isLPS?: boolean | undefined, + ) => BigNumber, ): TokenSelectionItem[] { const reservedFees = 0.1; const filteredTokens: TokenSelectionItem[] = []; tokens.forEach((t) => { const available = new BigNumber( - t.displaySymbol === "DFI" + t.displaySymbol === "DFI" && t.id !== "0_evm" ? new BigNumber(t.amount).minus(reservedFees).toFixed(8) - : t.amount + : t.amount, ); - if (available.isLessThan(0) || t.id === "0" || t.id === "0_utxo") { + + if (available.isLessThanOrEqualTo(0) || t.id === "0" || t.id === "0_utxo") { return; } @@ -318,17 +344,17 @@ function getTokensWithBalance( }); return filteredTokens.sort((a, b) => - b.usdAmount.minus(a.usdAmount).toNumber() + b.usdAmount.minus(a.usdAmount).toNumber(), ); } function filterTokensBySearchTerm( tokens: TokenSelectionItem[], - searchTerm: string + searchTerm: string, ): TokenSelectionItem[] { return tokens.filter((t) => [t.token.displaySymbol, t.token.name].some((searchItem) => - searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()) - ) + searchItem.toLowerCase().includes(searchTerm.trim().toLowerCase()), + ), ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/__snapshots__/ReceiveScreen.test.tsx.snap b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/__snapshots__/ReceiveScreen.test.tsx.snap index 303197a36c..a670665d2a 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/__snapshots__/ReceiveScreen.test.tsx.snap +++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/__snapshots__/ReceiveScreen.test.tsx.snap @@ -46,7 +46,7 @@ exports[`receive page should match snapshot 1`] = ` ] } > - Use QR or Wallet address to receive any tokens (DST) or DFI + Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI void; disabledTab?: ButtonGroupTabKey; }; AddOrEditAddressBookScreen: { title: string; onSaveButtonPress: (address?: string) => void; - addressLabel?: LocalAddress; + addressLabel?: WhitelistedAddress; + addressDomainType?: DomainType; address?: string; isAddNew: boolean; }; @@ -151,7 +155,7 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "screens/LanguageSelectionScreen", - "Select language" + "Select language", ), headerBackTitleVisible: false, }} @@ -171,7 +175,7 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "screens/AddOrEditAddressBookScreen", - "Add Address" + "Add Address", ), }} /> @@ -231,7 +235,7 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "components/RecoveryWordFaq", - "About Recovery Words" + "About Recovery Words", ), }} /> @@ -250,7 +254,7 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "components/LiquidityMiningFaq", - "About Liquidity Mining" + "About Liquidity Mining", ), }} /> @@ -261,7 +265,7 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "components/UtxoVsTokenFaq", - "About UTXO And Tokens" + "About UTXO And Tokens", ), }} /> @@ -272,7 +276,18 @@ export function SettingsNavigator(): JSX.Element { options={{ headerTitle: translate( "components/CfpDfipProposalsFaq", - "About Governance" + "About Governance", + ), + }} + /> + + diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx index 8d3445dd4d..87ad57a70b 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/SettingsScreen.tsx @@ -27,6 +27,7 @@ import { useAddressBook } from "@hooks/useAddressBook"; import { useAppDispatch } from "@hooks/useAppDispatch"; import { useFeatureFlagContext } from "@contexts/FeatureFlagContext"; import { useLanguageContext } from "@shared-contexts/LanguageProvider"; +import { useCustomServiceProviderContext } from "@contexts/CustomServiceProvider"; import { RowThemeItem } from "./components/RowThemeItem"; import { SettingsParamList } from "./SettingsNavigator"; @@ -41,13 +42,15 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { data: { type }, } = useWalletNodeContext(); const isEncrypted = type === "MNEMONIC_ENCRYPTED"; - const { isCustomUrl } = useServiceProviderContext(); + const { isCustomUrl: isCustomDvmUrl } = useServiceProviderContext(); + const { isCustomEvmUrl, isCustomEthRpcUrl } = + useCustomServiceProviderContext(); const { isFeatureAvailable } = useFeatureFlagContext(); const { language } = useLanguageContext(); const languages = getAppLanguages(); - const selectedLanguage = languages.find((languageItem) => - language?.startsWith(languageItem.locale) + const selectedLanguage = languages.find( + (languageItem) => language?.startsWith(languageItem.locale), ); const revealRecoveryWords = useCallback(() => { @@ -68,11 +71,11 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { message: translate("screens/UnlockWallet", "Enter passcode to continue"), loading: translate( "screens/UnlockWallet", - "It may take a few seconds to verify" + "It may take a few seconds to verify", ), title: translate( "screens/UnlockWallet", - "Provide your passcode to view recovery words." + "Provide your passcode to view recovery words.", ), successMessage: translate("screens/UnlockWallet", "Passcode verified!"), }; @@ -102,11 +105,11 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { message: translate("screens/UnlockWallet", "Enter passcode to continue"), loading: translate( "screens/UnlockWallet", - "It may take a few seconds to verify" + "It may take a few seconds to verify", ), title: translate( "screens/UnlockWallet", - "Provide existing passcode to change passcode." + "Provide existing passcode to change passcode.", ), successMessage: translate("screens/UnlockWallet", "Passcode verified!"), }; @@ -142,7 +145,11 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { testID="setting_navigate_service_provider" label="Provider" border - value={isCustomUrl ? "Custom" : "Default"} + value={ + isCustomDvmUrl || isCustomEvmUrl || isCustomEthRpcUrl + ? "Custom (3rd-party)" + : "Default" + } onPress={() => navigation.navigate("ServiceProviderScreen", {})} /> )} @@ -198,7 +205,7 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { > {translate( "screens/Settings", - "Auto-locks wallet if there is no activity for 1 min." + "Auto-locks wallet if there is no activity for 1 min.", )} )} @@ -230,7 +237,7 @@ export function SettingsScreen({ navigation }: Props): JSX.Element { > {translate( "screens/Settings", - "This will unlink your wallet from the app." + "This will unlink your wallet from the app.", )} @@ -245,11 +252,11 @@ function RowExitWalletItem(): JSX.Element { WalletAlert({ title: translate( "screens/Settings", - "Are you sure you want to unlink your wallet?" + "Are you sure you want to unlink your wallet?", ), message: translate( "screens/Settings", - "Once unlinked, you will need to enter your recovery words to restore your wallet." + "Once unlinked, you will need to enter your recovery words to restore your wallet.", ), buttons: [ { @@ -340,7 +347,7 @@ function NavigateItemRow({ @@ -358,6 +365,7 @@ function NavigateItemRow({ light={tailwind("text-mono-light-v2-700")} dark={tailwind("text-mono-dark-v2-700")} style={tailwind("font-normal-v2 text-sm mr-1")} + testID={`${testID}_value`} > {translate("screens/Settings", value)} diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/components/CustomUrlInput.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/components/CustomUrlInput.tsx new file mode 100644 index 0000000000..dea612c104 --- /dev/null +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/components/CustomUrlInput.tsx @@ -0,0 +1,140 @@ +import { View } from "@components"; +import { WalletTextInputV2 } from "@components/WalletTextInputV2"; +import { + ThemedIcon, + ThemedSectionTitleV2, + ThemedTouchableOpacityV2, +} from "@components/themed"; +import { CustomServiceProviderType } from "@contexts/CustomServiceProvider"; +import { tailwind } from "@tailwind"; +import { translate } from "@translations"; +import { useEffect, useState } from "react"; + +export interface CustomServiceProvider { + type: CustomServiceProviderType; + url: string; + defaultUrl: string; + label: string; + helperText: string; +} + +interface Props extends CustomServiceProvider { + inputValue: { url: string; isValid: boolean }; + isDisabled: boolean; + activeInput: CustomServiceProviderType | undefined; + setActiveInput: (type: CustomServiceProviderType | undefined) => void; + setShowActionButtons: (show: boolean) => void; + handleUrlInputChange: ( + type: CustomServiceProviderType, + value: string, + ) => void; +} + +export function CustomUrlInput({ + type, + url, + defaultUrl, + label, + helperText, + inputValue, + isDisabled, + activeInput, + setActiveInput, + setShowActionButtons, + handleUrlInputChange, +}: Props): JSX.Element { + const [isUnlocked, setIsUnlocked] = useState(false); + const [errMsg, setErrMsg] = useState(); + const [displayTickIcon, setDisplayTickIcon] = useState(true); + + // clear input on unlock + useEffect(() => { + if (isUnlocked && url === defaultUrl) { + return handleUrlInputChange(type, ""); + } + }, [isUnlocked]); + + // show err msg when input is invalid + useEffect(() => { + if (inputValue.isValid || inputValue.url === "") { + setErrMsg(undefined); + } else { + setErrMsg("Invalid URL"); + } + }, [inputValue]); + + // to display tick icon + useEffect(() => { + if (!isUnlocked && inputValue.isValid) { + return setDisplayTickIcon(true); + } else if (inputValue.url === "" && !inputValue.isValid) { + return setDisplayTickIcon(false); + } + }, [inputValue]); + + return ( + + + + handleUrlInputChange(type, text)} + onClearButtonPress={() => handleUrlInputChange(type, "")} + placeholder={translate("screens/ServiceProviderScreen", defaultUrl)} + style={tailwind("font-normal-v2 flex-1 py-2.5")} + containerStyle="flex-1 pr-3" + testID={`${type}_endpoint_url_input`} + inlineText={{ + type: errMsg !== undefined ? "error" : "helper", + text: translate( + "screens/ServiceProviderScreen", + errMsg || helperText, + ), + style: { paddingLeft: 20 }, + }} + displayClearButton={ + inputValue.url !== "" && + inputValue.url !== undefined && + isUnlocked && + !displayTickIcon + } + displayTickIcon={displayTickIcon} + /> + { + setIsUnlocked(true); + setShowActionButtons(true); + setActiveInput(type); + }} + light={tailwind("bg-mono-light-v2-900", { + "bg-opacity-70": isUnlocked, + "bg-opacity-30": + (!isUnlocked && activeInput !== undefined) || isDisabled, + })} + dark={tailwind("bg-mono-dark-v2-900", { + "bg-opacity-70": isUnlocked, + "bg-opacity-30": + (!isUnlocked && activeInput !== undefined) || isDisabled, + })} + style={tailwind("mt-2 h-10 w-10 p-2.5 text-center rounded-full")} + disabled={isUnlocked || isDisabled} + testID={`${type}_edit_service_provider`} + > + + + + + ); +} diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/components/ResetButton.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/components/ResetButton.tsx index f116f02232..ad61313aa5 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/components/ResetButton.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/components/ResetButton.tsx @@ -1,8 +1,5 @@ -import { ThemedTextV2, ThemedTouchableOpacityV2 } from "@components/themed"; -import { tailwind } from "@tailwind"; import { translate } from "@translations"; import { WalletAlert } from "@components/WalletAlert"; -import { View, Text } from "react-native"; import { NavigationProp, useNavigation } from "@react-navigation/native"; import React, { useCallback } from "react"; import { authentication, Authentication } from "@store/authentication"; @@ -16,21 +13,38 @@ import { hasOceanTXQueued, } from "@waveshq/walletkit-ui/dist/store"; import { useServiceProviderContext } from "@waveshq/walletkit-ui"; +import { ButtonV2 } from "@components/ButtonV2"; +import { + CustomServiceProviderType, + useCustomServiceProviderContext, +} from "@contexts/CustomServiceProvider"; +import { useDomainContext } from "@contexts/DomainContext"; import { SettingsParamList } from "../SettingsNavigator"; export function ResetButton(): JSX.Element { + const { isEvmFeatureEnabled } = useDomainContext(); const navigation = useNavigation>(); const logger = useLogger(); const dispatch = useAppDispatch(); const hasPendingJob = useSelector((state: RootState) => - hasTxQueued(state.transactionQueue) + hasTxQueued(state.transactionQueue), ); const hasPendingBroadcastJob = useSelector((state: RootState) => - hasOceanTXQueued(state.ocean) + hasOceanTXQueued(state.ocean), ); - const { url, defaultUrl, setUrl } = useServiceProviderContext(); + const { + url: dvmUrl, + defaultUrl: defaultDvmUrl, + setUrl: setDvmUrl, + } = useServiceProviderContext(); + const { evmUrl, ethRpcUrl, defaultEvmUrl, defaultEthRpcUrl, setCustomUrl } = + useCustomServiceProviderContext(); + + const isDisabled = + dvmUrl === defaultDvmUrl && + evmUrl === defaultEvmUrl && + ethRpcUrl === defaultEthRpcUrl; - const isDisabled = url === defaultUrl; const resetServiceProvider = useCallback(() => { // to check if user's transactions to be completed before resetting url if (hasPendingJob || hasPendingBroadcastJob) { @@ -39,21 +53,36 @@ export function ResetButton(): JSX.Element { const auth: Authentication = { consume: async (passphrase) => await MnemonicStorage.get(passphrase), onAuthenticated: async () => { - setUrl(defaultUrl); + await Promise.all([ + setDvmUrl(defaultDvmUrl), + ...(isEvmFeatureEnabled + ? [ + setCustomUrl(defaultEvmUrl, CustomServiceProviderType.EVM), + setCustomUrl( + defaultEthRpcUrl, + CustomServiceProviderType.ETHRPC, + ), + ] + : []), + ]); navigation.goBack(); }, onError: (e) => logger.error(e), title: translate( "screens/ServiceProviderScreen", - "Reset default service provider" + "Reset default service provider", ), message: translate( "screens/ServiceProviderScreen", - "Enter passcode to continue" + "Enter passcode to continue", ), loading: translate("screens/ServiceProviderScreen", "Verifying access"), additionalMessage: translate("screens/ServiceProviderScreen", "Default"), - additionalMessageUrl: defaultUrl, + additionalMessageUrl: [ + defaultDvmUrl, + defaultEvmUrl, + defaultEthRpcUrl, + ].join(" and "), }; dispatch(authentication.actions.prompt(auth)); }, [dispatch, navigation]); @@ -63,11 +92,11 @@ export function ResetButton(): JSX.Element { WalletAlert({ title: translate( "screens/ServiceProviderScreen", - "Reset Service Provider" + "Reset Service Provider", ), message: translate( "screens/ServiceProviderScreen", - "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?" + "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?", ), buttons: [ { @@ -85,33 +114,13 @@ export function ResetButton(): JSX.Element { }); }; return ( - - - - {translate("screens/ServiceProviderScreen", "Reset provider")} - - - - {translate( - "screens/ServiceProviderScreen", - "This will reset the service provider\nto the default URL." - )} - - + ); } diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/AboutScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/AboutScreen.tsx index 447b1b566d..76da3c4b8d 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/AboutScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/AboutScreen.tsx @@ -162,14 +162,14 @@ export function AboutScreen(): JSX.Element { {translate("screens/AboutScreen", "Developed by")} {translate("screens/AboutScreen", "Birthday Research")} @@ -216,7 +216,7 @@ export function AboutScreen(): JSX.Element { > {translate( "screens/CommunityScreen", - "DeFiChain is a community-driven and open project. The DeFiChain Foundation does not provide direct support." + "DeFiChain is a community-driven and open project. The DeFiChain Foundation does not provide direct support.", )} @@ -246,7 +246,7 @@ function LinkItemRow({ light={tailwind("bg-mono-light-v2-00")} onPress={handlePress} style={tailwind( - "flex-row px-5 py-4 items-center rounded-lg-v2 mb-2 mx-5 border-0" + "flex-row px-5 py-4 items-center rounded-lg-v2 mb-2 mx-5 border-0", )} testID={testID} > @@ -288,7 +288,7 @@ function SocialLink({ light={tailwind("bg-mono-light-v2-900")} onPress={handlePress} style={tailwind( - "justify-center items-center rounded-full w-10 h-10 mx-4 border-0" + "justify-center items-center rounded-full w-10 h-10 mx-4 border-0", )} testID={testID} > diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/FeatureFlagScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/FeatureFlagScreen.tsx index 5432e6bbb5..16371190ea 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/FeatureFlagScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/FeatureFlagScreen.tsx @@ -33,7 +33,7 @@ export function FeatureFlagScreen(): JSX.Element { } return features; }, - [] + [], ); }; @@ -43,7 +43,7 @@ export function FeatureFlagScreen(): JSX.Element { const onFeatureChange = async ( feature: FeatureFlag, - value: boolean + value: boolean, ): Promise => { const message = feature.id === "ocg_cfp_dfip" @@ -57,7 +57,7 @@ export function FeatureFlagScreen(): JSX.Element { title: translate( "screens/FeatureFlagScreen", "Enable {{feature}} (Beta)", - { feature: translate("screens/Settings", feature.name) } + { feature: translate("screens/Settings", feature.name) }, ), message: translate("screens/FeatureFlagScreen", message), buttons: [ @@ -87,7 +87,7 @@ export function FeatureFlagScreen(): JSX.Element { {translate( "screens/FeatureFlagScreen", - "Light Wallet beta features are in the user acceptance testing phase. Using beta feature(s) is encouraged, but caution is advised when using your assets." + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.", )} @@ -113,7 +113,7 @@ export function FeatureFlagItem({ dark={tailwind("bg-black")} light={tailwind("bg-white")} style={tailwind( - "flex flex-row p-4 mx-5 items-center justify-between rounded-lg" + "flex flex-row p-4 mx-5 items-center justify-between rounded-lg", )} > navigation.navigate("EvmFeatureFaq"), + }, ]; return ( @@ -113,7 +119,7 @@ function NavigateItemRow({ onPress={onPress} style={tailwind( "flex ml-5 mr-4 py-4.5 flex-row items-center justify-between", - { "border-b": border } + { "border-b": border }, )} testID={testID} > diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/ServiceProviderScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/ServiceProviderScreen.tsx index 9553d006b1..6fe6cc80d4 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/ServiceProviderScreen.tsx +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/ServiceProviderScreen.tsx @@ -1,13 +1,8 @@ -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useState } from "react"; import { Dimensions, Platform, Text, View } from "react-native"; import { tailwind } from "@tailwind"; import { translate } from "@translations"; -import { - ThemedScrollViewV2, - ThemedIcon, - ThemedSectionTitleV2, - ThemedTouchableOpacityV2, -} from "@components/themed"; +import { ThemedScrollViewV2 } from "@components/themed"; import { ButtonV2 } from "@components/ButtonV2"; import { authentication, Authentication } from "@store/authentication"; import { MnemonicStorage } from "@api/wallet/mnemonic_storage"; @@ -18,25 +13,94 @@ import { useServiceProviderContext, useWalletNodeContext, } from "@waveshq/walletkit-ui"; -import { WalletTextInputV2 } from "@components/WalletTextInputV2"; +import { + CustomServiceProviderType, + useCustomServiceProviderContext, +} from "@contexts/CustomServiceProvider"; +import { useDomainContext } from "@contexts/DomainContext"; import { SettingsParamList } from "../SettingsNavigator"; import { ResetButton } from "../components/ResetButton"; +import { + CustomServiceProvider, + CustomUrlInput, +} from "../components/CustomUrlInput"; type Props = StackScreenProps; +type CustomUrlInputState = { + [key in CustomServiceProviderType]: { + url: string; + isValid: boolean; + }; +}; export function ServiceProviderScreen({ navigation }: Props): JSX.Element { + const { isEvmFeatureEnabled } = useDomainContext(); const logger = useLogger(); const dispatch = useAppDispatch(); // show all content for small screen and web to adjust margins and paddings const isSmallScreen = Platform.OS === "web" || Dimensions.get("window").height <= 667; - const { url, defaultUrl, setUrl } = useServiceProviderContext(); - const [labelInput, setLabelInput] = useState(url); - const [isValid, setIsValid] = useState(false); - const [isUnlocked, setIsUnlocked] = useState(false); - const [errMsg, setErrMsg] = useState(""); - const [displayTickIcon, setDisplayTickIcon] = useState(true); + // get all default urls from context + const { + url: dvmUrl, + defaultUrl: defaultDvmUrl, + setUrl: setDvmUrl, + } = useServiceProviderContext(); + const { evmUrl, ethRpcUrl, defaultEvmUrl, defaultEthRpcUrl, setCustomUrl } = + useCustomServiceProviderContext(); + + const [urlInputValues, setUrlInputValues] = useState({ + [CustomServiceProviderType.DVM]: { url: dvmUrl, isValid: true }, + [CustomServiceProviderType.EVM]: { url: evmUrl, isValid: true }, + [CustomServiceProviderType.ETHRPC]: { url: ethRpcUrl, isValid: true }, + }); + const [activeInput, setActiveInput] = useState(); + const [showActionButtons, setShowActionButtons] = useState(false); + + const customProviders: CustomServiceProvider[] = [ + { + type: CustomServiceProviderType.DVM, + url: dvmUrl, + defaultUrl: defaultDvmUrl, + label: "ENDPOINT URL (DVM)", + helperText: "Used to get balance from Native DFC (MainNet and TestNet)", + }, + ...(isEvmFeatureEnabled + ? [ + { + type: CustomServiceProviderType.EVM, + url: evmUrl, + defaultUrl: defaultEvmUrl, + label: "ENDPOINT URL (EVM)", + helperText: "Used to get balance from EVM (MainNet and TestNet)", + }, + { + type: CustomServiceProviderType.ETHRPC, + url: ethRpcUrl, + defaultUrl: defaultEthRpcUrl, + label: "ENDPOINT URL (ETH-RPC)", + helperText: "Used to get Nonce and Chain ID", + }, + ] + : []), + ]; + + // Check customized urls + const getCustomizedUrls = () => { + const changedUrls: string[] = []; + const { DVM, EVM, ETHRPC } = urlInputValues; + if (DVM.url !== defaultDvmUrl) { + changedUrls.push(DVM.url); + } + if (EVM.url !== defaultEvmUrl) { + changedUrls.push(EVM.url); + } + if (ETHRPC.url !== defaultEthRpcUrl) { + changedUrls.push(ETHRPC.url); + } + return changedUrls; + }; // Passcode prompt const { @@ -48,152 +112,113 @@ export function ServiceProviderScreen({ navigation }: Props): JSX.Element { return; } + const customUrls = getCustomizedUrls().join(" and "); const auth: Authentication = { consume: async (passphrase) => await MnemonicStorage.get(passphrase), onAuthenticated: async () => { - await setUrl(labelInput); + const { DVM, EVM, ETHRPC } = urlInputValues; + await Promise.all([ + setDvmUrl(DVM.url), + ...(isEvmFeatureEnabled + ? [ + setCustomUrl(EVM.url, CustomServiceProviderType.EVM), + setCustomUrl(ETHRPC.url, CustomServiceProviderType.ETHRPC), + ] + : []), + ]); navigation.pop(); }, onError: (e) => logger.error(e), - title: translate( + title: `${translate( "screens/ServiceProviderScreen", - "Adding custom service provider" - ), + "Adding custom service providers", + )} ${customUrls}`, message: translate( "screens/ServiceProviderScreen", - "Enter passcode to continue" + "Enter passcode to continue", ), loading: translate("screens/ServiceProviderScreen", "Verifying access"), additionalMessage: translate("screens/ServiceProviderScreen", "Custom"), - additionalMessageUrl: labelInput, + additionalMessageUrl: customUrls, }; dispatch(authentication.actions.prompt(auth)); - }, [dispatch, isEncrypted, navigation, labelInput]); + }, [dispatch, isEncrypted, navigation, urlInputValues]); const validateInputlabel = (input: string): boolean => { if (input === "" || !/^https/.test(input)) { - setIsValid(false); - setErrMsg("Invalid URL"); return false; } - setErrMsg(""); - setIsValid(true); return true; }; - // to enable continue button - useEffect(() => { - if (validateInputlabel(labelInput)) { - return setIsValid(true); - } - return setIsValid(false); - }, [labelInput]); - - // hide err msg when input is empty - useEffect(() => { - if (labelInput === "") { - return setErrMsg(""); - } - }, [labelInput]); - - // clear input on unlock and not display warning msg - useEffect(() => { - if (isUnlocked && url === defaultUrl) { - return setLabelInput(""); - } - }, [isUnlocked]); - - // to display tick icon - useEffect(() => { - if (!isUnlocked && isValid) { - return setDisplayTickIcon(true); - } else if (labelInput === "" && !isValid) { - return setDisplayTickIcon(false); - } - }, [labelInput, isValid]); + const handleUrlInputChange = ( + type: CustomServiceProviderType, + value: string, + ) => { + const updatedInputValues = { + ...urlInputValues, + [type]: { + ...urlInputValues[type], + url: value, + isValid: validateInputlabel(value), + }, + }; + setUrlInputValues(updatedInputValues); + }; return ( - - - { - setLabelInput(_text); - validateInputlabel(_text); - }} - onClearButtonPress={() => { - setLabelInput(""); - validateInputlabel(""); - }} - placeholder={translate("screens/ServiceProviderScreen", defaultUrl)} - style={tailwind("font-normal-v2 flex-1 py-2.5")} - containerStyle="flex-1" - testID="endpoint_url_input" - inlineText={{ - type: "error", - text: translate("screens/ServiceProviderScreen", errMsg), - }} - displayClearButton={ - labelInput !== "" && - labelInput !== undefined && - isUnlocked && - !displayTickIcon - } - displayTickIcon={displayTickIcon} - /> - setIsUnlocked(true)} - light={tailwind("bg-mono-light-v2-900", { - "bg-opacity-30": isUnlocked, - })} - dark={tailwind("bg-mono-dark-v2-900", { - "bg-opacity-30": isUnlocked, - })} - style={tailwind("ml-3 h-10 w-10 p-2.5 text-center rounded-full")} - disabled={isUnlocked} - testID="edit_service_provider" - > - + {customProviders.map((provider) => ( + - + ))} - {isUnlocked && ( - <> - - + {showActionButtons && ( + + + {translate( "screens/ServiceProviderScreen", - "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app." + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.", )} - - - )} - {isUnlocked && ( - await submitCustomServiceProvider()} - disabled={!isValid} + disabled={ + !( + urlInputValues.DVM.isValid && + urlInputValues.EVM.isValid && + urlInputValues.ETHRPC.isValid + ) + } /> + )} diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/FeatureFlagScreen.test.tsx.snap b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/FeatureFlagScreen.test.tsx.snap index 3fe21df86f..c4534b1ab6 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/FeatureFlagScreen.test.tsx.snap +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/FeatureFlagScreen.test.tsx.snap @@ -169,7 +169,7 @@ exports[`feature flag screen should render FeatureFlagScreen 1`] = ` ] } > - Light Wallet beta features are in the user acceptance testing phase. Using beta feature(s) is encouraged, but caution is advised when using your assets. + Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets. + + + MetaChain (EVM) + + + diff --git a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/NetworkSelectionScreen.test.tsx.snap b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/NetworkSelectionScreen.test.tsx.snap index 19e2dc0d68..a0883469c0 100644 --- a/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/NetworkSelectionScreen.test.tsx.snap +++ b/mobile-app/app/screens/AppNavigator/screens/Settings/screens/__snapshots__/NetworkSelectionScreen.test.tsx.snap @@ -450,7 +450,9 @@ exports[`onboarding network selection screen should render 1`] = ` + + + + Changi + + + + { style={tailwind("items-end pt-5 px-5 rounded-t-xl-v2")} testID="cancel_authorization" disabled={[TransactionStatus.BLOCK, TransactionStatus.SIGNING].includes( - props.status + props.status, )} > { light={tailwind("text-mono-light-v2-900")} iconType="Feather" name="x-circle" - size={20} + size={22} /> @@ -105,7 +105,7 @@ const PromptContent = React.memo((props: PasscodePromptProps): JSX.Element => { )} {([TransactionStatus.SIGNING, TransactionStatus.AUTHORIZED].includes( - props.status + props.status, ) || (props.status === TransactionStatus.PIN && !props.isRetry)) && ( { ? "Incorrect passcode.\n{{attemptsRemaining}} attempts remaining" : "{{attemptsRemaining}} attempts remaining" }`, - { attemptsRemaining: props.attemptsRemaining } + { attemptsRemaining: props.attemptsRemaining }, )} ) @@ -251,7 +251,7 @@ export const PasscodePrompt = React.memo( ); - } + }, ); function EmptyHandleComponent(): JSX.Element { diff --git a/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/CreateWalletGuidelines.tsx b/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/CreateWalletGuidelines.tsx index 7af3a6bffb..9b7547ebae 100644 --- a/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/CreateWalletGuidelines.tsx +++ b/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/CreateWalletGuidelines.tsx @@ -1,4 +1,3 @@ -import { Feather } from "@expo/vector-icons"; import { StackScreenProps } from "@react-navigation/stack"; import { useState } from "react"; import * as React from "react"; @@ -18,26 +17,55 @@ import DarkNewWallet from "@assets/images/dark-wallet-guidelines.png"; import LightNewWallet from "@assets/images/light-wallet-guidelines.png"; import { useThemeContext } from "@waveshq/walletkit-ui"; import { ButtonV2 } from "@components/ButtonV2"; +import { WalletIcon } from "@components/icons/WalletIcon"; import { WalletParamList } from "../../WalletNavigator"; import { LearnMoreCTA } from "../components/LearnModeCTA"; type Props = StackScreenProps; interface GuidelineItem { - icon: React.ComponentProps["name"]; title: string; + Icon?: () => JSX.Element; } const guidelines: GuidelineItem[] = [ { title: "Write the words on paper. Take note of their correct spelling and order.", - icon: "edit-2", + Icon: (): JSX.Element => ( + + ), }, { title: "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.", - icon: "lock", + Icon: (): JSX.Element => ( + + ), + }, + { + title: + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.", + Icon: (): JSX.Element => { + const { isLight } = useThemeContext(); + return ( + + ); + }, }, ]; @@ -63,7 +91,7 @@ export function CreateWalletGuidelines({ navigation }: Props): JSX.Element { > {translate( "screens/Guidelines", - "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet." + "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.", )} - + {g.Icon?.()} {translate( "screens/Guidelines", - "I understand it is my responsibility to keep my recovery words secure. Losing them will result in the irrecoverable loss of access to my wallet funds." + "I understand it is my responsibility to keep my recovery words secure. Losing them will result in the irrecoverable loss of access to my wallet funds.", )} diff --git a/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/__snapshots__/CreateWalletGuidelines.test.tsx.snap b/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/__snapshots__/CreateWalletGuidelines.test.tsx.snap index d894b684d0..72712feaf7 100644 --- a/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/__snapshots__/CreateWalletGuidelines.test.tsx.snap +++ b/mobile-app/app/screens/WalletNavigator/screens/CreateWallet/__snapshots__/CreateWalletGuidelines.test.tsx.snap @@ -299,6 +299,157 @@ exports[`create wallet guidelines v2 should match snapshot 1`] = ` Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone. + + + + + + + + + + + A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain. + + + + + + Changi + + + + , + , ]; // Needs for it to work on web. Otherwise, it takes full window size @@ -69,6 +78,7 @@ export function ImageSlide({ return ( diff --git a/mobile-app/app/screens/enum.ts b/mobile-app/app/screens/enum.ts index 8a56a14686..33f49ae2d5 100644 --- a/mobile-app/app/screens/enum.ts +++ b/mobile-app/app/screens/enum.ts @@ -4,3 +4,10 @@ export enum ScreenName { LOANS_screen = "LoansScreen", AUCTIONS_screen = "AuctionsScreen", } + +export enum ConvertDirection { + evmToDvm = "evmToDvm", + dvmToEvm = "dvmToEvm", + utxosToAccount = "utxosToAccount", + accountToUtxos = "accountToUtxos", +} diff --git a/mobile-app/app/styles.json b/mobile-app/app/styles.json index 5a20c698e1..9613b28352 100644 --- a/mobile-app/app/styles.json +++ b/mobile-app/app/styles.json @@ -4389,9 +4389,15 @@ "w-16": { "width": 64 }, + "w-18": { + "width": 76 + }, "w-20": { "width": 80 }, + "w-21": { + "width": 84 + }, "w-24": { "width": 96 }, @@ -4817,6 +4823,12 @@ "borderBottomRightRadius": 9999, "borderBottomLeftRadius": 9999 }, + "rounded-sm-v2": { + "borderTopLeftRadius": 5, + "borderTopRightRadius": 5, + "borderBottomRightRadius": 5, + "borderBottomLeftRadius": 5 + }, "rounded-lg-v2": { "borderTopLeftRadius": 10, "borderTopRightRadius": 10, @@ -4871,6 +4883,10 @@ "borderTopLeftRadius": 9999, "borderTopRightRadius": 9999 }, + "rounded-t-sm-v2": { + "borderTopLeftRadius": 5, + "borderTopRightRadius": 5 + }, "rounded-t-lg-v2": { "borderTopLeftRadius": 10, "borderTopRightRadius": 10 @@ -4919,6 +4935,10 @@ "borderTopRightRadius": 9999, "borderBottomRightRadius": 9999 }, + "rounded-r-sm-v2": { + "borderTopRightRadius": 5, + "borderBottomRightRadius": 5 + }, "rounded-r-lg-v2": { "borderTopRightRadius": 10, "borderBottomRightRadius": 10 @@ -4967,6 +4987,10 @@ "borderBottomRightRadius": 9999, "borderBottomLeftRadius": 9999 }, + "rounded-b-sm-v2": { + "borderBottomRightRadius": 5, + "borderBottomLeftRadius": 5 + }, "rounded-b-lg-v2": { "borderBottomRightRadius": 10, "borderBottomLeftRadius": 10 @@ -5015,6 +5039,10 @@ "borderTopLeftRadius": 9999, "borderBottomLeftRadius": 9999 }, + "rounded-l-sm-v2": { + "borderTopLeftRadius": 5, + "borderBottomLeftRadius": 5 + }, "rounded-l-lg-v2": { "borderTopLeftRadius": 10, "borderBottomLeftRadius": 10 @@ -5054,6 +5082,9 @@ "rounded-tl-full": { "borderTopLeftRadius": 9999 }, + "rounded-tl-sm-v2": { + "borderTopLeftRadius": 5 + }, "rounded-tl-lg-v2": { "borderTopLeftRadius": 10 }, @@ -5090,6 +5121,9 @@ "rounded-tr-full": { "borderTopRightRadius": 9999 }, + "rounded-tr-sm-v2": { + "borderTopRightRadius": 5 + }, "rounded-tr-lg-v2": { "borderTopRightRadius": 10 }, @@ -5126,6 +5160,9 @@ "rounded-br-full": { "borderBottomRightRadius": 9999 }, + "rounded-br-sm-v2": { + "borderBottomRightRadius": 5 + }, "rounded-br-lg-v2": { "borderBottomRightRadius": 10 }, @@ -5162,6 +5199,9 @@ "rounded-bl-full": { "borderBottomLeftRadius": 9999 }, + "rounded-bl-sm-v2": { + "borderBottomLeftRadius": 5 + }, "rounded-bl-lg-v2": { "borderBottomLeftRadius": 10 }, @@ -6655,6 +6695,20 @@ "borderBottomColor": "rgba(0, 173, 29, var(--tw-border-opacity))", "borderLeftColor": "rgba(0, 173, 29, var(--tw-border-opacity))" }, + "border-evm-light": { + "--tw-border-opacity": 1, + "borderTopColor": "rgba(149, 178, 235, var(--tw-border-opacity))", + "borderRightColor": "rgba(149, 178, 235, var(--tw-border-opacity))", + "borderBottomColor": "rgba(149, 178, 235, var(--tw-border-opacity))", + "borderLeftColor": "rgba(149, 178, 235, var(--tw-border-opacity))" + }, + "border-evm-dark": { + "--tw-border-opacity": 1, + "borderTopColor": "rgba(77, 123, 193, var(--tw-border-opacity))", + "borderRightColor": "rgba(77, 123, 193, var(--tw-border-opacity))", + "borderBottomColor": "rgba(77, 123, 193, var(--tw-border-opacity))", + "borderLeftColor": "rgba(77, 123, 193, var(--tw-border-opacity))" + }, "border-opacity-0": { "--tw-border-opacity": 0 }, @@ -7467,6 +7521,14 @@ "--tw-bg-opacity": 1, "backgroundColor": "rgba(0, 173, 29, var(--tw-bg-opacity))" }, + "bg-evm-light": { + "--tw-bg-opacity": 1, + "backgroundColor": "rgba(149, 178, 235, var(--tw-bg-opacity))" + }, + "bg-evm-dark": { + "--tw-bg-opacity": 1, + "backgroundColor": "rgba(77, 123, 193, var(--tw-bg-opacity))" + }, "bg-opacity-0": { "--tw-bg-opacity": 0 }, @@ -9446,6 +9508,14 @@ "--tw-text-opacity": 1, "color": "rgba(0, 173, 29, var(--tw-text-opacity))" }, + "text-evm-light": { + "--tw-text-opacity": 1, + "color": "rgba(149, 178, 235, var(--tw-text-opacity))" + }, + "text-evm-dark": { + "--tw-text-opacity": 1, + "color": "rgba(77, 123, 193, var(--tw-text-opacity))" + }, "text-opacity-0": { "--tw-text-opacity": 0 }, @@ -10410,6 +10480,14 @@ "--tw-ring-opacity": 1, "--tw-ring-color": "rgba(0, 173, 29, var(--tw-ring-opacity))" }, + "ring-evm-light": { + "--tw-ring-opacity": 1, + "--tw-ring-color": "rgba(149, 178, 235, var(--tw-ring-opacity))" + }, + "ring-evm-dark": { + "--tw-ring-opacity": 1, + "--tw-ring-color": "rgba(77, 123, 193, var(--tw-ring-opacity))" + }, "ring-opacity-0": { "--tw-ring-opacity": 0 }, @@ -11046,6 +11124,12 @@ "ring-offset-green-v2": { "--tw-ring-offset-color": "#00AD1D" }, + "ring-offset-evm-light": { + "--tw-ring-offset-color": "#95B2EB" + }, + "ring-offset-evm-dark": { + "--tw-ring-offset-color": "#4D7BC1" + }, "filter": { "--tw-blur": "var(--tw-empty, )", "--tw-brightness": "var(--tw-empty, )", diff --git a/mobile-app/app/tailwind.config.js b/mobile-app/app/tailwind.config.js index 5fe963adca..69f91855da 100644 --- a/mobile-app/app/tailwind.config.js +++ b/mobile-app/app/tailwind.config.js @@ -161,6 +161,8 @@ module.exports = { "red-v2": "#E54545", "orange-v2": "#D97B01", "green-v2": "#00AD1D", + "evm-light":"#95B2EB", + "evm-dark":"#4D7BC1", }, maxWidth: { "1/4": "25%", @@ -179,6 +181,7 @@ module.exports = { 1.5: 1.5, }, borderRadius: { + "sm-v2": 5, "lg-v2": 10, "xl-v2": 15, "2xl-v2": 20, @@ -193,6 +196,8 @@ module.exports = { }, width: { 15: 60, + 18: 76, + 21: 84 }, height: { 15: 60, diff --git a/mobile-app/cypress/e2e/functional/transferDomain/addresses.spec.ts b/mobile-app/cypress/e2e/functional/transferDomain/addresses.spec.ts new file mode 100644 index 0000000000..c84c0f5342 --- /dev/null +++ b/mobile-app/cypress/e2e/functional/transferDomain/addresses.spec.ts @@ -0,0 +1,226 @@ +context("Portfolio - Send - Address Book", () => { + const labels = ["DVMAddress", "EVMAddress"]; + const addresses = [ + "bcrt1q8rfsfny80jx78cmk4rsa069e2ckp6rn83u6ut9", + "0x2DeC425BF3c289C9B7452aD54E2F9877F21e0316", + ]; + + // Addresses that shows up under the 'Your address' tab in address book + function populateYourAddresses(): void { + // Create new wallet address - only available if there is DFI UTXO + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("wallet_address").should("exist").click(); + cy.getByTestID("create_new_address").should("exist").click(); // Generate Address 2 wallet address + + // Go back to previous Address 1 + cy.getByTestID("wallet_address").should("exist").click(); + cy.getByTestID("address_row_0").click(); + cy.getByTestID("wallet_address").should("have.text", "Address 1"); + } + + // Whitelisted addresses + function populateAddressBook(hasExistingAddress?: boolean): void { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("header_settings").click(); + cy.getByTestID("address_book_title").click(); + cy.wrap(labels).each((_v, index: number) => { + cy.getByTestID("add_new_address").should("exist").click(); + + if (hasExistingAddress) { + // Reselect DVM address type + cy.getByTestID("address_book_address_type_DVM").click(); + } + + // Select EVM address type + if (index === 1) { + cy.getByTestID("address_book_address_type_EVM").click(); + } + cy.getByTestID("address_book_label_input").type(labels[index]); + cy.getByTestID("address_book_label_input_error").should("not.exist"); + cy.getByTestID("address_book_address_input") + .clear() + .type(addresses[index]) + .blur(); + cy.getByTestID("address_book_address_input_error").should("not.exist"); + cy.getByTestID("save_address_label").click().wait(1000); + cy.getByTestID("pin_authorize").type("000000").wait(4000); + cy.getByTestID("cancel_authorization").click(); + }); + } + + function verifyYourAddressRowItems(index: number) { + // Generated wallet label + cy.getByTestID(`address_row_label_${index}_YOUR_ADDRESS`).should( + "have.text", + `Address ${index + 1}`, + ); + // dvm address + cy.getByTestID(`address_row_text_${index}_YOUR_ADDRESS`).should("exist"); + + // evm address + cy.getByTestID(`address_row_text_${index}_YOUR_ADDRESS_EVM`).should( + "exist", + ); + } + + // Send DFI tokens dvm -> evm + function topUpDfiInEvmDomain() { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click(); + cy.getByTestID("select_DFI").click(); + cy.getByTestID("25%_amount_button").click(); + cy.getByTestID("address_book_button").click(); + cy.getByTestID("address_button_group_YOUR_ADDRESS").click(); + cy.getByTestID("address_row_text_0_YOUR_ADDRESS_EVM").click(); + cy.getByTestID("button_confirm_send_continue").click(); + + // Send confirmation screen + cy.getByTestID("button_confirm_send").click(); + cy.getByTestID("pin_authorize").type("000000").wait(4000); + cy.getByTestID("oceanInterface_close").click(); // Close ocean interface popup + } + + describe("Whitelisted and Your Addresses tab", () => { + before(() => { + cy.setFeatureFlags(["evm"]).wait(1000); + cy.createEmptyWallet(true); + cy.sendDFItoWallet().sendDFITokentoWallet().wait(4000); + topUpDfiInEvmDomain(); + populateYourAddresses(); // Generate new wallet Address 2 + populateAddressBook(); // Add whitelist addresses + }); + + it("(dvm) Whitelisted - should not display evm tag for dvm addresses", () => { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("header_settings").click(); + cy.getByTestID("address_book_title").click(); + cy.getByTestID("address_row_label_0_WHITELISTED").should( + "have.text", + labels[0], + ); + cy.getByTestID("address_row_text_0_WHITELISTED").should( + "have.text", + addresses[0], + ); + cy.getByTestID("address_row_0_WHITELISTED_caret").should("exist"); + + cy.getByTestID("address_row_label_0_WHITELISTED_EVM_tag").should( + "not.exist", + ); + }); + + it("(dvm) Whitelisted - should display evm tag for evm addresses", () => { + cy.getByTestID("address_row_label_1_WHITELISTED").should( + "have.text", + labels[1], + ); + cy.getByTestID("address_row_text_1_WHITELISTED").should( + "have.text", + addresses[1], + ); + cy.getByTestID("address_row_1_WHITELISTED_caret").should("exist"); + cy.getByTestID("address_row_label_1_WHITELISTED_EVM_tag").should("exist"); + }); + + it("(dvm) Your Addresses - should display not evm tag for dvm addresses", () => { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("header_settings").click(); + cy.getByTestID("address_book_title").click(); + cy.getByTestID("address_button_group_YOUR_ADDRESS").click(); + verifyYourAddressRowItems(0); + }); + + it("(dvm) Your Addresses - should display evm tag for evm addresses", () => { + verifyYourAddressRowItems(1); + }); + + // Switch to evm domain + it("(evm) Whitelisted - should disable evm addresses in evm domain", () => { + // Go back to portfolio page to switch domain + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("domain_switch").click(); + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click().wait(3000); + cy.getByTestID("select_DFI").click().wait(3000); + cy.getByTestID("address_book_button").click(); + + cy.getByTestID("address_row_0_WHITELISTED").should( + "have.attr", + "aria-disabled", + "true", + ); + cy.getByTestID("address_row_1_WHITELISTED").should("not.be.disabled"); + }); + + // Switch to your address tab + it("(evm) Your Address - should disable evm addresses in evm domain", () => { + cy.getByTestID("address_button_group_YOUR_ADDRESS").click(); + verifyYourAddressItemEvm(); + }); + }); +}); + +// Check if evm address is disabled in evm domain for generated Address 1 and 2 cards +function verifyYourAddressItemEvm() { + cy.wrap([0, 1]).each((index: number) => { + // dvm address + cy.getByTestID(`address_row_text_${index}_YOUR_ADDRESS`).should( + "not.be.disabled", + ); + // evm address + cy.getByTestID(`address_row_text_${index}_YOUR_ADDRESS_EVM`).should( + "have.attr", + "aria-disabled", + "true", + ); + }); +} + +context("Portfolio", () => { + before(() => { + cy.setFeatureFlags(["evm"]).wait(1000); + cy.createEmptyWallet(true); + cy.sendDFItoWallet().sendTokenToWallet(["BTC", "BTC-DFI"]).wait(4000); + cy.getByTestID("bottom_tab_portfolio").click(); + }); + + describe("Wallet label (& address book bottom sheet)", () => { + it('should display generated address label "Address 1" as first wallet label', () => { + cy.getByTestID("wallet_address") + .should("exist") + .should("have.text", "Address 1"); + }); + it("should display new wallet label after modifying wallet label", () => { + cy.getByTestID("wallet_address").should("exist").click(); + + // Go to edit address book bottom sheet + cy.getByTestID("address_edit_icon_address_row_0").click(); + cy.getByTestID("address_book_label_input") + .click() + .type("New Wallet Label") + .blur() + .wait(1000); + cy.getByTestID("button_confirm_save_address_label").click().wait(1000); + + // Go back to address book bottom sheet + cy.getByTestID("list_header_address_label").should("exist"); + cy.getByTestID("close_bottom_sheet_button").click(); + + // Go back to portfolio page + cy.getByTestID("wallet_address").should("have.text", "New Wallet Label"); + }); + + // Generate new wallet address + it("should display generated Address 2 label as second wallet label", () => { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("wallet_address").should("exist").click(); + + cy.getByTestID("create_new_address").should("exist").click(); // Generate Address 2 wallet address + cy.getByTestID("wallet_address").should("have.text", "Address 2"); + }); + }); +}); + +// Ensure that the blockchain container in Docker returns 'Block minted' to know that it's connected to Local env, else restart container +// If values are taking too long to load or for flaky tests, restart Cypress diff --git a/mobile-app/cypress/e2e/functional/wallet/dex/swap/swap_tabs_dropdowns.spec.ts b/mobile-app/cypress/e2e/functional/wallet/dex/swap/swap_tabs_dropdowns.spec.ts index fb1ae7ab85..224cf82bda 100644 --- a/mobile-app/cypress/e2e/functional/wallet/dex/swap/swap_tabs_dropdowns.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/dex/swap/swap_tabs_dropdowns.spec.ts @@ -97,12 +97,12 @@ context("Wallet - DEX - disabled pool pairs", () => { cy.getByTestID("dex_action_button_composite_swap_button_26").should( "have.css", "opacity", // using opacity to check enable - "1" + "1", ); // status: true cy.getByTestID("dex_action_button_composite_swap_button_28").should( "have.css", "opacity", // using opacity to check disable - "0.3" + "0.3", ); // status: false }); }); @@ -134,7 +134,8 @@ context("Wallet - DEX - Instant/Future Swap - tabs and dropdowns", () => { }); it("should be able to choose tokens to swap", () => { - cy.getByTestID("composite_swap").click(); + cy.wait(1000); + cy.getByTestID("composite_swap").should("exist").click(); cy.wait(5000); cy.getByTestID("token_select_button_FROM").click(); cy.getByTestID("select_DFI").click().wait(2000); @@ -146,18 +147,18 @@ context("Wallet - DEX - Instant/Future Swap - tabs and dropdowns", () => { cy.getByTestID("switch_button").click(); cy.getByTestID("token_select_button_FROM_display_symbol").should( "have.text", - "dTU10" + "dTU10", ); cy.getByTestID("token_select_button_TO_display_symbol").should( "have.text", - "DFI" + "DFI", ); }); it("should be able to disable future swap tab if tokenA and tokenB is not a valid future swap pair", () => { cy.getByTestID("swap_tabs_FUTURE_SWAP").should( "have.attr", - "aria-disabled" + "aria-disabled", ); /* Only DUSD <-> Loan tokens are allowed in future swap */ @@ -167,7 +168,7 @@ context("Wallet - DEX - Instant/Future Swap - tabs and dropdowns", () => { cy.getByTestID("select_dTU10").click(); cy.getByTestID("swap_tabs_FUTURE_SWAP").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); }); @@ -175,11 +176,11 @@ context("Wallet - DEX - Instant/Future Swap - tabs and dropdowns", () => { cy.getByTestID("swap_tabs_FUTURE_SWAP").click(); cy.getByTestID("token_select_button_FROM_display_symbol").should( "have.text", - "DUSD" + "DUSD", ); cy.getByTestID("token_select_button_TO_display_symbol").should( "have.text", - "dTU10" + "dTU10", ); }); diff --git a/mobile-app/cypress/e2e/functional/wallet/portfolio/addresses.spec.ts b/mobile-app/cypress/e2e/functional/wallet/portfolio/addresses.spec.ts index 7d08d3e21c..dc8038ec59 100644 --- a/mobile-app/cypress/e2e/functional/wallet/portfolio/addresses.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/portfolio/addresses.spec.ts @@ -19,6 +19,7 @@ function addLocalStorageFeatureFlag(): void { context("Wallet - Addresses", () => { let whale: WhaleApiClient; + let address: string; before(() => { addLocalStorageFeatureFlag(); @@ -48,6 +49,7 @@ context("Wallet - Addresses", () => { cy.getByTestID("active_address") .invoke("css", "text-overflow") .should("eq", "ellipsis"); + cy.getByTestID("bottomsheet-address-header").contains("DVM"); cy.getByTestID("active_address").click(); cy.getByTestID("wallet_toast").should("exist"); }); @@ -55,10 +57,14 @@ context("Wallet - Addresses", () => { it("should not present create new address when wallet is freshly setup", () => { const network: string = localStorage.getItem("Development.NETWORK"); expect( - localStorage.getItem(`Development.${network}.WALLET_ADDRESS.INDEX.active`) + localStorage.getItem( + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq(null); expect( - localStorage.getItem(`Development.${network}.WALLET_ADDRESS.INDEX.length`) + localStorage.getItem( + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq(null); cy.getByTestID("address_row_text_0") .invoke("text") @@ -71,6 +77,28 @@ context("Wallet - Addresses", () => { }); }); + it("should show EVM address when toggle set to EVM", () => { + cy.getByTestID("header_settings").click(); + cy.getByTestID("address_book_title").click(); + cy.getByTestID("address_button_group_YOUR_ADDRESS").click(); + cy.getByTestID("address_row_text_0_YOUR_ADDRESS_EVM") + .invoke("text") + .then((evmAddress: string) => { + cy.getByTestID("bottom_tab_portfolio").click(); + cy.getByTestID("domain_switch_DVM").should("exist"); + cy.getByTestID("domain_switch").click(); + cy.getByTestID("domain_switch_EVM").should("exist"); + cy.getByTestID("switch_account_button").click(); + cy.getByTestID("address_row_text_0").contains(evmAddress); + cy.getByTestID("bottomsheet-address-header").contains("EVM"); + cy.getByTestID("close_bottom_sheet_button").click(); + }); + + // Toggled back to DVM for next test + cy.getByTestID("domain_switch_EVM").should("exist"); + cy.getByTestID("domain_switch").click(); + }); + it("should be able to create new address when all available address are active", () => { cy.sendDFItoWallet().wait(4000); cy.getByTestID("dfi_total_balance_amount") @@ -89,13 +117,13 @@ context("Wallet - Addresses", () => { const network: string = localStorage.getItem("Development.NETWORK"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq("1"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq("1"); }); cy.wait(3000); @@ -130,16 +158,13 @@ context("Wallet - Addresses", () => { .click() .wait(1000); cy.getByTestID(`address_active_indicator_${activeAddress}`).should( - "exist" + "exist", ); cy.getByTestID("close_bottom_sheet_button").click(); cy.getByTestID("receive_balance_button").click(); cy.getByTestID("address_text").contains(activeAddress); }); - }); - context("Wallet - Addresses transfer dfi between addresses", () => { - let address: string; it("should able to transfer dfi between addresses", () => { cy.getByTestID("bottom_tab_portfolio").click(); cy.getByTestID("switch_account_button") @@ -155,17 +180,17 @@ context("Wallet - Addresses", () => { .click() .should(() => { const network: string = localStorage.getItem( - "Development.NETWORK" + "Development.NETWORK", ); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq("0"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq("1"); }); cy.getByTestID("dfi_total_balance_amount").contains("10.00000000"); @@ -176,7 +201,7 @@ context("Wallet - Addresses", () => { cy.getByTestID("amount_input").clear().type("1"); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("confirm_title").contains("You are sending"); @@ -209,13 +234,13 @@ context("Wallet - Addresses", () => { const network: string = localStorage.getItem("Development.NETWORK"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq("1"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq("1"); }); cy.getByTestID("dfi_total_balance_amount").contains("1.00000000"); @@ -277,20 +302,20 @@ context( const network: string = localStorage.getItem("Development.NETWORK"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq("0"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq("0"); }); cy.getByTestID("address_row_0").should("exist"); cy.getByTestID("address_row_text_0").contains(address); cy.getByTestID(`address_active_indicator_${address}`).should("exist"); }); - } + }, ); context( @@ -328,10 +353,10 @@ context( .should(() => { const network: string = localStorage.getItem("Development.NETWORK"); maxAddress = localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` + `Development.${network}.WALLET_ADDRESS.INDEX.length`, ); const activeAddress = localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` + `Development.${network}.WALLET_ADDRESS.INDEX.active`, ); expect(activeAddress).to.eq("1"); expect(maxAddress).to.eq("1"); @@ -370,13 +395,13 @@ context( const network: string = localStorage.getItem("Development.NETWORK"); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.active` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.active`, + ), ).to.eq(null); expect( localStorage.getItem( - `Development.${network}.WALLET_ADDRESS.INDEX.length` - ) + `Development.${network}.WALLET_ADDRESS.INDEX.length`, + ), ).to.eq(maxAddress); }); addresses.forEach((address, index) => { @@ -384,10 +409,10 @@ context( cy.getByTestID(`address_row_text_${index}`).contains(address); }); cy.getByTestID(`address_active_indicator_${addresses[0]}`).should( - "exist" + "exist", ); }); - } + }, ); context("Wallet - Addresses should able to create maximum 10 addresses", () => { @@ -467,7 +492,7 @@ context("Wallet - should be able to discover Wallet Addresses", () => { cy.getByTestID("amount_input").clear().type("1"); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("button_confirm_send").click().wait(3000); @@ -486,13 +511,13 @@ context("Wallet - Address Label", () => { if (shouldAllow) { cy.getByTestID("button_confirm_save_address_label").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("address_book_label_input_error").should("not.exist"); } else { cy.getByTestID("button_confirm_save_address_label").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("address_book_label_input_error").should("exist"); } @@ -508,7 +533,7 @@ context("Wallet - Address Label", () => { cy.getByTestID("address_book_label_input").clear().type(label); cy.getByTestID("button_confirm_save_address_label").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("button_confirm_save_address_label").click().wait(1000); cy.getByTestID(`list_address_label_${address}`).contains(label); @@ -549,7 +574,7 @@ context("Wallet - Address Label", () => { validateLabel("abcdefghijklmnopqrstuvwxyz12345678910ABCD", false); // block >40 char validateLabel( "😀🙌👶👩🏻‍💻🐶🌵🌝🍏🥨⚽️🪂🚗⌚😀🙌👶👩🏻‍💻🐶🌵🌝🍏🥨⚽️🪂🚗⌚😀🙌👶👩🏻‍💻️ ", - false + false, ); // not all emoji equivalent to 1 char // allow validateLabel("abcdefghijklmnopqrstuvwxyz1234", true); @@ -585,7 +610,7 @@ context("Wallet - Address Label", () => { cy.getByTestID("address_book_label_input").clear().type(inputLabel); cy.getByTestID("button_confirm_save_address_label").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("button_confirm_save_address_label").click(); cy.getByTestID(`list_address_label_${address}`).contains(trimmedLabel); diff --git a/mobile-app/cypress/e2e/functional/wallet/portfolio/portfolio.spec.ts b/mobile-app/cypress/e2e/functional/wallet/portfolio/portfolio.spec.ts index 958e90b821..5f8085aa14 100644 --- a/mobile-app/cypress/e2e/functional/wallet/portfolio/portfolio.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/portfolio/portfolio.spec.ts @@ -419,7 +419,7 @@ context("Wallet - Portfolio page", () => { cy.getByTestID("empty_tokens_title").should("have.text", "Empty portfolio"); cy.getByTestID("empty_tokens_subtitle").should( "have.text", - "Add DFI and other tokens to get started" + "Add DFI and other tokens to get started", ); }); }); @@ -598,7 +598,7 @@ context("Wallet - Portfolio - No balance", () => { it("should enabled send button", () => { cy.getByTestID("send_balance_button").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); }); @@ -650,7 +650,7 @@ context("Wallet - Portfolio - No balance", () => { .invoke("text") .then((price: string) => { expect(price).to.equal( - `$${new BigNumber(response.price.aggregated.amount).toFixed(2)}` + `$${new BigNumber(response.price.aggregated.amount).toFixed(2)}`, ); }); }); @@ -1024,7 +1024,7 @@ context( }); cy.getByTestID("toggle_sorting_assets").should("exist"); cy.getByTestID("portfolio_button_group_ALL_TOKENS_active").should( - "exist" + "exist", ); cy.getByTestID("portfolio_row_1").should("exist"); // dBTC = row 1 cy.getByTestID("portfolio_button_group_CRYPTO").click(); @@ -1034,21 +1034,21 @@ context( cy.getByTestID("portfolio_button_group_LP_TOKENS_active").should("exist"); cy.getByTestID("empty_tokens_title").should( "have.text", - "No LP tokens found" + "No LP tokens found", ); cy.getByTestID("empty_tokens_subtitle").should( "have.text", - "Add liquidity to get started" + "Add liquidity to get started", ); cy.getByTestID("portfolio_button_group_d_TOKENS").click(); cy.getByTestID("portfolio_button_group_d_TOKENS_active").should("exist"); cy.getByTestID("empty_tokens_title").should( "have.text", - "No dTokens found" + "No dTokens found", ); cy.getByTestID("empty_tokens_subtitle").should( "have.text", - "Mint dTokens to get started" + "Mint dTokens to get started", ); }); it("should exist in All tokens and dTokens tabs, should not exist in LP tokens and Crypto tabs", () => { @@ -1072,34 +1072,34 @@ context( cy.getByTestID("toggle_sorting_assets").should("exist"); cy.getByTestID("portfolio_button_group_ALL_TOKENS").click(); cy.getByTestID("portfolio_button_group_ALL_TOKENS_active").should( - "exist" + "exist", ); cy.getByTestID("portfolio_row_14").should("exist"); // DUSD = row 14 cy.getByTestID("portfolio_button_group_LP_TOKENS").click(); cy.getByTestID("portfolio_button_group_LP_TOKENS_active").should("exist"); cy.getByTestID("empty_tokens_title").should( "have.text", - "No LP tokens found" + "No LP tokens found", ); cy.getByTestID("empty_tokens_subtitle").should( "have.text", - "Add liquidity to get started" + "Add liquidity to get started", ); cy.getByTestID("portfolio_button_group_CRYPTO").click(); cy.getByTestID("portfolio_button_group_CRYPTO_active").should("exist"); cy.getByTestID("empty_tokens_title").should( "have.text", - "No crypto found" + "No crypto found", ); cy.getByTestID("empty_tokens_subtitle").should( "have.text", - "Add crypto to get started" + "Add crypto to get started", ); cy.getByTestID("portfolio_button_group_d_TOKENS").click(); cy.getByTestID("portfolio_button_group_d_TOKENS_active").should("exist"); cy.getByTestID("portfolio_row_14").should("exist"); // DUSD = row 14 }); - } + }, ); context("Wallet - Portfolio - Portfolio group tab", () => { @@ -1119,7 +1119,7 @@ context("Wallet - Portfolio - Portfolio group tab", () => { "$100,000.00", "$100,000.00", "$100,000.00", - "$1,000.00" + "$1,000.00", ); }); @@ -1133,7 +1133,7 @@ context("Wallet - Portfolio - Portfolio group tab", () => { "10.00 DFI", "10.00 DFI", "10.00 DFI", - "0.10000000 DFI" + "0.10000000 DFI", ); }); @@ -1147,7 +1147,7 @@ context("Wallet - Portfolio - Portfolio group tab", () => { "10.00 BTC", "10.00 BTC", "10.00 BTC", - "0.10000000 BTC" + "0.10000000 BTC", ); }); }); @@ -1180,7 +1180,7 @@ function checkPortfolioPageDenominationValues( DfiTotalBalUsdAmt: string, DfiAvailableAmt: string, BtcUsdAmt: string, - EthUsdAmt: string + EthUsdAmt: string, ): void { // TotalPortfolio cy.getByTestID("total_usd_amount").contains(totalUsdAmt); @@ -1213,7 +1213,7 @@ function checkPortfolioPageDenominationValues( function checkAssetsSortingOrder( sortedType: string, firstToken: string, - lastToken: string + lastToken: string, ): void { const containerTestID = '[data-testid="card_balance_row_container"]'; const arrowTestID = "your_assets_dropdown_arrow"; @@ -1282,7 +1282,7 @@ context( it("should sort assets based on Lowest value (DFI)", () => { checkAssetsSortingOrder("Lowest value (DFI)", "dLTC", "dBTC"); }); - } + }, ); function interceptTokensForSorting(data: {}): void { @@ -1311,7 +1311,7 @@ context( interceptTokensForSorting(addLPTokens); checkAssetsSortingOrder("Lowest value (DFI)", "dUSDT-DFI", "dBTC-DFI"); }); - } + }, ); context( @@ -1332,7 +1332,7 @@ context( interceptTokensForSorting(addCrypto); checkAssetsSortingOrder("Lowest value (DFI)", "dETH", "dBTC"); }); - } + }, ); context( @@ -1353,7 +1353,7 @@ context( interceptTokensForSorting(addDTokens); checkAssetsSortingOrder("Lowest value (DFI)", "DUSD", "dTD10"); }); - } + }, ); context( @@ -1373,7 +1373,7 @@ context( it("should sort assets based on Lowest value (BTC)", () => { checkAssetsSortingOrder("Lowest value (BTC)", "DUSD", "dBTC"); }); - } + }, ); context("Wallet - Portfolio - Skeleton Loader", () => { @@ -1548,3 +1548,54 @@ context("Wallet - Portfolio - portfolio", () => { }); }); }); + +context( + "Transfer domain - Wallet - Portfolio - Portfolio group tab - DFI currency", + () => { + before(() => { + cy.createEmptyWallet(true); + cy.getByTestID("header_settings").click(); + cy.getByTestID("bottom_tab_portfolio").click(); + + cy.intercept("**/address/**/tokens?size=*", { + body: { + data: [ + { + amount: "5.00000000", + displaySymbol: "dBTC", + id: "1", + isDAT: true, + isLPS: false, + isLoanToken: false, + name: "Playground BTC", + symbol: "BTC", + symbolKey: "BTC", + }, + { + id: "24", + amount: "10.00000000", + symbol: "TU10-DUSD", + symbolKey: "TU10-DUSD", + name: "Decentralized TU10-Decentralized USD", + isDAT: true, + isLPS: true, + isLoanToken: false, + displaySymbol: "dTU10-DUSD", + }, + ], + }, + }); + }); + + it("should display all tokens in dvm domain", () => { + cy.getByTestID("portfolio_row_1").should("exist"); + cy.getByTestID("portfolio_row_24").should("exist"); + }); + + it("should only display non LP tokens in evm domain", () => { + cy.getByTestID("domain_switch").click(); + cy.getByTestID("portfolio_row_1").should("exist"); + cy.getByTestID("portfolio_row_24").should("not.exist"); + }); + }, +); diff --git a/mobile-app/cypress/e2e/functional/wallet/portfolio/send.spec.ts b/mobile-app/cypress/e2e/functional/wallet/portfolio/send.spec.ts index e8831aba2c..cfaffcf72b 100644 --- a/mobile-app/cypress/e2e/functional/wallet/portfolio/send.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/portfolio/send.spec.ts @@ -12,7 +12,7 @@ const validateAmountButtonResult = (value: string, usdValue: string): void => { }); cy.getByTestID("amount_input_in_usd").should( "have.text", - `$${usdValueWithThousandSep}` + `$${usdValueWithThousandSep}`, ); }; @@ -21,7 +21,7 @@ const validateInfotext = ( | "insufficient_balance" | "lp_warning" | "utxo_warning" - | "minimal_fee_warning" + | "minimal_fee_warning", ): void => { const infoText = { insufficient_balance: "Insufficient balance", @@ -86,7 +86,7 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").type("0.1"); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("amount_input").clear(); @@ -94,17 +94,17 @@ context("Wallet - Send", () => { cy.getByTestID("address_input").type("z"); cy.getByTestID("address_error_text").should( "have.text", - "Invalid address. Make sure the address is correct to avoid irrecoverable losses" + "Invalid address. Make sure the address is correct to avoid irrecoverable losses", ); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.wait(1000); cy.getByTestID("address_input_clear_button").click(); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); // Invalid amount - Character, over max amount, zero @@ -112,17 +112,17 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").clear().type("a"); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("amount_input").clear().type("12"); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("amount_input").clear().type("0"); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); }); @@ -133,7 +133,7 @@ context("Wallet - Send", () => { cy.getByTestID("token_search_input").clear().type("xxx").wait(2000); cy.getByTestID("empty_search_result_text").should( "have.text", - "Search results for “xxx”" + "Search results for “xxx”", ); cy.getByTestID("select_DFI").should("not.exist"); cy.getByTestID("select_dBTC-DFI").should("not.exist"); @@ -142,7 +142,7 @@ context("Wallet - Send", () => { cy.getByTestID("token_search_input").clear().type("btc").wait(2000); cy.getByTestID("empty_search_result_text").should( "have.text", - "Search results for “btc”" + "Search results for “btc”", ); cy.getByTestID("select_DFI").should("not.exist"); cy.getByTestID("select_dBTC-DFI").should("exist"); @@ -189,11 +189,11 @@ context("Wallet - Send", () => { cy.getByTestID(`${key}_amount_button`).click(); const availableBalance = new BigNumber(text); const inputAfterButtonPress = availableBalance.multipliedBy( - amountButtons[key] + amountButtons[key], ); validateAmountButtonResult( inputAfterButtonPress.toFixed(8), - inputAfterButtonPress.multipliedBy(10000).toFixed(2) + inputAfterButtonPress.multipliedBy(10000).toFixed(2), ); }); }); @@ -213,7 +213,7 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").clear().type(sendAmount); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); // Check txn value @@ -222,14 +222,14 @@ context("Wallet - Send", () => { .then((textAmount) => { const amount = textAmount.replace(" DFI", ""); expect(new BigNumber(amount).toFixed(8)).eq( - new BigNumber(sendAmount).toFixed(8) + new BigNumber(sendAmount).toFixed(8), ); cy.getByTestID("text_fee") .invoke("text") .then((textFeeValue) => { const textFee = textFeeValue.replace(" DFI", ""); expect(new BigNumber(transactionFee).toFixed(8)).eq( - new BigNumber(textFee).toFixed(8) + new BigNumber(textFee).toFixed(8), ); // Check computed pending balance cy.getByTestID("resulting_DFI") @@ -237,14 +237,14 @@ context("Wallet - Send", () => { .then((pendingBalanceValue) => { const pendingBalance = pendingBalanceValue.replace( " DFI", - "" + "", ); expect( new BigNumber(balance) .plus(slippage) .minus(transactionFee) .minus(sendAmount) - .toFixed(8) + .toFixed(8), ).eq(pendingBalance); cy.getByTestID("button_cancel_send").click(); }); @@ -264,7 +264,7 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").clear().type("1"); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("confirm_title").contains("You are sending"); @@ -301,7 +301,7 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").clear().type(oldAmount); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); @@ -309,7 +309,7 @@ context("Wallet - Send", () => { cy.getByTestID("confirm_title").contains("You are sending"); cy.getByTestID("text_send_amount").should( "have.text", - new BigNumber(oldAmount).toFixed(8) + new BigNumber(oldAmount).toFixed(8), ); // Address @@ -318,26 +318,26 @@ context("Wallet - Send", () => { // Transaction details cy.getByTestID("transaction_fee_label").should( "have.text", - "Transaction fee" + "Transaction fee", ); cy.getByTestID("transaction_fee_value").should("exist"); cy.getByTestID("text_amount_label").should("have.text", "Amount to send"); cy.getByTestID("text_amount").contains(oldAmount); const usdValueWithThousandSep = Number( - new BigNumber(oldAmount).multipliedBy(10000).toFixed(2) + new BigNumber(oldAmount).multipliedBy(10000).toFixed(2), ).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, }); cy.getByTestID("text_amount_rhsUsdAmount").should( "have.text", - `$${usdValueWithThousandSep}` + `$${usdValueWithThousandSep}`, ); cy.getByTestID("button_confirm_send").click().wait(5000); // Check for authorization page description cy.getByTestID("txn_authorization_title").contains( - `Sending ${new BigNumber(oldAmount).toFixed(8)} DFI to ${oldAddress}` + `Sending ${new BigNumber(oldAmount).toFixed(8)} DFI to ${oldAddress}`, ); // Cancel send on authorisation page cy.getByTestID("cancel_authorization").click(); @@ -354,7 +354,7 @@ context("Wallet - Send", () => { cy.getByTestID("amount_input").clear().type(newAmount); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); // Check address and amount in confirm send page @@ -364,7 +364,7 @@ context("Wallet - Send", () => { cy.getByTestID("button_confirm_send").click().wait(3000); // Check for authorization page description cy.getByTestID("txn_authorization_title").contains( - `Sending ${new BigNumber(newAmount).toFixed(8)} DFI to ${newAddress}` + `Sending ${new BigNumber(newAmount).toFixed(8)} DFI to ${newAddress}`, ); cy.closeOceanInterface(); }); @@ -404,7 +404,7 @@ context("Wallet - Send", () => { cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("button_confirm_send").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("lp_ack_switch").click(); cy.getByTestID("button_confirm_send").click().wait(3000); @@ -452,21 +452,21 @@ context("Wallet - Send - Max Values", () => { cy.getByTestID("MAX_amount_button").click(); cy.getByTestID("button_confirm_send_continue").should( "not.have.attr", - "disabled" + "disabled", ); cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("confirm_title").contains("You are sending"); cy.getByTestID("text_send_amount").contains("9.90000000"); cy.getByTestID("text_amount").contains("9.90000000 DFI"); const usdValueWithThousandSep = Number( - new BigNumber(9.9).multipliedBy(10000).toFixed(2) + new BigNumber(9.9).multipliedBy(10000).toFixed(2), ).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, }); cy.getByTestID("text_amount_rhsUsdAmount").should( "have.text", - `$${usdValueWithThousandSep}` + `$${usdValueWithThousandSep}`, ); cy.getByTestID("button_confirm_send").click().wait(3000); cy.closeOceanInterface(); @@ -516,40 +516,40 @@ context("Wallet - Send - with Conversion", () => { cy.getByTestID("amount_input").type("12"); cy.getByTestID("transaction_details_info_text").should( "contain", - "By continuing, the required amount of DFI will be converted" + "By continuing, the required amount of DFI will be converted", ); cy.getByTestID("button_confirm_send_continue").click(); cy.getByTestID("txn_authorization_title").contains( - `Convert ${new BigNumber("2.1").toFixed(8)} DFI to UTXO` + `Convert ${new BigNumber("2.1").toFixed(8)} DFI to UTXO`, ); cy.closeOceanInterface().wait(3000); cy.getByTestID("amount_to_convert_label").should( "have.text", - "Amount to convert" + "Amount to convert", ); cy.getByTestID("amount_to_convert_value").should( "contain", - "2.10000000 DFI" + "2.10000000 DFI", ); cy.getByTestID("conversion_status").should("have.text", "Converted"); cy.getByTestID("transaction_fee_label").should( "have.text", - "Transaction fee" + "Transaction fee", ); cy.getByTestID("transaction_fee_value").should("exist"); cy.getByTestID("text_amount").should("have.text", "12.00000000 DFI"); const usdValueWithThousandSep = Number( - new BigNumber(12).multipliedBy(10000).toFixed(2) + new BigNumber(12).multipliedBy(10000).toFixed(2), ).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, }); cy.getByTestID("text_amount_rhsUsdAmount").should( "have.text", - `$${usdValueWithThousandSep}` + `$${usdValueWithThousandSep}`, ); cy.getByTestID("text_send_amount").should("contain", "12.00000000"); @@ -584,7 +584,7 @@ context("Wallet - Send - Switch token", () => { cy.getByTestID("select_DFI").click(); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("max_value").should("have.text", "19.90000000"); cy.getByTestID("max_value_display_symbol").contains("DFI"); @@ -598,7 +598,7 @@ context("Wallet - Send - Switch token", () => { cy.getByTestID("max_value_display_symbol").contains("dBTC"); cy.getByTestID("button_confirm_send_continue").should( "have.attr", - "aria-disabled" + "aria-disabled", ); }); @@ -661,10 +661,10 @@ context("Wallet - Send - Address book", () => { cy.getByTestID("address_input_clear_button").click(); cy.getByTestID("address_book_button").click(); cy.getByTestID(`address_row_label_${index}_WHITELISTED`).contains( - labels[index] + labels[index], ); cy.getByTestID(`address_row_text_${index}_WHITELISTED`).contains( - addresses[index] + addresses[index], ); // cy.getByTestID('address_book_address_input').clear().type(addresses[index]).blur() }); @@ -704,15 +704,15 @@ context("Wallet - Send - Address book", () => { cy.getByTestID("address_book_address_input").type("fake address"); cy.getByTestID("save_address_label").should("have.attr", "aria-disabled"); cy.getByTestID("address_book_address_input_error").contains( - "Please enter a valid address" + "Please enter a valid address", ); cy.getByTestID("address_book_label_input_clear_button").click(); cy.getByTestID("address_book_label_input_error").contains( - "Required field. Please enter a label. Maximum of 40 characters." + "Required field. Please enter a label. Maximum of 40 characters.", ); cy.getByTestID("address_book_address_input").clear(); cy.getByTestID("address_book_address_input_error").contains( - "Please enter a valid address" + "Please enter a valid address", ); cy.getByTestID("save_address_label").should("have.attr", "aria-disabled"); }); @@ -758,7 +758,7 @@ context("Wallet - Send - Address book", () => { .type(addresses[index]) .blur(); cy.getByTestID("address_book_address_input_error").contains( - "This address already exists in your address book, please enter a different address" + "This address already exists in your address book, please enter a different address", ); cy.go("back"); }); @@ -776,7 +776,7 @@ context("Wallet - Send - Address book", () => { .type(walletAddress) .blur(); cy.getByTestID("address_book_address_input_error").contains( - "This address already exists in your address book, please enter a different address" + "This address already exists in your address book, please enter a different address", ); }); }); @@ -804,7 +804,7 @@ context("Wallet - Send - Address book", () => { .should("exist") .then(() => { const walletUserPreference = JSON.parse( - localStorage.getItem("Local.WALLET.SETTINGS") ?? "{}" + localStorage.getItem("Local.WALLET.SETTINGS") ?? "{}", ); expect(walletUserPreference).to.have.deep.property("addressBook", {}); }); @@ -827,9 +827,207 @@ context("Wallet - Send - Address book", () => { .should("exist") .then(() => { const walletUserPreference = JSON.parse( - localStorage.getItem("Local.WALLET.SETTINGS") ?? "{}" + localStorage.getItem("Local.WALLET.SETTINGS") ?? "{}", ); expect(walletUserPreference).to.have.deep.property("addressBook", {}); }); }); }); + +context.only("(dvm -> dvm) Wallet - Send - Address book", () => { + before(() => { + cy.createEmptyWallet(true); + cy.sendDFItoWallet().sendDFITokentoWallet().wait(6000); + cy.getByTestID("bottom_tab_portfolio").click(); + + // Portfolio -> Send action btn -> Address book + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click().wait(3000); + cy.getByTestID("select_DFI").click().wait(3000); + cy.getByTestID("address_book_button").click(); + cy.getByTestID("address_row_0_WHITELISTED").should("not.exist"); + cy.getByTestID("button_add_address").should("exist"); + }); + + const labels = ["DVMAddress", "EVMAddress"]; + const addresses = [ + "bcrt1q8rfsfny80jx78cmk4rsa069e2ckp6rn83u6ut9", + "0x2DeC425BF3c289C9B7452aD54E2F9877F21e0316", + ]; + + function validateMatchAddress(address: string, label: string): void { + cy.getByTestID("address_input").contains(address); + if (label === labels[0]) { + cy.getByTestID("address_input_footer").contains(label); + } else { + cy.getByTestID("address_input_footer_evm").contains(label); + } + } + + function populateAddressBook(): void { + cy.createEmptyWallet(true); + cy.sendDFItoWallet().sendDFITokentoWallet().wait(6000); + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click().wait(3000); + cy.getByTestID("select_DFI").click().wait(3000); + cy.getByTestID("address_book_button").click(); + cy.wrap(labels).each((_v, index: number) => { + if (index === 0) { + cy.getByTestID("button_add_address").click(); + } else { + cy.getByTestID("add_new_address").click(); + } + // Select EVM address type + if (index === 1) { + cy.getByTestID("address_book_address_type_EVM").click(); + } + cy.getByTestID("address_book_label_input").type(labels[index]); + cy.getByTestID("address_book_label_input_error").should("not.exist"); + cy.getByTestID("address_book_address_input") + .clear() + .type(addresses[index]) + .blur(); + cy.getByTestID("address_book_address_input_error").should("not.exist"); + cy.getByTestID("save_address_label").click().wait(1000); + cy.getByTestID("pin_authorize").type("000000").wait(2000); + validateMatchAddress(addresses[index], labels[index]); + cy.wait(1000); + cy.getByTestID("address_input_clear_button").click(); + cy.getByTestID("address_book_button").click(); + cy.getByTestID(`address_row_label_${index}_WHITELISTED`).contains( + labels[index], + ); + cy.getByTestID(`address_row_text_${index}_WHITELISTED`).contains( + addresses[index], + ); + // cy.getByTestID('address_book_address_input').clear().type(addresses[index]).blur() + }); + } + + it("should enable selection for both DVM and EVM whitelisted wallet addresses", () => { + populateAddressBook(); + + // check if cards are enabled + cy.getByTestID("address_row_0_WHITELISTED").should( + "not.have.attr", + "aria-disabled", + ); + cy.getByTestID("address_row_1_WHITELISTED").should( + "not.have.attr", + "aria-disabled", + ); + }); + + it.only("should display evm tag when EVM address is selected in DVM domain", () => { + populateAddressBook(); + cy.getByTestID("address_row_text_1_WHITELISTED").click(); + + // expect to see evm tag in address input + cy.getByTestID("address_input_footer_evm").contains(labels[1]); + + cy.getByTestID("amount_input").type("0.1"); + cy.getByTestID("button_confirm_send_continue").click(); + + // expect to see evm tag in confirm screen + cy.getByTestID("to_address_label_evm_tag").should("exist"); + }); +}); + +context("(evm -> dvm) Wallet - Send - Address book", () => { + const isEvmDomain = true; + before(() => { + cy.createEmptyWallet(true); + cy.sendDFItoWallet().sendDFITokentoWallet().wait(6000); + cy.getByTestID("bottom_tab_portfolio").click(); + + // Portfolio -> Send btn -> Address book + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click().wait(3000); + cy.getByTestID("select_DFI").click().wait(3000); + cy.getByTestID("address_book_button").click(); + cy.getByTestID("address_row_0_WHITELISTED").should("not.exist"); + cy.getByTestID("button_add_address").should("exist"); + }); + + const labels = ["DVMAddress", "EVMAddress"]; + const addresses = [ + "bcrt1q8rfsfny80jx78cmk4rsa069e2ckp6rn83u6ut9", + "0x2DeC425BF3c289C9B7452aD54E2F9877F21e0316", + ]; + + function validateMatchAddress(address: string, label: string): void { + cy.getByTestID("address_input").contains(address); + if (label === labels[0]) { + cy.getByTestID("address_input_footer").contains(label); + } else { + cy.getByTestID("address_input_footer_evm").contains(label); + } + } + + function populateAddressBook(): void { + cy.createEmptyWallet(true); + cy.getByTestID("domain_switch").click(); // Switch to EVM domain + cy.sendDFItoWallet().sendDFITokentoWallet().wait(6000); + cy.getByTestID("action_button_group").should("exist"); + cy.getByTestID("send_balance_button").click().wait(3000); + cy.getByTestID("select_DFI").click().wait(3000); + cy.getByTestID("address_book_button").click(); + cy.wrap(labels).each((_v, index: number) => { + if (index === 0) { + cy.getByTestID("button_add_address").click(); + } else { + cy.getByTestID("add_new_address").click(); + } + if (isEvmDomain && index === 0) { + cy.getByTestID("address_book_address_type_DVM").click(); + } + cy.getByTestID("address_book_label_input").type(labels[index]); + cy.getByTestID("address_book_label_input_error").should("not.exist"); + cy.getByTestID("address_book_address_input") + .clear() + .type(addresses[index]) + .blur(); + cy.getByTestID("address_book_address_input_error").should("not.exist"); + cy.getByTestID("save_address_label").click().wait(1000); + cy.getByTestID("pin_authorize").type("000000").wait(2000); + validateMatchAddress(addresses[index], labels[index]); + cy.wait(1000); + cy.getByTestID("address_input_clear_button").click(); + cy.getByTestID("address_book_button").click(); + + // Skip test below since the order of address is rearranged + if (isEvmDomain && index === 1) { + return; + } + cy.getByTestID(`address_row_label_${index}_WHITELISTED`).contains( + labels[index], + ); + cy.getByTestID(`address_row_text_${index}_WHITELISTED`).contains( + addresses[index], + ); + + // cy.getByTestID('address_book_address_input').clear().type(addresses[index]).blur() + }); + } + + it("should enable selection only for DVM whitelisted wallet addresses in EVM domain", () => { + populateAddressBook(); + + // EVM address + cy.getByTestID("address_row_label_0_WHITELISTED").contains(labels[1]); + cy.getByTestID("address_row_text_0_WHITELISTED").contains(addresses[1]); + cy.getByTestID("address_row_0_WHITELISTED").should( + "have.attr", + "aria-disabled", + ); + + // DVM address + cy.getByTestID("address_row_label_1_WHITELISTED").contains(labels[0]); + cy.getByTestID("address_row_text_1_WHITELISTED").contains(addresses[0]); + cy.getByTestID("address_row_label_0_WHITELISTED_EVM_tag").should("exist"); + cy.getByTestID("address_row_1_WHITELISTED").should( + "not.have.attr", + "aria-disabled", + ); + }); +}); diff --git a/mobile-app/cypress/e2e/functional/wallet/portfolio/sendConfirmation.spec.ts b/mobile-app/cypress/e2e/functional/wallet/portfolio/sendConfirmation.spec.ts index d032af62a9..e9a5f36111 100644 --- a/mobile-app/cypress/e2e/functional/wallet/portfolio/sendConfirmation.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/portfolio/sendConfirmation.spec.ts @@ -20,14 +20,14 @@ context("Wallet - Send Preview/Confirmation", () => { .invoke("text") .should((t) => expect(t).equal("1.23400000")); cy.getByTestID("wallet_address").should("exist"); - cy.getByTestID("summary_to_value").should( + cy.getByTestID("address_input_footer").should( "have.text", - "bcrt1q8rfsfny80jx78cmk4rsa069e2ckp6rn83u6ut9" + "bcrt1q8rfsfny80jx78cmk4rsa069e2ckp6rn83u6ut9", ); cy.getByTestID("transaction_fee_label").should( "have.text", - "Transaction fee" + "Transaction fee", ); cy.getByTestID("transaction_fee_value").contains("DFI"); @@ -35,7 +35,7 @@ context("Wallet - Send Preview/Confirmation", () => { cy.getByTestID("text_amount").contains("1.23400000 dBTC"); cy.getByTestID("text_amount_rhsUsdAmount").should( "have.text", - "$12,340.00" + "$12,340.00", ); cy.getByTestID("button_confirm_send").should("not.have.attr", "disabled"); }); diff --git a/mobile-app/cypress/e2e/functional/wallet/settings/addressBook.spec.ts b/mobile-app/cypress/e2e/functional/wallet/settings/addressBook.spec.ts index 16ce596027..4831e5ebf1 100644 --- a/mobile-app/cypress/e2e/functional/wallet/settings/addressBook.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/settings/addressBook.spec.ts @@ -33,10 +33,10 @@ context("Wallet - Settings - Address Book", () => { cy.getByTestID("save_address_label").click().wait(1000); cy.getByTestID("pin_authorize").type("000000").wait(2000); cy.getByTestID(`address_row_label_${index}_WHITELISTED`).contains( - labels[index] + labels[index], ); cy.getByTestID(`address_row_text_${index}_WHITELISTED`).contains( - addresses[index] + addresses[index], ); }); } @@ -49,6 +49,7 @@ context("Wallet - Settings - Address Book", () => { it("should have Your Addresses tab with one wallet address", () => { cy.getByTestID("address_button_group_YOUR_ADDRESS").click(); cy.getByTestID("address_row_text_0_YOUR_ADDRESS").should("exist"); + cy.getByTestID("address_row_text_0_YOUR_ADDRESS_EVM").should("exist"); }); it("should have refresh button in Your address tab", () => { @@ -58,19 +59,64 @@ context("Wallet - Settings - Address Book", () => { it("should block wallet address during add new whitelisted address", () => { cy.getByTestID("address_row_text_0_YOUR_ADDRESS") .invoke("text") - .then((walletAddress) => { - cy.getByTestID("address_button_group_WHITELISTED").click(); - cy.getByTestID("add_new_address").click(); - cy.getByTestID("address_book_address_input") - .clear() - .type(walletAddress) - .blur(); - cy.getByTestID("address_book_address_input_error").contains( - "This address already exists in your address book, please enter a different address" - ); + .then((walletDFIAddress) => { + cy.getByTestID("address_row_text_0_YOUR_ADDRESS_EVM") + .invoke("text") + .then((walletETHAddress) => { + cy.getByTestID("address_button_group_WHITELISTED").click(); + cy.getByTestID("add_new_address").click(); + cy.getByTestID("address_book_address_type_DFI_checked").should( + "exist", + ); + // check for DFI address + cy.getByTestID("address_book_address_input") + .clear() + .type(walletDFIAddress) + .blur(); + cy.getByTestID("address_book_address_input_error").contains( + "This address already exists in your address book, please enter a different address", + ); + // check for evm address + cy.getByTestID("address_book_address_input") + .clear() + .type(walletETHAddress) + .blur(); + cy.getByTestID("address_book_address_input_error").contains( + "Please enter a valid address", + ); + // change domain type + cy.getByTestID("address_book_address_type_EVM").click(); + cy.getByTestID("address_book_address_input_error").contains( + "This address already exists in your address book, please enter a different address", + ); + }); }); }); + it("should be able to create EVM address in whitelisted tab", () => { + const evmAddress = "0x333333f332a06ECB5D20D35da44ba07986D6E203"; + const label = "EVM Address"; + cy.createEmptyWallet(true); + cy.getByTestID("header_settings").click(); + cy.getByTestID("address_book_title").click(); + cy.getByTestID("add_new_address").click(); + cy.getByTestID("address_book_label_input").type(label); + cy.getByTestID("address_book_label_input_error").should("not.exist"); + cy.getByTestID("address_book_address_type_EVM").click(); + cy.getByTestID("address_book_address_type_EVM_checked").should("exist"); + cy.getByTestID("address_book_address_input") + .clear() + .type(evmAddress) + .blur(); + cy.getByTestID("address_book_address_input_error").should("not.exist"); + cy.wait(1000); + cy.getByTestID("save_address_label").click(); + cy.getByTestID("pin_authorize").type("000000").wait(5000); + cy.getByTestID(`address_row_label_0_WHITELISTED`).contains(label); + cy.getByTestID(`address_row_text_0_WHITELISTED`).contains(evmAddress); + cy.getByTestID(`address_row_label_0_WHITELISTED_EVM_tag`).contains("EVM"); + }); + it("should be able to create address in whitelisted tab", () => { populateAddressBook(); }); @@ -81,7 +127,7 @@ context("Wallet - Settings - Address Book", () => { cy.getByTestID("search_title").contains(`Search results for “${label}`); cy.getByTestID("address_row_label_0_WHITELISTED").contains(label); cy.getByTestID("address_row_text_0_WHITELISTED").contains( - addresses[index] + addresses[index], ); cy.getByTestID("address_search_input").clear(); cy.getByTestID("search_title").contains("Search with label or address"); @@ -116,10 +162,10 @@ context("Wallet - Settings - Address Book", () => { cy.getByTestID("pin_authorize").type("000000").wait(2000); cy.wrap(modifiedLabels).each((_v, index: number) => { cy.getByTestID(`address_row_label_${index}_WHITELISTED`).contains( - modifiedLabels[index] + modifiedLabels[index], ); cy.getByTestID(`address_row_text_${index}_WHITELISTED`).contains( - addresses[index] + addresses[index], ); }); }); diff --git a/mobile-app/cypress/e2e/functional/wallet/settings/serviceProvider.spec.ts b/mobile-app/cypress/e2e/functional/wallet/settings/serviceProvider.spec.ts index b0bc35f455..bbe9d2bd7c 100644 --- a/mobile-app/cypress/e2e/functional/wallet/settings/serviceProvider.spec.ts +++ b/mobile-app/cypress/e2e/functional/wallet/settings/serviceProvider.spec.ts @@ -53,56 +53,61 @@ defichainUrlEnvs.forEach((defichainUrlEnv) => { cy.getByTestID("header_network_name") .first() .contains(defichainUrlEnv); - cy.getByTestID("setting_navigate_service_provider").contains( - "Default" + cy.getByTestID("setting_navigate_service_provider_value").contains( + "Default", ); cy.url().should("include", "app/Settings", () => { - expect(localStorage.getItem("WALLET.SERVICE_PROVIDER_URL")).to.eq( - url.default - ); + expect( + localStorage.getItem("WALLET.SERVICE_PROVIDER_URL.DVM"), + ).to.eq(url.default); }); }); }); it(`should have default service provider url on ${defichainUrlEnv}`, () => { cy.getByTestID("setting_navigate_service_provider").click(); - cy.getByTestID("endpoint_url_input").should("have.value", url.default); + cy.getByTestID("DVM_endpoint_url_input").should( + "have.value", + url.default, + ); }); it(`input should be locked and not editable on ${defichainUrlEnv}`, () => { - cy.getByTestID("endpoint_url_input").should("have.attr", "readonly"); + cy.getByTestID("DVM_endpoint_url_input").should( + "have.attr", + "readonly", + ); }); it(`can unlock to change service provider endpoint on ${defichainUrlEnv}`, () => { - cy.getByTestID("edit_service_provider").click(); + cy.getByTestID("DVM_edit_service_provider").click(); cy.getByTestID("reset_button").should("exist"); - cy.getByTestID("endpoint_url_input").should( + cy.getByTestID("DVM_endpoint_url_input").should( "not.have.attr", - "readonly" + "readonly", ); + cy.getByTestID("DVM_endpoint_url_input").should("have.value", ""); cy.getByTestID("button_submit").should("have.attr", "aria-disabled"); }); it(`should type invalid custom provider URL on ${defichainUrlEnv}`, () => { - cy.getByTestID("endpoint_url_input").should("have.value", ""); - cy.getByTestID("endpoint_url_input").type( - "http://invalidcustomURL.com" + cy.getByTestID("DVM_endpoint_url_input").type( + "http://invalidcustomURL.com", ); - cy.getByTestID("endpoint_url_input_error").contains("Invalid URL"); + cy.getByTestID("DVM_endpoint_url_input_error").contains("Invalid URL"); cy.getByTestID("button_submit").should("have.attr", "aria-disabled"); }); it(`should submit valid custom service provider on ${defichainUrlEnv}`, () => { - cy.getByTestID("endpoint_url_input").clear().type(url.custom); + cy.getByTestID("DVM_endpoint_url_input").clear().type(url.custom); cy.getByTestID("button_submit").should( "not.have.attr", - "aria-disabled" + "aria-disabled", ); cy.getByTestID("button_submit").click().wait(3000); - cy.getByTestID("pin_authorize").type("000000", { delay: 3000 }); - cy.wait(5000); - cy.url().should("include", "app/portfolio"); + cy.getByTestID("pin_authorize").type("000000").wait(5000); cy.getByTestID("bottom_tab_portfolio").click(); + cy.url().should("include", "app/portfolio"); cy.wait(4000); cy.getByTestID("header_settings").click().wait(1000); cy.wait(4000); @@ -111,7 +116,7 @@ defichainUrlEnvs.forEach((defichainUrlEnv) => { cy.getByTestID("setting_navigate_service_provider").contains("Custom"); cy.url().should("include", "app/Settings", () => { expect(localStorage.getItem("WALLET.SERVICE_PROVIDER_URL")).to.eq( - url.custom + url.custom, ); }); cy.getByTestID("bottom_tab_portfolio").click(); @@ -121,10 +126,9 @@ defichainUrlEnvs.forEach((defichainUrlEnv) => { cy.getByTestID("bottom_tab_portfolio").click(); cy.getByTestID("header_settings").click(); cy.getByTestID("setting_navigate_service_provider").click(); - cy.getByTestID("edit_service_provider").click(); + cy.getByTestID("DVM_edit_service_provider").click(); cy.getByTestID("reset_button").should("exist").click().wait(3000); - cy.getByTestID("pin_authorize").type("000000", { delay: 3000 }); - cy.wait(5000); + cy.getByTestID("pin_authorize").type("000000").wait(5000); cy.getByTestID("bottom_tab_portfolio").click(); cy.getByTestID("header_settings").click().wait(1000); cy.getByTestID("header_custom_active_network").should("not.exist"); diff --git a/package-lock.json b/package-lock.json index 0e1190667a..b7ab8af83d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,57 +11,58 @@ "@expo-google-fonts/ibm-plex-sans": "^0.2.3", "@expo-google-fonts/sora": "^0.2.3", "@expo/vector-icons": "^13.0.0", - "@gorhom/bottom-sheet": "^4.4.7", + "@gorhom/bottom-sheet": "^4.5.1", "@mealection/react-native-boring-avatars": "1.1.2", "@react-native-async-storage/async-storage": "1.18.2", - "@react-native-community/netinfo": "9.3.10", - "@react-native-community/slider": "4.4.2", - "@react-native-masked-view/masked-view": "0.2.9", - "@react-navigation/bottom-tabs": "^6.5.8", - "@react-navigation/native": "^6.1.7", - "@react-navigation/stack": "^6.3.17", - "@reduxjs/toolkit": "^1.9.5", + "@react-native-community/netinfo": "9.4.1", + "@react-native-community/slider": "4.4.3", + "@react-native-masked-view/masked-view": "0.3.0", + "@react-navigation/bottom-tabs": "^6.5.11", + "@react-navigation/native": "^6.1.9", + "@react-navigation/stack": "^6.3.20", + "@reduxjs/toolkit": "^1.9.7", "@shopify/flash-list": "1.4.3", - "@waveshq/standard-defichain-jellyfishsdk": "^2.2.0", - "@waveshq/walletkit-core": "^1.3.5", - "@waveshq/walletkit-ui": "^1.3.5", - "bignumber.js": "^9.1.1", + "@waveshq/standard-defichain-jellyfishsdk": "^2.20.0", + "@waveshq/walletkit-core": "^1.3.7", + "@waveshq/walletkit-ui": "^1.3.7", + "bignumber.js": "^9.1.2", "buffer": "^6.0.3", "classnames": "^2.3.2", - "dayjs": "^1.11.9", - "expo": "^49.0.7", + "dayjs": "^1.11.10", + "ethers": "^5.7.2", + "expo": "^49.0.16", "expo-asset": "~8.10.1", "expo-barcode-scanner": "~12.5.3", "expo-checkbox": "~2.4.0", "expo-clipboard": "~4.3.1", "expo-constants": "~14.4.2", - "expo-crypto": "~12.4.1", - "expo-file-system": "~15.4.3", + "expo-crypto": "~12.6.0", + "expo-file-system": "~15.4.4", "expo-font": "~11.4.0", - "expo-image": "~1.3.2", + "expo-image": "~1.3.4", "expo-linear-gradient": "~12.3.0", "expo-linking": "~5.0.2", - "expo-local-authentication": "~13.4.1", - "expo-localization": "~14.3.0", - "expo-secure-store": "~12.3.1", - "expo-splash-screen": "~0.20.5", - "expo-status-bar": "~1.6.0", - "expo-updates": "~0.18.11", - "expo-web-browser": "~12.3.2", + "expo-local-authentication": "~13.6.0", + "expo-localization": "~14.5.0", + "expo-secure-store": "~12.5.0", + "expo-splash-screen": "~0.22.0", + "expo-status-bar": "~1.7.1", + "expo-updates": "~0.18.16", + "expo-web-browser": "~12.5.0", "i18n-js": "^3.9.2", "install": "^0.13.0", "lodash": "^4.17.21", "lru-cache": "^7.18.3", "react": "18.2.0", "react-content-loader": "^6.2.1", - "react-devtools": "^4.28.0", + "react-devtools": "^4.28.4", "react-dom": "18.2.0", - "react-hook-form": "^7.45.4", - "react-native": "0.72.3", + "react-hook-form": "^7.47.0", + "react-native": "0.72.6", "react-native-circular-progress-indicator": "^4.4.2", "react-native-collapsible": "^1.6.1", - "react-native-confirmation-code-field": "^7.3.1", - "react-native-gesture-handler": "~2.12.1", + "react-native-confirmation-code-field": "^7.3.2", + "react-native-gesture-handler": "~2.13.4", "react-native-get-random-values": "~1.9.0", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-popover-view": "^5.1.8", @@ -71,12 +72,12 @@ "react-native-screens": "~3.22.1", "react-native-svg": "13.9.0", "react-native-swiper-flatlist": "^3.2.3", - "react-native-toast-notifications": "^3.3.1", - "react-native-web": "~0.19.7", - "react-number-format": "^5.3.0", + "react-native-toast-notifications": "^3.4.0", + "react-native-web": "~0.19.9", + "react-number-format": "^5.3.1", "react-overlays": "^5.2.1", "react-qr-code": "^2.0.12", - "react-redux": "^8.1.2", + "react-redux": "^8.1.3", "semver": "^7.5.4", "smart-buffer": "^4.2.0", "stream-browserify": "^3.0.0", @@ -84,51 +85,51 @@ "tailwindcss": "^2.2.19" }, "devDependencies": { - "@babel/core": "^7.22.10", + "@babel/core": "^7.23.2", "@babel/plugin-transform-private-methods": "^7.22.5", - "@cypress/code-coverage": "^3.11.0", + "@cypress/code-coverage": "^3.12.5", "@expo/metro-config": "0.10.7", "@testing-library/cypress": "^8.0.7", "@testing-library/react-native": "^11.5.4", - "@types/find-in-files": "^0.5.1", - "@types/i18n-js": "^3.8.4", - "@types/jest": "^29.5.3", - "@types/lodash": "^4.14.195", - "@types/randomcolor": "^0.5.7", - "@types/react-native": "~0.72.2", - "@types/react-native-loading-spinner-overlay": "^0.5.3", - "@types/react-test-renderer": "^18.0.0", - "@types/semver": "^7.5.0", + "@types/find-in-files": "^0.5.2", + "@types/i18n-js": "^3.8.7", + "@types/jest": "^29.5.6", + "@types/lodash": "^4.14.200", + "@types/randomcolor": "^0.5.8", + "@types/react-native": "~0.72.5", + "@types/react-native-loading-spinner-overlay": "^0.5.4", + "@types/react-test-renderer": "^18.0.5", + "@types/semver": "^7.5.4", "babel-plugin-istanbul": "^6.1.1", "babel-plugin-transform-remove-console": "^6.9.4", "colors": "1.4.0", "cypress": "^10.11.0", - "cypress-image-diff-js": "^1.27.3", - "eslint": "^8.47.0", + "cypress-image-diff-js": "^1.31.0", + "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-node": "^4.1.0", "eslint-config-prettier": "^9.0.0", - "eslint-plugin-cypress": "^2.14.0", - "eslint-plugin-jest": "27.2.3", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-jest": "27.4.3", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-native": "^4.0.0", + "eslint-plugin-react-native": "^4.1.0", "find-in-files": "^0.5.0", "husky": "^8.0.3", - "jest": "^29.6.3", + "jest": "^29.7.0", "jest-expo": "^49.0.0", - "lint-staged": "^14.0.0", + "lint-staged": "^14.0.1", "randomcolor": "^0.6.2", "react-dev-utils": "^12.0.1", "react-test-renderer": "18.1.0", "standard-version": "^9.5.0", "standard-version-expo": "^1.0.3", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "wait-on": "^6.0.1", - "webpack-merge": "^5.9.0" + "webpack-merge": "^5.10.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -140,9 +141,9 @@ } }, "node_modules/@adraffy/ens-normalize": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz", - "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" }, "node_modules/@ampproject/remapping": { "version": "2.2.1", @@ -157,11 +158,11 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -169,32 +170,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -214,11 +215,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -239,23 +240,23 @@ } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz", - "integrity": "sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dependencies": { - "@babel/types": "^7.22.10" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dependencies": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -286,14 +287,14 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz", - "integrity": "sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-function-name": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -316,9 +317,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz", - "integrity": "sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "regexpu-core": "^5.3.1", @@ -340,9 +341,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", - "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -355,20 +356,20 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -386,37 +387,37 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", - "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -445,13 +446,13 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz", - "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-wrap-function": "^7.22.9" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -461,12 +462,12 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", - "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { @@ -518,53 +519,53 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz", - "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dependencies": { "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -573,9 +574,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -584,9 +585,9 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", - "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", + "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -598,13 +599,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", - "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", + "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.5" + "@babel/plugin-transform-optional-chaining": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -617,6 +618,7 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-plugin-utils": "^7.20.2", @@ -634,6 +636,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -646,13 +649,13 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.10.tgz", - "integrity": "sha512-KxN6TqZzcFi4uD3UifqXElBTBNLAEH1l3vzMQj6JwJZbL2sZlThxSViOKCYY+4Ah4V4JhQ95IVB7s/Y6SJSlMQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.2.tgz", + "integrity": "sha512-eR0gJQc830fJVGz37oKLvt9W9uUIQSAovUl0e9sJ3YeO09dlcoBVYD3CLrjCj4qHdXmfiyTyFt8yeQYSN5fxLg==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.10", + "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-split-export-declaration": "^7.22.6", "@babel/plugin-syntax-decorators": "^7.22.10" }, @@ -667,6 +670,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", @@ -680,9 +684,9 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.22.5.tgz", - "integrity": "sha512-UCe1X/hplyv6A5g2WnQ90tnHRvYL29dabCWww92lO7VdfMVTVReBTRrhiMrKQejHD9oVkdnRdwYuzUZkBVQisg==", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.22.17.tgz", + "integrity": "sha512-cop/3quQBVvdz6X5SJC6AhUv3C9DrVTM06LUEXimEdWAhCSyOJIr9NiZDU9leHZ0/aiG0Sh7Zmvaku5TWYNgbA==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-export-default-from": "^7.22.5" @@ -698,6 +702,7 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -713,6 +718,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", @@ -729,6 +735,7 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", @@ -745,6 +752,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -760,6 +768,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -775,6 +784,7 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", "dependencies": { "@babel/compat-data": "^7.20.5", "@babel/helper-compilation-targets": "^7.20.7", @@ -793,6 +803,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -808,6 +819,7 @@ "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", @@ -824,6 +836,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", @@ -851,6 +864,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", "dev": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", @@ -1176,13 +1190,13 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz", - "integrity": "sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz", + "integrity": "sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/helper-remap-async-to-generator": "^7.22.20", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1223,9 +1237,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", - "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz", + "integrity": "sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -1252,11 +1266,11 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", - "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, @@ -1268,17 +1282,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz", - "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", + "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-function-name": "^7.22.5", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, @@ -1305,9 +1319,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", - "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz", + "integrity": "sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -1348,9 +1362,9 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", - "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1378,9 +1392,9 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", - "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1408,9 +1422,9 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", - "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", + "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -1438,9 +1452,9 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", - "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1467,9 +1481,9 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", - "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1496,11 +1510,11 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", - "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz", + "integrity": "sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw==", "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { @@ -1511,11 +1525,11 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", - "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz", + "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, @@ -1527,14 +1541,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", - "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz", + "integrity": "sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg==", "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1588,9 +1602,9 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", - "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1603,9 +1617,9 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", - "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1632,15 +1646,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", - "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", + "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", "dependencies": { - "@babel/compat-data": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.5", + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.22.5" + "@babel/plugin-transform-parameters": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1665,9 +1679,9 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", - "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1680,9 +1694,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz", - "integrity": "sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz", + "integrity": "sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", @@ -1696,9 +1710,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", - "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", + "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, @@ -1725,12 +1739,12 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", - "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, @@ -1770,15 +1784,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", - "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", + "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-jsx": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1845,15 +1859,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.10.tgz", - "integrity": "sha512-RchI7HePu1eu0CYNKHHHQdfenZcM4nz8rew5B1VWqeRKdcwW5aQ5HeG9eTUbWiAS1UrmHVLmoxTWHt3iLD/NhA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.2.tgz", + "integrity": "sha512-XOntj6icgzMS58jPVtQpiuF6ZFWxQiJavISGx5KGjRj+3gqZr8+N6Kx+N9BApWzgS+DOjIZfXXj0ZesenOWDyA==", "dependencies": { - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "semver": "^6.3.1" }, "engines": { @@ -1943,12 +1957,12 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.10.tgz", - "integrity": "sha512-7++c8I/ymsDo4QQBAgbraXLzIM6jmfao11KgIBEYZRReWzNWH9NtNgJcyrZiXsOPh523FQm6LfpLyy/U5fn46A==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.15.tgz", + "integrity": "sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.10", + "@babel/helper-create-class-features-plugin": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-typescript": "^7.22.5" }, @@ -2019,16 +2033,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.10.tgz", - "integrity": "sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.2.tgz", + "integrity": "sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ==", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.10", + "@babel/compat-data": "^7.23.2", + "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -2049,41 +2063,41 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.10", + "@babel/plugin-transform-async-generator-functions": "^7.23.2", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.10", + "@babel/plugin-transform-block-scoping": "^7.23.0", "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-class-static-block": "^7.22.5", - "@babel/plugin-transform-classes": "^7.22.6", + "@babel/plugin-transform-class-static-block": "^7.22.11", + "@babel/plugin-transform-classes": "^7.22.15", "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.10", + "@babel/plugin-transform-destructuring": "^7.23.0", "@babel/plugin-transform-dotall-regex": "^7.22.5", "@babel/plugin-transform-duplicate-keys": "^7.22.5", - "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.11", "@babel/plugin-transform-exponentiation-operator": "^7.22.5", - "@babel/plugin-transform-export-namespace-from": "^7.22.5", - "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.11", + "@babel/plugin-transform-for-of": "^7.22.15", "@babel/plugin-transform-function-name": "^7.22.5", - "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.11", "@babel/plugin-transform-literals": "^7.22.5", - "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.5", - "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.23.0", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-modules-systemjs": "^7.23.0", "@babel/plugin-transform-modules-umd": "^7.22.5", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.22.5", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", - "@babel/plugin-transform-numeric-separator": "^7.22.5", - "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-numeric-separator": "^7.22.11", + "@babel/plugin-transform-object-rest-spread": "^7.22.15", "@babel/plugin-transform-object-super": "^7.22.5", - "@babel/plugin-transform-optional-catch-binding": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.10", - "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.23.0", + "@babel/plugin-transform-parameters": "^7.22.15", "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", "@babel/plugin-transform-property-literals": "^7.22.5", "@babel/plugin-transform-regenerator": "^7.22.10", "@babel/plugin-transform-reserved-words": "^7.22.5", @@ -2097,10 +2111,10 @@ "@babel/plugin-transform-unicode-regex": "^7.22.5", "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "0.1.6-no-external-plugins", - "@babel/types": "^7.22.10", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", + "@babel/types": "^7.23.0", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -2120,12 +2134,12 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.22.5.tgz", - "integrity": "sha512-ta2qZ+LSiGCrP5pgcGt8xMnnkXQrq8Sa4Ulhy06BOlF5QbLw9q5hIx7bn5MrsvyTGAfh6kTOo07Q+Pfld/8Y5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.22.15.tgz", + "integrity": "sha512-dB5aIMqpkgbTfN5vDdTRPzjqtWiZcRESNR88QYnoPR+bmdYoluOzMX9tQerTv0XzSgZYctPfO1oc0N5zdog1ew==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "@babel/plugin-transform-flow-strip-types": "^7.22.5" }, "engines": { @@ -2149,15 +2163,15 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz", - "integrity": "sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.2.tgz", + "integrity": "sha512-u4UJc1XsS1GhIGteM8rnGiIvf9rJpiVgMEeCnwlLA7WJPC+jcXWJAGxYmeqs5hOZD8BbAfnV5ezBOxQbb4OUxA==", "dependencies": { "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "@babel/plugin-syntax-jsx": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.5", - "@babel/plugin-transform-typescript": "^7.22.5" + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-typescript": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -2167,9 +2181,9 @@ } }, "node_modules/@babel/register": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.5.tgz", - "integrity": "sha512-vV6pm/4CijSQ8Y47RH5SopXzursN35RQINfGJkmOlcpAtGuf94miFvIPhCKGQN7WGIcsgG1BHEX2KVdTYwTwUQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", + "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", @@ -2307,9 +2321,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2318,31 +2332,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", - "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2351,12 +2365,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2410,14 +2424,14 @@ } }, "node_modules/@cypress/code-coverage": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.11.0.tgz", - "integrity": "sha512-ihSO1s03gmLRE224oIjrbdG1ey63vw/UY+VSqQ5m/TKkAvyz6GIiniq6juk3AV/+0vQC1Eb4UWFu8ndtji4M1g==", + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@cypress/code-coverage/-/code-coverage-3.12.5.tgz", + "integrity": "sha512-0hczq2kgzkh/fBLm74rHcDRX//W3bhJJw/aPWu57/pPaRp5c+LcatWuv8ZtIWNXit2kBClueOrVj0I20Arh80A==", "dev": true, "dependencies": { - "@cypress/webpack-preprocessor": "^5.11.0", + "@cypress/webpack-preprocessor": "^6.0.0", "chalk": "4.1.2", - "dayjs": "1.11.9", + "dayjs": "1.11.10", "debug": "4.3.4", "execa": "4.1.0", "globby": "11.0.4", @@ -2426,7 +2440,11 @@ "nyc": "15.1.0" }, "peerDependencies": { - "cypress": "*" + "@babel/core": "^7.0.1", + "@babel/preset-env": "^7.0.0", + "babel-loader": "^8.3 || ^9", + "cypress": "*", + "webpack": "^4 || ^5" } }, "node_modules/@cypress/code-coverage/node_modules/ansi-styles": { @@ -2538,9 +2556,9 @@ } }, "node_modules/@cypress/webpack-preprocessor": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.17.1.tgz", - "integrity": "sha512-FE/e8ikPc8z4EVopJCaior3RGy0jd2q9Xcp5NtiwNG4XnLfEnUFTZlAGwXe75sEh4fNMPrBJW1KIz77PX5vGAw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-6.0.0.tgz", + "integrity": "sha512-1AS1Et5CNPJii0+DdBZBS8e0hlM2BkBNmYRdZO4/16A3KS3em1sjPZtFw7jJF00m6DYAdB9iy6QW/lLZ2bN0gg==", "dev": true, "dependencies": { "bluebird": "3.7.1", @@ -2550,7 +2568,7 @@ "peerDependencies": { "@babel/core": "^7.0.1", "@babel/preset-env": "^7.0.0", - "babel-loader": "^8.0.2 || ^9", + "babel-loader": "^8.3 || ^9", "webpack": "^4 || ^5" } }, @@ -2574,61 +2592,61 @@ } }, "node_modules/@defichain/jellyfish-address": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-address/-/jellyfish-address-4.0.0-rc.1.2.tgz", - "integrity": "sha512-ErcMIsfMQUkdabg2UIqfsRv04pPu3UNKG/0vx4WrYtroDG8VVOv1EWyrBCIuV4O/wM2qFJOn9Pwp3UWDVYqLXA==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-address/-/jellyfish-address-4.0.0-beta.14.1.tgz", + "integrity": "sha512-JQR90siVgN/w9ozY0ob/wYVl4uBk9B8hQSnDTNqd8lOn6K19qbnbRuGs9wD8l1O6xGg0lXCySc2oBytR51VKfQ==", "dependencies": { - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2", - "@defichain/jellyfish-network": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1", + "@defichain/jellyfish-network": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1", "bech32": "^2.0.0", "bs58": "^4.0.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-api-core": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-api-core/-/jellyfish-api-core-4.0.0-rc.1.2.tgz", - "integrity": "sha512-GM7iPiWkt8bspPS+RZGokzGwyUJp6Lqq8VmNKPow6OzHqtpVheLmhQwg2oWWQTc0yFOTHbiEXn9NK/k/gQl1Jw==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-api-core/-/jellyfish-api-core-4.0.0-beta.14.1.tgz", + "integrity": "sha512-Eob/zdPwVipk0tNXCWjnNiGp2GG8jYZOCmA8f5XgR5AkoOar1DyT6oSO8Z3rZ5/6DvoicJnc9VUH2M3z48cFsg==", "dependencies": { - "@defichain/jellyfish-json": "4.0.0-rc.1.2" + "@defichain/jellyfish-json": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-api-jsonrpc": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-api-jsonrpc/-/jellyfish-api-jsonrpc-4.0.0-rc.1.2.tgz", - "integrity": "sha512-dZI2tapqoYJGg2VE90cOMkjHZmIAak/uyIZo58eIKX57Nu3Qqu7s/LOQYnFOhRnttdanEujExee2GedzvyKZ2g==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-api-jsonrpc/-/jellyfish-api-jsonrpc-4.0.0-beta.14.1.tgz", + "integrity": "sha512-FrU/OpzIJes6Ul8pNpl6tuEIO6Grfy3ot+3Z/NR1fmDd/9aJtGWPf6K1tqbDdGWlo7kC3nkIUuHRuxMDLnwU9Q==", "dependencies": { - "@defichain/jellyfish-api-core": "4.0.0-rc.1.2", + "@defichain/jellyfish-api-core": "4.0.0-beta.14.1", "abort-controller": "^3.0.0", "cross-fetch": "^3.1.5" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-buffer": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-buffer/-/jellyfish-buffer-4.0.0-rc.1.2.tgz", - "integrity": "sha512-Z62pzcG3+/a1pQTYJ4HQlmpnLFJKQNOjZZ8YhbaKn210HxxktYZga1kfu4qsSQp4fOTyxhsl4UaUTRc1XcNtUA==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-buffer/-/jellyfish-buffer-4.0.0-beta.14.1.tgz", + "integrity": "sha512-b0E+QvU7dWbiKr1I583amq/kVS19ltgTxKLUJxwwwii3COszXUJYeZ5PQfZIqIn/jiX2dAxI4rXXKELBZh5FLA==", "dependencies": { "bignumber.js": "^9.0.2", "bn.js": "^5.2.1", "smart-buffer": "^4.2.0" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-crypto": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-crypto/-/jellyfish-crypto-4.0.0-rc.1.2.tgz", - "integrity": "sha512-AoahaWw/3RXTXA3TXzwfLnFgIYxDQjL13CDooZJC67vruMN0iQGK/hDDFE0bHm09WOmr77jShqsVz2Tlp05AJQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-crypto/-/jellyfish-crypto-4.0.0-beta.14.1.tgz", + "integrity": "sha512-wqiBaBYK2AvibFUTk4snyikhN29vdYt1ojeD4unMozWm9lI2223PzjwoOv5olSjKxyUf1XeNRLway6jaDx8WDQ==", "dependencies": { "bech32": "^2.0.0", "bip66": "^1.1.5", @@ -2641,85 +2659,74 @@ "wif": "^2.0.6" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-json": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-json/-/jellyfish-json-4.0.0-rc.1.2.tgz", - "integrity": "sha512-tjpj7VSb5n2pwZbXGwuoTeYzrkw13Ejc1FLdMuCK+vw1vl/DsQJbAlqmgKEHCenlXnzzqYku2HpS5ncHrZUXnQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-json/-/jellyfish-json-4.0.0-beta.14.1.tgz", + "integrity": "sha512-SIyLc+fhTXsueBPVDzlingodQybz44q1ulrMQjF/6ziqTYU1kbYdnkCjlvDekDw1UsSodN/QRm5fcR6TANpgaQ==", "dependencies": { "@types/lossless-json": "^1.0.1", "bignumber.js": "^9.0.2", "lossless-json": "^1.0.5" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-network": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-network/-/jellyfish-network-4.0.0-rc.1.2.tgz", - "integrity": "sha512-DXVfv8wNR9AyKAD6c1kTT1bYEYMU//lyoKVupux4I2WG5LUuMyY6aExPgT41XZ0Bh+Je4KvNAS+U5yjR29zvkQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-network/-/jellyfish-network-4.0.0-beta.14.1.tgz", + "integrity": "sha512-NzE+Rvl8kIadjv0sp6G2UWAkmla019Cvi3kMg9tMOj6X3F3bI0h0xufXNfb6rYKtZU8/0QFypatu8eYmxXm2JQ==", "dependencies": { "bignumber.js": "^9.0.2" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-testing": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-testing/-/jellyfish-testing-4.0.0-rc.1.2.tgz", - "integrity": "sha512-iWGpjZcVBRxcENvLWh7/hG3os4jxtIKuD5Ip3BBy7edPdpIXPb55IkiTnnGHXSCM3kRU//3NH0wsi/J7bMMj9w==", - "dependencies": { - "@defichain/jellyfish-api-jsonrpc": "4.0.0-rc.1.2", - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2", - "@defichain/jellyfish-network": "4.0.0-rc.1.2", - "@defichain/testcontainers": "4.0.0-rc.1.2", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-testing/-/jellyfish-testing-4.0.0-beta.14.1.tgz", + "integrity": "sha512-TR7QPdGD9TkGx7jp0+3I/6MjGIYmYjmGY2o8MxrBnk2Vk8nDR1twpndgAl+0ROtVdEcE3un6v6Wita2dr14C4g==", + "dependencies": { + "@defichain/jellyfish-api-jsonrpc": "4.0.0-beta.14.1", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1", + "@defichain/jellyfish-network": "4.0.0-beta.14.1", + "@defichain/testcontainers": "4.0.0-beta.14.1", "cross-fetch": "^3.1.5" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-transaction": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction/-/jellyfish-transaction-4.0.0-rc.1.2.tgz", - "integrity": "sha512-NA4wr1skMcfP3R0xcvM12RRrbPBtJpKaaI9sPM5kxYF6ZTBg1CEHbaVhgU+MXMaO+kdAuagFNIvjuP4GMgd0mQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction/-/jellyfish-transaction-4.0.0-beta.14.1.tgz", + "integrity": "sha512-R9i/oaYPqfUTpJFmAjAdAZ+r2i84/SP8N0bg/hRAqhnxsdSMIZRGaBzT1dBLB385k31S8uEoPoVElGdBL0/8/A==", "dependencies": { - "@defichain/jellyfish-buffer": "4.0.0-rc.1.2", - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2" + "@defichain/jellyfish-buffer": "4.0.0-beta.14.1", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-transaction-builder": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction-builder/-/jellyfish-transaction-builder-4.0.0-rc.1.2.tgz", - "integrity": "sha512-7mIMsInAHQi7BWnjNJj6k8jHE0q+KzPNE+F5JQihS48pUnFd6kWiU8VMkzn/9dzW1xxPTlz1wTMmUyIFcZFilA==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction-builder/-/jellyfish-transaction-builder-4.0.0-beta.14.1.tgz", + "integrity": "sha512-IIDv8wOxkHYRIjOI4DSRImZ5dfRf38ety3iQVlQem2klRobIoOMcs4K0X6OPAj+25RucYnrUqLAC9WlNKgp6NQ==", "dependencies": { - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction-signature": "4.0.0-rc.1.2", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction-signature": "4.0.0-beta.14.1", "ethers": "^6.7.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, - "node_modules/@defichain/jellyfish-transaction-builder/node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@defichain/jellyfish-transaction-builder/node_modules/@types/node": { "version": "18.15.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", @@ -2731,9 +2738,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/@defichain/jellyfish-transaction-builder/node_modules/ethers": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.7.1.tgz", - "integrity": "sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.0.tgz", + "integrity": "sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q==", "funding": [ { "type": "individual", @@ -2745,9 +2752,9 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.9.2", - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.7.1", + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", "@types/node": "18.15.13", "aes-js": "4.0.0-beta.5", "tslib": "2.4.0", @@ -2778,92 +2785,92 @@ } }, "node_modules/@defichain/jellyfish-transaction-signature": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction-signature/-/jellyfish-transaction-signature-4.0.0-rc.1.2.tgz", - "integrity": "sha512-Cqyz99UClM/nAlz0NkoKU1Fl12OBPYIABHW1Lb4p+TPm03lvtYvOd8VeHhejNY3gKLb7hfonexg8cWnnsXRYIw==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-transaction-signature/-/jellyfish-transaction-signature-4.0.0-beta.14.1.tgz", + "integrity": "sha512-aFsRpg9Tza+nH73KyvUGFYQ/ka5v1EhD7hu1XibIR3SLO6p6WV7xbhzmniDU3zobE6YFW2LPZBCMiEhqhqmyoQ==", "dependencies": { - "@defichain/jellyfish-buffer": "4.0.0-rc.1.2", - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2" + "@defichain/jellyfish-buffer": "4.0.0-beta.14.1", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-wallet": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet/-/jellyfish-wallet-4.0.0-rc.1.2.tgz", - "integrity": "sha512-FsKGt42spRTp/83mtnVp4RCY1tfLvvED7wZzssX3X0cypfBMKOySgoI2TDEqtn3iR/nVRAFnWaoOpSqhNrjObA==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet/-/jellyfish-wallet-4.0.0-beta.14.1.tgz", + "integrity": "sha512-TuI4DG+4kZvUMRfiJ2K5ktSj6ERubTt/Lx8Pk5bKpbjKyvj7k9EgEGtFYOv35tgGzzAl0hj8kIXKEWrIOXGleQ==", "dependencies": { - "@defichain/jellyfish-address": "4.0.0-rc.1.2", - "@defichain/jellyfish-crypto": "4.0.0-rc.1.2", - "@defichain/jellyfish-network": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction-builder": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction-signature": "4.0.0-rc.1.2" + "@defichain/jellyfish-address": "4.0.0-beta.14.1", + "@defichain/jellyfish-crypto": "4.0.0-beta.14.1", + "@defichain/jellyfish-network": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction-builder": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction-signature": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-wallet-encrypted": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-encrypted/-/jellyfish-wallet-encrypted-4.0.0-rc.1.2.tgz", - "integrity": "sha512-/QCGAV1lPPmWLcXvIIBxxf8v3lWrt7DRJm5NJLbQp++y8kr6wJLcEnOSM6EIXm3sMC0u80vQcWMgKlI4JJaXXw==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-encrypted/-/jellyfish-wallet-encrypted-4.0.0-beta.14.1.tgz", + "integrity": "sha512-4WBkWr4S2pjNhy94pK2RxA20vwR6j0Gy9lPwUjYWa2Zeq5qZ6TJ4614kS/IWyoPQAqy33CVNXkTauUtlbTH0uA==", "dependencies": { - "@defichain/jellyfish-wallet-mnemonic": "4.0.0-rc.1.2", + "@defichain/jellyfish-wallet-mnemonic": "4.0.0-beta.14.1", "scrypt-js": "^3.0.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/jellyfish-wallet-mnemonic": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-mnemonic/-/jellyfish-wallet-mnemonic-4.0.0-rc.1.2.tgz", - "integrity": "sha512-D5QY8AKLw9yLN4BdlX+36yk8hAc8lrSIiJPyujJ1qLlbe80wac4PNuRqa3m7tl+8DHOHAeE1IMy5d2yiTYkz3g==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/jellyfish-wallet-mnemonic/-/jellyfish-wallet-mnemonic-4.0.0-beta.14.1.tgz", + "integrity": "sha512-z6S3/AUNhq1jUOOb0rPxpIsttn8IpkvHrdzqv7m6fdQdImmz2hgsM3Bk8+geqsVEhjxvfU7x8YknTzY4dZU1LQ==", "dependencies": { - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2", - "@defichain/jellyfish-wallet": "4.0.0-rc.1.2", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1", + "@defichain/jellyfish-wallet": "4.0.0-beta.14.1", "bip32": "^2.0.6", "bip39": "^3.0.4", "create-hmac": "^1.1.7" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/ocean-api-client": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/ocean-api-client/-/ocean-api-client-4.0.0-rc.1.2.tgz", - "integrity": "sha512-kiZpzHiXTbbx5sW5abuJaNyEMpkkLq3bm6ORhvXLXM2kTFAe5NlE1GvFLVHPXMIA1tPl+tqqx4VVpxp2FKwMJw==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/ocean-api-client/-/ocean-api-client-4.0.0-beta.14.1.tgz", + "integrity": "sha512-TUc+y6GMO7KX7eqkZ4auuJuh/KRdywwMA/lklVK0S+I/kZXlcPJGtJyx8Doh+1A+KbjhKdVjUI7MHDjWC3CB1A==", "dependencies": { "abort-controller": "^3.0.0", "cross-fetch": "^3.1.5", "url-search-params-polyfill": "8.1.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/playground-api-client": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/playground-api-client/-/playground-api-client-4.0.0-rc.1.2.tgz", - "integrity": "sha512-1ph/mRVa5oIT5EAxcXPsOejV/LoXKlB1u6o4X53RvF82FvzDwVhu4/swns2Cq+HCndql3L/UkonUdC8wt2M2xQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/playground-api-client/-/playground-api-client-4.0.0-beta.14.1.tgz", + "integrity": "sha512-MJi2H2w5jiZIwTRPaeKYYScWCLhiDZcVOuS7M4uJTF8K+Np+pyLEB/4rQ4GhQsf8yQKmJoCoHDksLqRiIcf/WA==", "dependencies": { - "@defichain/jellyfish-api-core": "4.0.0-rc.1.2", - "@defichain/ocean-api-client": "4.0.0-rc.1.2" + "@defichain/jellyfish-api-core": "4.0.0-beta.14.1", + "@defichain/ocean-api-client": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/testcontainers": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/testcontainers/-/testcontainers-4.0.0-rc.1.2.tgz", - "integrity": "sha512-ywyb0BrY7kCvg2xdt2HyTDrLuYubd8jPq4VPsCsHcu5UXuszXolfn/dN2WShM0lxZ6uouBr48E8uTHUUoj9o7Q==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/testcontainers/-/testcontainers-4.0.0-beta.14.1.tgz", + "integrity": "sha512-p4rKtgMtLj5vVTiBP2lWr+llaFG62uQB+4zZR1bjzQKG2GJu5L03D9kHYMPjk+Jl2rvqnVdiepc+LSyn6C9fbg==", "dependencies": { - "@defichain/jellyfish-network": "4.0.0-rc.1.2", + "@defichain/jellyfish-network": "4.0.0-beta.14.1", "cross-fetch": "^3.1.5", "dockerode": "^3.3.5", "tar-fs": "^2.1.1", @@ -2872,35 +2879,35 @@ }, "peerDependencies": { "@types/tar-fs": "^2.0.1", - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/whale-api-client": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/whale-api-client/-/whale-api-client-4.0.0-rc.1.2.tgz", - "integrity": "sha512-ecdELKLdt+BAJt44P55YEJkymNdHMxQIyhmLM768FI8bKVVLgdWNZAywcLVwPQWs1smSAA42wk+5RKT0cv9k0Q==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/whale-api-client/-/whale-api-client-4.0.0-beta.14.1.tgz", + "integrity": "sha512-Hn+/HUqP0YETLyfTxsU6OLorbf8IXGi6VXYYWjuqKHFVPS/z19nGFeHX39kx6eARs50l5UV83Br2FVU5blMQuQ==", "dependencies": { - "@defichain/jellyfish-api-core": "4.0.0-rc.1.2", - "@defichain/jellyfish-api-jsonrpc": "4.0.0-rc.1.2", + "@defichain/jellyfish-api-core": "4.0.0-beta.14.1", + "@defichain/jellyfish-api-jsonrpc": "4.0.0-beta.14.1", "abort-controller": "^3.0.0", "cross-fetch": "^3.1.5", "url-search-params-polyfill": "8.1.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@defichain/whale-api-wallet": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/@defichain/whale-api-wallet/-/whale-api-wallet-4.0.0-rc.1.2.tgz", - "integrity": "sha512-h2M2etOrZ2OdL2eCP68wieBA/rHEjKokX0Y1Ke4Z5gv5Y7o8KR/TO04y/clLx3uedlHM2DhnD1fQZsCXJBx7MQ==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/@defichain/whale-api-wallet/-/whale-api-wallet-4.0.0-beta.14.1.tgz", + "integrity": "sha512-qr8eeueZK4obKgHiZX/ApkuyUMGVjmtOqyThs4XdEtAFFr4ziMExI6Xu5Ovhz1IRJU/ofGX2dAkRh6W6IAdgyQ==", "dependencies": { - "@defichain/jellyfish-transaction-builder": "4.0.0-rc.1.2", - "@defichain/jellyfish-wallet": "4.0.0-rc.1.2", - "@defichain/whale-api-client": "4.0.0-rc.1.2" + "@defichain/jellyfish-transaction-builder": "4.0.0-beta.14.1", + "@defichain/jellyfish-wallet": "4.0.0-beta.14.1", + "@defichain/whale-api-client": "4.0.0-beta.14.1" }, "peerDependencies": { - "defichain": "^4.0.0-rc.1.2" + "defichain": "^4.0.0-beta.14.1" } }, "node_modules/@egjs/hammerjs": { @@ -2915,9 +2922,9 @@ } }, "node_modules/@electron/get": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.2.tgz", - "integrity": "sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", @@ -2986,9 +2993,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.7.0.tgz", - "integrity": "sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -3016,9 +3023,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dependencies": { "type-fest": "^0.20.2" }, @@ -3041,9 +3048,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -3773,9 +3780,9 @@ } }, "node_modules/@expo/cli": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.10.11.tgz", - "integrity": "sha512-ehaAOw4SwkJ9uL5z9c3RD4LJpmMDCXZBCWZG4fonUGutks4t/GLoNRcdENkWsf6NSgkdPNgNl8KwphU1p083PQ==", + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.10.14.tgz", + "integrity": "sha512-IIZ9mYYHpNkK9XJAWLPtwTwZmasDq/NJsHLPjLtw5la4ANjWWwKYUcl3XKBECKovSDn9WHEQHGsBz6cyKS88Mg==", "dependencies": { "@babel/runtime": "^7.20.0", "@expo/code-signing-certificates": "0.0.5", @@ -3787,7 +3794,7 @@ "@expo/json-file": "^8.2.37", "@expo/metro-config": "~0.10.0", "@expo/osascript": "^2.0.31", - "@expo/package-manager": "~1.0.0", + "@expo/package-manager": "~1.1.0", "@expo/plist": "^0.0.20", "@expo/prebuild-config": "6.2.6", "@expo/rudder-sdk-node": "1.1.1", @@ -3812,7 +3819,6 @@ "graphql-tag": "^2.10.1", "https-proxy-agent": "^5.0.1", "internal-ip": "4.3.0", - "is-root": "^2.1.0", "js-yaml": "^3.13.1", "json-schema-deref-sync": "^0.13.0", "md5-file": "^3.2.3", @@ -3982,9 +3988,9 @@ } }, "node_modules/@expo/cli/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, @@ -4433,6 +4439,87 @@ "node": ">=8" } }, + "node_modules/@expo/fingerprint": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.2.0.tgz", + "integrity": "sha512-k6MhJTrX4CYEwsyGemiLT8rnBwjRBYe0eKYAM3kqw0WbSHzkOJm739sgdswGLmA53iiX6FbB1TsiLnqt+h2U2w==", + "dependencies": { + "@expo/spawn-async": "^1.5.0", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "find-up": "^5.0.0", + "minimatch": "^3.0.4", + "p-limit": "^3.1.0", + "resolve-from": "^5.0.0" + }, + "bin": { + "fingerprint": "bin/cli.js" + } + }, + "node_modules/@expo/fingerprint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@expo/fingerprint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@expo/fingerprint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@expo/fingerprint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@expo/fingerprint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@expo/fingerprint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@expo/image-utils": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.3.22.tgz", @@ -4710,9 +4797,9 @@ } }, "node_modules/@expo/package-manager": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.0.2.tgz", - "integrity": "sha512-dlUp6o8qs1mi3/+l3y7cY3oMoqQVVzvH18cUTi6+t4ob8XwTpaeP2SwOP+obwZN29dMg9YzZAv4eQz+mshAbQA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.1.2.tgz", + "integrity": "sha512-JI9XzrxB0QVXysyuJ996FPCJGDCYRkbUvgG4QmMTTMFA1T+mv8YzazC3T9C1pHQUAAveVCre1+Pqv0nZXN24Xg==", "dependencies": { "@expo/json-file": "^8.2.37", "@expo/spawn-async": "^1.5.0", @@ -5097,9 +5184,9 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "node_modules/@gorhom/bottom-sheet": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-4.4.7.tgz", - "integrity": "sha512-ukTuTqDQi2heo68hAJsBpUQeEkdqP9REBcn47OpuvPKhdPuO1RBOOADjqXJNCnZZRcY+HqbnGPMSLFVc31zylQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-4.5.1.tgz", + "integrity": "sha512-4Qy6hzvN32fXu2hDxDXOIS0IBGBT6huST7J7+K1V5bXemZ08KIx5ZffyLgwhCUl+CnyeG2KG6tqk6iYLkIwi7Q==", "dependencies": { "@gorhom/portal": "1.0.14", "invariant": "^2.2.4" @@ -5155,11 +5242,11 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -5180,9 +5267,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==" }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", @@ -5295,15 +5382,15 @@ } }, "node_modules/@jest/console": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz", - "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0" }, "engines": { @@ -5375,14 +5462,14 @@ } }, "node_modules/@jest/core": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz", - "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==", - "dependencies": { - "@jest/console": "^29.6.4", - "@jest/reporters": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", @@ -5390,21 +5477,21 @@ "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.6.3", - "jest-config": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-resolve-dependencies": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "jest-watcher": "^29.6.4", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -5474,9 +5561,9 @@ } }, "node_modules/@jest/core/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -5514,9 +5601,9 @@ } }, "node_modules/@jest/create-cache-key-function": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.6.3.tgz", - "integrity": "sha512-kzSK9XAxtD1kRPJKxsmD0YKw2fyXveP+5ikeQkCYCHeacWW1EGYMTgjDIM/Di4Uhttx7lnHwrNpz2xn+0rTp8g==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", "dependencies": { "@jest/types": "^29.6.3" }, @@ -5525,35 +5612,35 @@ } }, "node_modules/@jest/environment": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", - "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dependencies": { - "@jest/fake-timers": "^29.6.4", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dependencies": { - "expect": "^29.6.4", - "jest-snapshot": "^29.6.4" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz", - "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -5562,44 +5649,44 @@ } }, "node_modules/@jest/fake-timers": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", - "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz", - "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", "@jest/types": "^29.6.3", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz", - "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", @@ -5613,9 +5700,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -5695,9 +5782,9 @@ } }, "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -5745,11 +5832,11 @@ } }, "node_modules/@jest/test-result": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz", - "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dependencies": { - "@jest/console": "^29.6.4", + "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" @@ -5759,13 +5846,13 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz", - "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dependencies": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "slash": "^3.0.0" }, "engines": { @@ -5773,9 +5860,9 @@ } }, "node_modules/@jest/transform": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", - "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -5785,9 +5872,9 @@ "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -5842,11 +5929,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6507,9 +6589,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -6526,11 +6608,11 @@ } }, "node_modules/@netlify/functions": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-2.0.2.tgz", - "integrity": "sha512-goWRtaIPUK/q47qLYtfGGj7HgJIRaT0snw7zZ0yeoNTfQfCRwQwvRrMAsXkCsCtq2N2Oo81L26SpkMxEQMk9hg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-2.3.0.tgz", + "integrity": "sha512-E3kzXPWMP/r1rAWhjTaXcaOT47dhEvg/eQUJjRLhD9Zzp0WqkdynHr+bqff4rFNv6tuXrtFZrpbPJFKHH0c0zw==", "dependencies": { - "@netlify/serverless-functions-api": "1.7.3", + "@netlify/serverless-functions-api": "1.9.0", "is-promise": "^4.0.0" }, "engines": { @@ -6538,14 +6620,14 @@ } }, "node_modules/@netlify/ipx": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@netlify/ipx/-/ipx-1.4.4.tgz", - "integrity": "sha512-UM2pFatBDg9ehrUwA/PwpAo/PpF447uXFgKR/2QtqlPriwJlNXJ7sj/YPEblC/8UzNJjhSIv2gA6T9bcVqxe7Q==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@netlify/ipx/-/ipx-1.4.5.tgz", + "integrity": "sha512-QuPxUj8Bn8hXwjdcA1BF+HPLqFJ2e9OCNrKX/s3hoUFjjqQrNSK8lLARAtzGfOM3BRsTXyi/zGdwBE+oJKd0dw==", "dependencies": { - "@netlify/functions": "^2.0.1", + "@netlify/functions": "^2.1.0", "etag": "^1.8.1", "fs-extra": "^11.0.0", - "ipx": "^1.0.0", + "ipx": "^1.3.1", "micromatch": "^4.0.5", "mkdirp": "^3.0.0", "murmurhash": "^2.0.0", @@ -6563,9 +6645,9 @@ } }, "node_modules/@netlify/serverless-functions-api": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.7.3.tgz", - "integrity": "sha512-n6/7cJlSWvvbBlUOEAbkGyEld80S6KbG/ldQI9OhLfe1lTatgKmrTNIgqVNpaWpUdTgP2OHWFjmFBzkxxBWs5w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.9.0.tgz", + "integrity": "sha512-Jq4uk1Mwa5vyxImupJYXPP+I5yYcp3PtguvXtJRutKdm9DPALXfZVtCQzBWMNdZiqVWCM3La9hvaBsPjSMfeug==", "dependencies": { "@netlify/node-cookies": "^0.1.0", "urlpattern-polyfill": "8.0.2" @@ -6575,14 +6657,14 @@ } }, "node_modules/@next/env": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.3.tgz", - "integrity": "sha512-X4te86vsbjsB7iO4usY9jLPtZ827Mbx+WcwNBGUOIuswuTAKQtzsuoxc/6KLxCMvogKG795MhrR1LDhYgDvasg==" + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", + "integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==" }, "node_modules/@next/eslint-plugin-next": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.3.tgz", - "integrity": "sha512-lbZOoEjzSuTtpk9UgV9rOmxYw+PsSfNR+00mZcInqooiDMZ1u+RqT1YQYLsEZPW1kumZoQe5+exkCBtZ2xn0uw==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz", + "integrity": "sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg==", "dependencies": { "glob": "7.1.7" } @@ -6607,9 +6689,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.3.tgz", - "integrity": "sha512-6hiYNJxJmyYvvKGrVThzo4nTcqvqUTA/JvKim7Auaj33NexDqSNwN5YrrQu+QhZJCIpv2tULSHt+lf+rUflLSw==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz", + "integrity": "sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==", "cpu": [ "arm64" ], @@ -6622,9 +6704,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.3.tgz", - "integrity": "sha512-UpBKxu2ob9scbpJyEq/xPgpdrgBgN3aLYlxyGqlYX5/KnwpJpFuIHU2lx8upQQ7L+MEmz+fA1XSgesoK92ppwQ==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz", + "integrity": "sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==", "cpu": [ "x64" ], @@ -6637,9 +6719,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.3.tgz", - "integrity": "sha512-5AzM7Yx1Ky+oLY6pHs7tjONTF22JirDPd5Jw/3/NazJ73uGB05NqhGhB4SbeCchg7SlVYVBeRMrMSZwJwq/xoA==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz", + "integrity": "sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==", "cpu": [ "arm64" ], @@ -6652,9 +6734,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.3.tgz", - "integrity": "sha512-A/C1shbyUhj7wRtokmn73eBksjTM7fFQoY2v/0rTM5wehpkjQRLOXI8WJsag2uLhnZ4ii5OzR1rFPwoD9cvOgA==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz", + "integrity": "sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==", "cpu": [ "arm64" ], @@ -6667,9 +6749,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.3.tgz", - "integrity": "sha512-FubPuw/Boz8tKkk+5eOuDHOpk36F80rbgxlx4+xty/U71e3wZZxVYHfZXmf0IRToBn1Crb8WvLM9OYj/Ur815g==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz", + "integrity": "sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==", "cpu": [ "x64" ], @@ -6682,9 +6764,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.3.tgz", - "integrity": "sha512-DPw8nFuM1uEpbX47tM3wiXIR0Qa+atSzs9Q3peY1urkhofx44o7E1svnq+a5Q0r8lAcssLrwiM+OyJJgV/oj7g==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz", + "integrity": "sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==", "cpu": [ "x64" ], @@ -6697,9 +6779,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.3.tgz", - "integrity": "sha512-zBPSP8cHL51Gub/YV8UUePW7AVGukp2D8JU93IHbVDu2qmhFAn9LWXiOOLKplZQKxnIPUkJTQAJDCWBWU4UWUA==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz", + "integrity": "sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==", "cpu": [ "arm64" ], @@ -6712,9 +6794,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.3.tgz", - "integrity": "sha512-ONcL/lYyGUj4W37D4I2I450SZtSenmFAvapkJQNIJhrPMhzDU/AdfLkW98NvH1D2+7FXwe7yclf3+B7v28uzBQ==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz", + "integrity": "sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==", "cpu": [ "ia32" ], @@ -6727,9 +6809,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.3.tgz", - "integrity": "sha512-2Vz2tYWaLqJvLcWbbTlJ5k9AN6JD7a5CN2pAeIzpbecK8ZF/yobA39cXtv6e+Z8c5UJuVOmaTldEAIxvsIux/Q==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz", + "integrity": "sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==", "cpu": [ "x64" ], @@ -6741,6 +6823,17 @@ "node": ">= 10" } }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/hashes": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", @@ -6752,17 +6845,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7206,19 +7288,19 @@ } }, "node_modules/@react-native-community/cli": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.5.tgz", - "integrity": "sha512-wMXgKEWe6uesw7vyXKKjx5EDRog0QdXHxdgRguG14AjQRao1+4gXEWq2yyExOTi/GDY6dfJBUGTCwGQxhnk/Lg==", - "dependencies": { - "@react-native-community/cli-clean": "11.3.5", - "@react-native-community/cli-config": "11.3.5", - "@react-native-community/cli-debugger-ui": "11.3.5", - "@react-native-community/cli-doctor": "11.3.5", - "@react-native-community/cli-hermes": "11.3.5", - "@react-native-community/cli-plugin-metro": "11.3.5", - "@react-native-community/cli-server-api": "11.3.5", - "@react-native-community/cli-tools": "11.3.5", - "@react-native-community/cli-types": "11.3.5", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.7.tgz", + "integrity": "sha512-Ou8eDlF+yh2rzXeCTpMPYJ2fuqsusNOhmpYPYNQJQ2h6PvaF30kPomflgRILems+EBBuggRtcT+I+1YH4o/q6w==", + "dependencies": { + "@react-native-community/cli-clean": "11.3.7", + "@react-native-community/cli-config": "11.3.7", + "@react-native-community/cli-debugger-ui": "11.3.7", + "@react-native-community/cli-doctor": "11.3.7", + "@react-native-community/cli-hermes": "11.3.7", + "@react-native-community/cli-plugin-metro": "11.3.7", + "@react-native-community/cli-server-api": "11.3.7", + "@react-native-community/cli-tools": "11.3.7", + "@react-native-community/cli-types": "11.3.7", "chalk": "^4.1.2", "commander": "^9.4.1", "execa": "^5.0.0", @@ -7226,7 +7308,7 @@ "fs-extra": "^8.1.0", "graceful-fs": "^4.1.3", "prompts": "^2.4.0", - "semver": "^6.3.0" + "semver": "^7.5.2" }, "bin": { "react-native": "build/bin.js" @@ -7236,11 +7318,11 @@ } }, "node_modules/@react-native-community/cli-clean": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.5.tgz", - "integrity": "sha512-1+7BU962wKkIkHRp/uW3jYbQKKGtU7L+R3g59D8K6uLccuxJYUBJv18753ojMa6SD3SAq5Xh31bAre+YwVcOTA==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.7.tgz", + "integrity": "sha512-twtsv54ohcRyWVzPXL3F9VHGb4Qhn3slqqRs3wEuRzjR7cTmV2TIO2b1VhaqF4HlCgNd+cGuirvLtK2JJyaxMg==", "dependencies": { - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "execa": "^5.0.0", "prompts": "^2.4.0" @@ -7352,11 +7434,11 @@ } }, "node_modules/@react-native-community/cli-config": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.5.tgz", - "integrity": "sha512-fMblIsHlUleKfGsgWyjFJYfx1SqrsnhS/QXfA8w7iT6GrNOOjBp5UWx8+xlMDFcmOb9e42g1ExFDKl3n8FWkxQ==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.7.tgz", + "integrity": "sha512-FDBLku9xskS+bx0YFJFLCmUJhEZ4/MMSC9qPYOGBollWYdgE7k/TWI0IeYFmMALAnbCdKQAYP5N29N55Tad8lg==", "dependencies": { - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "cosmiconfig": "^5.1.0", "deepmerge": "^4.3.0", @@ -7500,22 +7582,22 @@ } }, "node_modules/@react-native-community/cli-debugger-ui": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.5.tgz", - "integrity": "sha512-o5JVCKEpPUXMX4r3p1cYjiy3FgdOEkezZcQ6owWEae2dYvV19lLYyJwnocm9Y7aG9PvpgI3PIMVh3KZbhS21eA==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.7.tgz", + "integrity": "sha512-aVmKuPKHZENR8SrflkMurZqeyLwbKieHdOvaZCh1Nn/0UC5CxWcyST2DB2XQboZwsvr3/WXKJkSUO+SZ1J9qTQ==", "dependencies": { "serve-static": "^1.13.1" } }, "node_modules/@react-native-community/cli-doctor": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.5.tgz", - "integrity": "sha512-+4BuFHjoV4FFjX5y60l0s6nS0agidb1izTVwsFixeFKW73LUkOLu+Ae5HI94RAFEPE4ePEVNgYX3FynIau6K0g==", - "dependencies": { - "@react-native-community/cli-config": "11.3.5", - "@react-native-community/cli-platform-android": "11.3.5", - "@react-native-community/cli-platform-ios": "11.3.5", - "@react-native-community/cli-tools": "11.3.5", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.7.tgz", + "integrity": "sha512-YEHUqWISOHnsl5+NM14KHelKh68Sr5/HeEZvvNdIcvcKtZic3FU7Xd1WcbNdo3gCq5JvzGFfufx02Tabh5zmrg==", + "dependencies": { + "@react-native-community/cli-config": "11.3.7", + "@react-native-community/cli-platform-android": "11.3.7", + "@react-native-community/cli-platform-ios": "11.3.7", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "command-exists": "^1.2.8", "envinfo": "^7.7.2", @@ -7525,7 +7607,7 @@ "node-stream-zip": "^1.9.1", "ora": "^5.4.1", "prompts": "^2.4.0", - "semver": "^6.3.0", + "semver": "^7.5.2", "strip-ansi": "^5.2.0", "sudo-prompt": "^9.0.0", "wcwidth": "^1.0.1", @@ -7659,14 +7741,6 @@ "node": ">=8" } }, - "node_modules/@react-native-community/cli-doctor/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -7703,12 +7777,12 @@ } }, "node_modules/@react-native-community/cli-hermes": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.5.tgz", - "integrity": "sha512-+3m34hiaJpFel8BlJE7kJOaPzWR/8U8APZG2LXojbAdBAg99EGmQcwXIgsSVJFvH8h/nezf4DHbsPKigIe33zA==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.7.tgz", + "integrity": "sha512-chkKd8n/xeZkinRvtH6QcYA8rjNOKU3S3Lw/3Psxgx+hAYV0Gyk95qJHTalx7iu+PwjOOqqvCkJo5jCkYLkoqw==", "dependencies": { - "@react-native-community/cli-platform-android": "11.3.5", - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-platform-android": "11.3.7", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "hermes-profile-transformer": "^0.0.6", "ip": "^1.1.5" @@ -7779,11 +7853,11 @@ } }, "node_modules/@react-native-community/cli-platform-android": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.5.tgz", - "integrity": "sha512-s4Lj7FKxJ/BofGi/ifjPfrA9MjFwIgYpHnHBSlqtbsvPoSYzmVCU2qlWM8fb3AmkXIwyYt4A6MEr3MmNT2UoBg==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.7.tgz", + "integrity": "sha512-WGtXI/Rm178UQb8bu1TAeFC/RJvYGnbHpULXvE20GkmeJ1HIrMjkagyk6kkY3Ej25JAP2R878gv+TJ/XiRhaEg==", "dependencies": { - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "execa": "^5.0.0", "glob": "^7.1.3", @@ -7896,11 +7970,11 @@ } }, "node_modules/@react-native-community/cli-platform-ios": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.5.tgz", - "integrity": "sha512-ytJC/YCFD7P+KuQHOT5Jzh1ho2XbJEjq71yHa1gJP2PG/Q/uB4h1x2XpxDqv5iXU6E250yjvKMmkReKTW4CTig==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.7.tgz", + "integrity": "sha512-Z/8rseBput49EldX7MogvN6zJlWzZ/4M97s2P+zjS09ZoBU7I0eOKLi0N9wx+95FNBvGQQ/0P62bB9UaFQH2jw==", "dependencies": { - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "execa": "^5.0.0", "fast-xml-parser": "^4.0.12", @@ -8036,20 +8110,20 @@ } }, "node_modules/@react-native-community/cli-plugin-metro": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.5.tgz", - "integrity": "sha512-r9AekfeLKdblB7LfWB71IrNy1XM03WrByQlUQajUOZAP2NmUUBLl9pMZscPjJeOSgLpHB9ixEFTIOhTabri/qg==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.7.tgz", + "integrity": "sha512-0WhgoBVGF1f9jXcuagQmtxpwpfP+2LbLZH4qMyo6OtYLWLG13n2uRep+8tdGzfNzl1bIuUTeE9yZSAdnf9LfYQ==", "dependencies": { - "@react-native-community/cli-server-api": "11.3.5", - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-server-api": "11.3.7", + "@react-native-community/cli-tools": "11.3.7", "chalk": "^4.1.2", "execa": "^5.0.0", - "metro": "0.76.7", - "metro-config": "0.76.7", - "metro-core": "0.76.7", - "metro-react-native-babel-transformer": "0.76.7", - "metro-resolver": "0.76.7", - "metro-runtime": "0.76.7", + "metro": "0.76.8", + "metro-config": "0.76.8", + "metro-core": "0.76.8", + "metro-react-native-babel-transformer": "0.76.8", + "metro-resolver": "0.76.8", + "metro-runtime": "0.76.8", "readline": "^1.3.0" } }, @@ -8159,12 +8233,12 @@ } }, "node_modules/@react-native-community/cli-server-api": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.5.tgz", - "integrity": "sha512-PM/jF13uD1eAKuC84lntNuM5ZvJAtyb+H896P1dBIXa9boPLa3KejfUvNVoyOUJ5s8Ht25JKbc3yieV2+GMBDA==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.7.tgz", + "integrity": "sha512-yoFyGdvR3HxCnU6i9vFqKmmSqFzCbnFSnJ29a+5dppgPRetN+d//O8ard/YHqHzToFnXutAFf2neONn23qcJAg==", "dependencies": { - "@react-native-community/cli-debugger-ui": "11.3.5", - "@react-native-community/cli-tools": "11.3.5", + "@react-native-community/cli-debugger-ui": "11.3.7", + "@react-native-community/cli-tools": "11.3.7", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.1", @@ -8190,9 +8264,9 @@ } }, "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", + "version": "15.0.17", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.17.tgz", + "integrity": "sha512-cj53I8GUcWJIgWVTSVe2L7NJAB5XWGdsoMosVvUgv1jEnMbAcsbaCzt1coUcyi8Sda5PgTWAooG8jNyDTD+CWA==", "dependencies": { "@types/yargs-parser": "*" } @@ -8301,9 +8375,9 @@ } }, "node_modules/@react-native-community/cli-tools": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.5.tgz", - "integrity": "sha512-zDklE1+ah/zL4BLxut5XbzqCj9KTHzbYBKX7//cXw2/0TpkNCaY9c+iKx//gZ5m7U1OKbb86Fm2b0AKtKVRf6Q==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.7.tgz", + "integrity": "sha512-peyhP4TV6Ps1hk+MBHTFaIR1eI3u+OfGBvr5r0wPwo3FAJvldRinMgcB/TcCcOBXVORu7ba1XYjkubPeYcqAyA==", "dependencies": { "appdirsjs": "^1.2.4", "chalk": "^4.1.2", @@ -8312,7 +8386,7 @@ "node-fetch": "^2.6.0", "open": "^6.2.0", "ora": "^5.4.1", - "semver": "^6.3.0", + "semver": "^7.5.2", "shell-quote": "^1.7.3" } }, @@ -8410,14 +8484,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@react-native-community/cli-tools/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@react-native-community/cli-tools/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8430,9 +8496,9 @@ } }, "node_modules/@react-native-community/cli-types": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.5.tgz", - "integrity": "sha512-pf0kdWMEfPSV/+8rcViDCFzbLMtWIHMZ8ay7hKwqaoWegsJ0oprSF2tSTH+LSC/7X1Beb9ssIvHj1m5C4es5Xg==", + "version": "11.3.7", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.7.tgz", + "integrity": "sha512-OhSr/TiDQkXjL5YOs8+hvGSB+HltLn5ZI0+A3DCiMsjUgTTsYh+Z63OtyMpNjrdCEFcg0MpfdU2uxstCS6Dc5g==", "dependencies": { "joi": "^17.2.1" } @@ -8608,14 +8674,6 @@ "node": ">=8" } }, - "node_modules/@react-native-community/cli/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@react-native-community/cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8636,22 +8694,22 @@ } }, "node_modules/@react-native-community/netinfo": { - "version": "9.3.10", - "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-9.3.10.tgz", - "integrity": "sha512-OwnqoJUp/4sa9e3ju+wQavAa8l0fiA3DheeLMKzKxtKeAe0CA7bNxWRM752JvRQ6A/igPnt1V0zSlu5owvQEuA==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-9.4.1.tgz", + "integrity": "sha512-dAbY5mfw+6Kas/GJ6QX9AZyY+K+eq9ad4Su6utoph/nxyH3whp5cMSgRNgE2VhGQVRZ/OG0qq3IaD3+wzoqJXw==", "peerDependencies": { "react-native": ">=0.59" } }, "node_modules/@react-native-community/slider": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.4.2.tgz", - "integrity": "sha512-D9bv+3Vd2gairAhnRPAghwccgEmoM7g562pm8i4qB3Esrms5mggF81G3UvCyc0w3jjtFHh8dpQkfEoKiP0NW/Q==" + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-4.4.3.tgz", + "integrity": "sha512-WdjvGtqJfqcCiLwtbzie53Z/H6w6dIfRHhlW832D89ySAdE5DxLAsqRhDOG0eacuAxxEB+T9sGCkVMD0fa3aBg==" }, "node_modules/@react-native-masked-view/masked-view": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.9.tgz", - "integrity": "sha512-Hs4vKBKj+15VxHZHFtMaFWSBxXoOE5Ea8saoigWhahp8Mepssm0ezU+2pTl7DK9z8Y9s5uOl/aPb4QmBZ3R3Zw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.3.0.tgz", + "integrity": "sha512-qLyoObcjzrkpNcoJjXquUePXfL1dXjHtuv+yX0zZ0Q4kG5yvVqd620+tSh7WbRoHkjpXhFBfLwvGhcWB2I0Lpw==", "peerDependencies": { "react": ">=16", "react-native": ">=0.57" @@ -8663,9 +8721,9 @@ "integrity": "sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ==" }, "node_modules/@react-native/codegen": { - "version": "0.72.6", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.72.6.tgz", - "integrity": "sha512-idTVI1es/oopN0jJT/0jB6nKdvTUKE3757zA5+NPXZTeB46CIRbmmos4XBiAec8ufu9/DigLPbHTYAaMNZJ6Ig==", + "version": "0.72.7", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.72.7.tgz", + "integrity": "sha512-O7xNcGeXGbY+VoqBGNlZ3O05gxfATlwE1Q1qQf5E38dK+tXn5BY4u0jaQ9DPjfE8pBba8g/BYI1N44lynidMtg==", "dependencies": { "@babel/parser": "^7.20.0", "flow-parser": "^0.206.0", @@ -8709,11 +8767,11 @@ } }, "node_modules/@react-navigation/bottom-tabs": { - "version": "6.5.8", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.8.tgz", - "integrity": "sha512-0aa/jXea+LyBgR5NoRNWGKw0aFhjHwCkusigMRXIrCA4kINauDcAO0w0iFbZeKfaTCVAix5kK5UxDJJ2aJpevg==", + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.11.tgz", + "integrity": "sha512-CBN/NOdxnMvmjw+AJQI1kltOYaClTZmGec5pQ3ZNTPX86ytbIOylDIITKMfTgHZcIEFQDymx1SHeS++PIL3Szw==", "dependencies": { - "@react-navigation/elements": "^1.3.18", + "@react-navigation/elements": "^1.3.21", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -8726,25 +8784,25 @@ } }, "node_modules/@react-navigation/core": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.9.tgz", - "integrity": "sha512-G9GH7bP9x0qqupxZnkSftnkn4JoXancElTvFc8FVGfEvxnxP+gBo3wqcknyBi7M5Vad4qecsYjCOa9wqsftv9g==", + "version": "6.4.10", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.10.tgz", + "integrity": "sha512-oYhqxETRHNHKsipm/BtGL0LI43Hs2VSFoWMbBdHK9OqgQPjTVUitslgLcPpo4zApCcmBWoOLX2qPxhsBda644A==", "dependencies": { "@react-navigation/routers": "^6.1.9", "escape-string-regexp": "^4.0.0", "nanoid": "^3.1.23", "query-string": "^7.1.3", "react-is": "^16.13.0", - "use-latest-callback": "^0.1.5" + "use-latest-callback": "^0.1.7" }, "peerDependencies": { "react": "*" } }, "node_modules/@react-navigation/elements": { - "version": "1.3.18", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.18.tgz", - "integrity": "sha512-/0hwnJkrr415yP0Hf4PjUKgGyfshrvNUKFXN85Mrt1gY49hy9IwxZgrrxlh0THXkPeq8q4VWw44eHDfAcQf20Q==", + "version": "1.3.21", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz", + "integrity": "sha512-eyS2C6McNR8ihUoYfc166O1D8VYVh9KIl0UQPI8/ZJVsStlfSTgeEEh+WXge6+7SFPnZ4ewzEJdSAHH+jzcEfg==", "peerDependencies": { "@react-navigation/native": "^6.0.0", "react": "*", @@ -8753,11 +8811,11 @@ } }, "node_modules/@react-navigation/native": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.7.tgz", - "integrity": "sha512-W6E3+AtTombMucCRo6q7vPmluq8hSjS+IxfazJ/SokOe7ChJX7eLvvralIsJkjFj3iWV1KgOSnHxa6hdiFasBw==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.9.tgz", + "integrity": "sha512-AMuJDpwXE7UlfyhIXaUCCynXmv69Kb8NzKgKJO7v0k0L+u6xUTbt6xvshmJ79vsvaFyaEH9Jg5FMzek5/S5qNw==", "dependencies": { - "@react-navigation/core": "^6.4.9", + "@react-navigation/core": "^6.4.10", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.1.23" @@ -8776,11 +8834,11 @@ } }, "node_modules/@react-navigation/stack": { - "version": "6.3.17", - "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.17.tgz", - "integrity": "sha512-8/8ZvJROK3fp6PRmQ9MrXd9epBowA8NkfCaWW/N9H5arqwNX9lTXAkmcjicRhjpX+UNlMBR9dTLkWvPRe2vY9A==", + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.20.tgz", + "integrity": "sha512-vE6mgZzOgoa5Uy7ayT97Cj+ZIK7DK+JBYVuKUViILlWZy6IWK7HFDuqoChSbZ1ajTIfAxj/acVGg1jkbAKsToA==", "dependencies": { - "@react-navigation/elements": "^1.3.18", + "@react-navigation/elements": "^1.3.21", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -8794,9 +8852,9 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.6.tgz", - "integrity": "sha512-Gc4ikl90ORF4viIdAkY06JNUnODjKfGxZRwATM30EdHq8hLSVoSrwXne5dd739yenP5bJxAX7tLuOWK5RPGtrw==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", "dependencies": { "immer": "^9.0.21", "redux": "^4.2.1", @@ -8828,9 +8886,9 @@ } }, "node_modules/@rushstack/eslint-patch": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.4.0.tgz", - "integrity": "sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz", + "integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==" }, "node_modules/@segment/loosely-validate-event": { "version": "2.0.0", @@ -8906,12 +8964,12 @@ } }, "node_modules/@stickyjs/jest": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@stickyjs/jest/-/jest-1.3.2.tgz", - "integrity": "sha512-jXf8sJZtcm2i05tny+bzlcQXNmozZAkvPa5EEVz1y/7QLKDHY2IsiMAjDSKKJ5kzFjdQw1whZVB1hoqewV6rWA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@stickyjs/jest/-/jest-1.3.4.tgz", + "integrity": "sha512-ps0IBJCMvtRbwEMqBARwmqjqMtsCkD4AWtXgWnmtQAR+cFDxKqnVHZQWAVplm25cZ+I/rgjPmRl4ImXtHgfRPA==", "dependencies": { - "@types/jest": "^29.5.4", - "jest": "29.6.4", + "@types/jest": "^29.5.5", + "jest": "29.7.0", "jest-extended": "4.0.1", "ts-jest": "29.1.1", "wait-for-expect": "^3.0.2" @@ -8937,21 +8995,20 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.0.0-rc.1.tgz", - "integrity": "sha512-6jzPCwvEHS+Y3QCildpOlIrqJXXJ+v2EvbtCnbKUi6FpOrrfoSPacVB3nr0cjSBG/rCXnTB0aaevx9T8iT9CrQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.0.5.tgz", + "integrity": "sha512-MThCETMkHDHTnFZHp71L+SqTtD5d6XHftFCVR1xRJdWM3qGrlQ2VCXaj0SKVcyJej2e1Opa2c7iknu1llxCDNQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/react-query": { - "version": "5.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.0.0-rc.1.tgz", - "integrity": "sha512-hFz2j/pp+faqwaBbp0KV8kgn01GfErfA1BtcwHVE/E+GJINU2ZOAiVJ43LR05JCWnIu4b9pAnOBMHv55GshMZQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.0.5.tgz", + "integrity": "sha512-ZG0Q4HZ0iuI8mWiZ2/MdVYPHbrmAVhMn7+gLOkxJh6zLIgCL4luSZlohzN5Xt4MjxfxxWioO1nemwpudaTsmQg==", "dependencies": { - "@tanstack/query-core": "5.0.0-rc.1", - "client-only": "0.0.1" + "@tanstack/query-core": "5.0.5" }, "funding": { "type": "github", @@ -9110,9 +9167,9 @@ } }, "node_modules/@testing-library/react-native/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", @@ -9163,23 +9220,23 @@ "devOptional": true }, "node_modules/@types/archiver": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.3.tgz", - "integrity": "sha512-0ABdVcXL6jOwNGY+hjWPqrxUvKelBEwNLcuv/SV2vZ4YCH8w9NttFCt+/QqI5zgMX+iX/XqVy89/r7EmLJmMpQ==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.4.tgz", + "integrity": "sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==", "dependencies": { "@types/readdir-glob": "*" } }, "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.3.tgz", + "integrity": "sha512-0Z6Tr7wjKJIk4OUEjVUQMtyunLDy339vcMaj38Kpj6jM2OE1p3S4kXExKZ7a3uXQAPCoy3sbrP1wibDKaf39oA==", "dev": true }, "node_modules/@types/babel__core": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", - "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -9189,26 +9246,26 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", + "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", + "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", + "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", "dependencies": { "@babel/types": "^7.20.7" } @@ -9225,27 +9282,27 @@ } }, "node_modules/@types/docker-modem": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.4.tgz", - "integrity": "sha512-INK4TOrJ9hbgaSqHA1HaEOCcYVftJRH0v03gCg6R57JGKgltkDvdFYBtoN4lHrJ3h8aF1upvEPN2eWVLIvKStQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.5.tgz", + "integrity": "sha512-LDkftannOJFknJDWDGbuBrT1Xu6TN28SKxsWIjbM/MHHJCO20mnuHnkkZl0YMSo7cTxvfV7V7mMkdd9ZziuSGA==", "dependencies": { "@types/node": "*", "@types/ssh2": "*" } }, "node_modules/@types/dockerode": { - "version": "3.3.20", - "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.20.tgz", - "integrity": "sha512-Q+1e3z6SPWXR/Sk+WIyJFVsSDg78S7MDaGcwAh1WKlveO1tVO8TF1rOzJir5GLnqzEdUbclFKlw/4rhwESxwPw==", + "version": "3.3.21", + "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.21.tgz", + "integrity": "sha512-1d4GSWFpOnqu2rbpz+YR97txVVouHE4/HJm7CU9JTCs/IigNO8AhVOYh+6Rqv/IRznUycMR4MVBnTHrf39Es7g==", "dependencies": { "@types/docker-modem": "*", "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.44.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", - "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", "devOptional": true, "peer": true, "dependencies": { @@ -9254,9 +9311,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", + "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", "dev": true, "peer": true, "dependencies": { @@ -9265,76 +9322,76 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", + "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", "devOptional": true, "peer": true }, "node_modules/@types/find-in-files": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@types/find-in-files/-/find-in-files-0.5.1.tgz", - "integrity": "sha512-kUPtvVXZn99bBHx08jAJgrI1NKWspuoX6RgqQgfNlH2debcwcowUV41P6Kfg4VDaCAr5KNBW9qdjIyKRnXVuBA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/find-in-files/-/find-in-files-0.5.2.tgz", + "integrity": "sha512-hAbM2HgDYVTRWOnFobGLjGRg4kWoM3LMquW7DDhstgcBTNw/1mteT2T5D1QN0TiQ67KeqjjBF3chtVljyqasBw==", "dev": true }, "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", + "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/hammerjs": { - "version": "2.0.41", - "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz", - "integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==" + "version": "2.0.43", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.43.tgz", + "integrity": "sha512-wqxfwHk83RS7+6OpytGdo5wqkqtvx+bGaIs1Rwm5NrtQHUfL4OgWs/5p0OipmjmT+fexePh37Ek+mqIpdNjQKA==" }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.4.tgz", + "integrity": "sha512-ZchYkbieA+7tnxwX/SCBySx9WwvWR8TaP5tb2jRAzwvLb/rWchGw3v0w3pqUbUvj0GCwW2Xz/AVPSk6kUGctXQ==", "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" } }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==" }, "node_modules/@types/i18n-js": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/@types/i18n-js/-/i18n-js-3.8.4.tgz", - "integrity": "sha512-lXIJLglOZsa81DzqiiG99xF6qGJvwRGqzCQe1FB+/JhgVTyGGVa63DMopEQMJdpAlUUSdJsIhC7sw5xDfDjXWw==", + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@types/i18n-js/-/i18n-js-3.8.7.tgz", + "integrity": "sha512-NFQR1FDTVq0y41o4JLPjZABStuyGoNooazTiO/Up5QjuN26Hshh63QxvStNR9GcvffLjTgk1CFGRizDg2s5nkg==", "dev": true }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==" }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", + "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", + "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -9352,9 +9409,9 @@ } }, "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -9381,9 +9438,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -9399,61 +9456,64 @@ } }, "node_modules/@types/lodash": { - "version": "4.14.197", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", - "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", + "version": "4.14.200", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz", + "integrity": "sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==", "dev": true }, "node_modules/@types/lossless-json": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/lossless-json/-/lossless-json-1.0.2.tgz", - "integrity": "sha512-RdV8M8qlWUpmk7gnY3fBB4TNn3Ab8hMMqhJC/sG77t8Zk+hjVwvZGTFv+upEBUkxXbq0+UxGAPhOml83w1IkIQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/lossless-json/-/lossless-json-1.0.3.tgz", + "integrity": "sha512-QE6ntzS+KL5C5bp3w5tV6EiJYsu2vh4hWGKFFii7VwgZpMPpVhJQAIpsOprVJJtNXbBr2+h31gDh15Ta6GjR7w==" }, "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.4.tgz", + "integrity": "sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ==" }, "node_modules/@types/node": { - "version": "20.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", - "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" + "version": "20.8.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.8.tgz", + "integrity": "sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ==", + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==" }, "node_modules/@types/nprogress": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.1.tgz", - "integrity": "sha512-TYuyVnp+nOnimgdOydDIDYIxv2kSeuJZw4tF0p/KG7hpzcMF1WkHaREwM8O4blqfT1F7rq0nht6Ko2KVUfWzBA==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@types/nprogress/-/nprogress-0.2.2.tgz", + "integrity": "sha512-2wLrSJXLztGmr7wXwM0hA/wuIOY9DznVdd+ZFofHOiXcj9JnVt+2ZeLRJ7v5ZVlmheSkUOSg3Q3O4Ce7yji79A==" }, "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", + "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.9", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", + "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" }, "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "version": "6.9.9", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", + "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==" }, "node_modules/@types/randomcolor": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.7.tgz", - "integrity": "sha512-LPcG96dGYRCsXlk1fslUNIg6ebEi+bKNyn84uBL/pu2cRSf5i/djD3ArJZOyzszVMVV/DB87va6pMZP+tRSl/w==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.8.tgz", + "integrity": "sha512-hCajbxWpZsGKf6gHiJyEJPCQ6jJaYYcryqtrXNGFnGjreXyws8xCvVln/Gg6ms/AqNntoFHxa2754E7WhpBTEg==", "dev": true }, "node_modules/@types/react": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.22.tgz", - "integrity": "sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA==", + "version": "18.2.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.31.tgz", + "integrity": "sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -9461,17 +9521,17 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "18.2.14", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", + "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-native": { - "version": "0.72.2", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.2.tgz", - "integrity": "sha512-/eEjr04Zqo7mTMszuSdrLx90+j5nWhDMMOgtnKZfAYyV3RwmlpSb7F17ilmMMxZWJY81n/JZ4e6wdhMJFpjrCg==", + "version": "0.72.5", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.5.tgz", + "integrity": "sha512-HAt+EC576kbyg3+qruzbOLgVhgDHTHJ3d3rTkWRJ0wukze+l3ldWUkh1IarERHqsUlWwmkuYu0+4TQE5y1EjwA==", "devOptional": true, "dependencies": { "@react-native/virtualized-lists": "^0.72.4", @@ -9479,9 +9539,9 @@ } }, "node_modules/@types/react-native-loading-spinner-overlay": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@types/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.3.tgz", - "integrity": "sha512-TP6//QhdBEUQT0sB9iG3+a+YKsMzP4/MJNNxSyfWsbdDTbBnO0lD9ksXdwBI5KY91r8gTmBE7PwRS+eEazZpxg==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@types/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.4.tgz", + "integrity": "sha512-Oy6QK7iPtVX40mbVZh+0n2F30OaXZmedIWldajft/twC013JBTEIsxJi/baHAru4A/0bo0z6dOkJ7LXxQH1sng==", "dev": true, "dependencies": { "@types/react": "*", @@ -9489,39 +9549,39 @@ } }, "node_modules/@types/react-test-renderer": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz", - "integrity": "sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ==", + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.5.tgz", + "integrity": "sha512-PsnmF4Hpi61PTRX+dTxkjgDdtZ09kFFgPXczoF+yBfOVxn7xBLPvKP1BUrSasYHmerj33rhoJuvpIMsJuyRqHw==", "dev": true, "dependencies": { "@types/react": "*" } }, "node_modules/@types/readdir-glob": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.1.tgz", - "integrity": "sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-trCChHpWDGCJCUPJRwD62eapW4KOru6h4S7n9KUIESaxhyBM/2Jh20P3XrFRQQ6Df78E/rq2DbUCVZlI8CXPnA==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/4YQT5Kp6HxUDb4yhRkm0bJ7TbjvTddqX7PZ5hz6qV3pxSo72f/6YPRo+Mu2DU307tm9IioO69l7uAwn5XNcFA==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz", + "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==" }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==" + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==" }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -9530,41 +9590,41 @@ "dev": true }, "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.5.tgz", + "integrity": "sha512-tAe4Q+OLFOA/AMD+0lq8ovp8t3ysxAOeaScnfNdZpUxaGl51ZMDEITxkvFl1STudQ58mz6gzVGl9VhMKhwRnZQ==", "dev": true }, "node_modules/@types/ssh2": { - "version": "1.11.14", - "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.11.14.tgz", - "integrity": "sha512-O/U38mvV4jVVrdtZz8KpmitkmeD/PUDeDNNueQhm34166dmaqb1iZ3sfarSxBArM2/iX4PZVJY3EOta0Zks9hw==", + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.11.15.tgz", + "integrity": "sha512-QFPpT9Gamh+oOKWH6uDUxe8izo8NaCJaN5HdYcbCIiS3hs7fB65KAfyGWBVXaXxXLj7IhFam5Q/ZxQ4eIPc/1Q==", "dependencies": { "@types/node": "^18.11.18" } }, "node_modules/@types/ssh2-streams": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.10.tgz", - "integrity": "sha512-r3HYPL0kPxRwk7Nk1P4JxaWPyJ2Mfnfm5efuK0vYgYZu16RerZUTyun6Yqu5KEfc3AR7BvTL1x+nzf7+kbKftQ==", + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.11.tgz", + "integrity": "sha512-UVM27UaKdWpkO96VfA4A5v0fViRoiO5VzAMiYi+z66tAobfWBA8VbEKCGZpmZRkZpUIr8XnnoHpzsNPFWaEP8w==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ssh2/node_modules/@types/node": { - "version": "18.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.0.tgz", - "integrity": "sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw==" + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", + "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==" }, "node_modules/@types/tar-fs": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.2.tgz", - "integrity": "sha512-XuZRAvdo7FbDfgQCNkc8NOdSae5XtG+of2mTSgJ85G4OG0miN4E8BTGT+JBTLO87RQ7iCwsIDCqCsHnf2IaSXA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.3.tgz", + "integrity": "sha512-ADS99HAnztB8MD+LSOdzDrDLcSe5oBIg+SUQwwsgnsOgZobWoSqYmg9ZJWdvLppoKV8R8kZinX6Om+LlsNuIlQ==", "peer": true, "dependencies": { "@types/node": "*", @@ -9572,18 +9632,18 @@ } }, "node_modules/@types/tar-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.0.tgz", - "integrity": "sha512-U05c7l6K5VdO1ZV+j3E0NJOX1hfJB497M1+QT2rXx2QqyMbEQJqBw3Utk9eUVnWPyLLqYKt5Ja1kPV1ejm6cZw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.2.tgz", + "integrity": "sha512-qnIpUItVb5u8jl3kbrHofkM40ggO3YKSzc7TWqLYjDdwlrL7CiEAkDySaGfeUBLtC50RTfh2acdz51ItUbV7pQ==", "peer": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.4.tgz", + "integrity": "sha512-95Sfz4nvMAb0Nl9DTxN3j64adfwfbBPEYq14VN7zT5J5O2M9V6iZMIIQU1U+pJyl9agHYHNCqhCXgyEtIRRa5A==", "dev": true }, "node_modules/@types/use-sync-external-store": { @@ -9592,43 +9652,43 @@ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, "node_modules/@types/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", - "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz", + "integrity": "sha512-S/2+OjBIcBl8Kur23YLe0hG1e7J5m2bHfB4UuMNoLZjIFhQWhTf1FeS+WFoXHUC6QsCEfk4pftj4J1KIKC1glA==" }, "node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.29.tgz", + "integrity": "sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", + "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==" }, "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.2.tgz", + "integrity": "sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.1.tgz", - "integrity": "sha512-3F5PtBzUW0dYlq77Lcqo13fv+58KDwUib3BddilE8ajPJT+faGgxmI9Sw+I8ZS22BYwoir9ZhNXcLi+S+I2bkw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", + "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.4.1", - "@typescript-eslint/type-utils": "6.4.1", - "@typescript-eslint/utils": "6.4.1", - "@typescript-eslint/visitor-keys": "6.4.1", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -9654,14 +9714,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.1.tgz", - "integrity": "sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg==", - "dependencies": { - "@typescript-eslint/scope-manager": "6.4.1", - "@typescript-eslint/types": "6.4.1", - "@typescript-eslint/typescript-estree": "6.4.1", - "@typescript-eslint/visitor-keys": "6.4.1", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", + "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "dependencies": { + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4" }, "engines": { @@ -9681,12 +9741,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz", - "integrity": "sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", "dependencies": { - "@typescript-eslint/types": "6.4.1", - "@typescript-eslint/visitor-keys": "6.4.1" + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -9697,13 +9757,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.1.tgz", - "integrity": "sha512-7ON8M8NXh73SGZ5XvIqWHjgX2f+vvaOarNliGhjrJnv1vdjG0LVIz+ToYfPirOoBi56jxAKLfsLm40+RvxVVXA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", + "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.4.1", - "@typescript-eslint/utils": "6.4.1", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -9724,9 +9784,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.1.tgz", - "integrity": "sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -9736,12 +9796,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz", - "integrity": "sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", "dependencies": { - "@typescript-eslint/types": "6.4.1", - "@typescript-eslint/visitor-keys": "6.4.1", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -9781,17 +9841,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.1.tgz", - "integrity": "sha512-F/6r2RieNeorU0zhqZNv89s9bDZSovv3bZQpUNOmmQK1L80/cV4KEu95YUJWi75u5PhboFoKUJBnZ4FQcoqhDw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", + "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.4.1", - "@typescript-eslint/types": "6.4.1", - "@typescript-eslint/typescript-estree": "6.4.1", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", "semver": "^7.5.4" }, "engines": { @@ -9806,11 +9866,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz", - "integrity": "sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dependencies": { - "@typescript-eslint/types": "6.4.1", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -9821,6 +9881,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@urql/core": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@urql/core/-/core-2.3.6.tgz", @@ -9846,94 +9911,495 @@ } }, "node_modules/@waveshq/standard-defichain-jellyfishsdk": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/@waveshq/standard-defichain-jellyfishsdk/-/standard-defichain-jellyfishsdk-2.11.3.tgz", - "integrity": "sha512-miD1adVBTft4aFQnKcOXVpu5kZl+MksZh144UgCLRM9xaSAWWBj1iK/me+Dwro2lSobIqM6i8DFrRbwGzbxjlQ==", - "dependencies": { - "@defichain/jellyfish-address": "4.0.0-rc.1.2", - "@defichain/jellyfish-api-core": "4.0.0-rc.1.2", - "@defichain/jellyfish-network": "4.0.0-rc.1.2", - "@defichain/jellyfish-testing": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction": "4.0.0-rc.1.2", - "@defichain/jellyfish-transaction-builder": "4.0.0-rc.1.2", - "@defichain/jellyfish-wallet": "4.0.0-rc.1.2", - "@defichain/jellyfish-wallet-encrypted": "4.0.0-rc.1.2", - "@defichain/jellyfish-wallet-mnemonic": "4.0.0-rc.1.2", - "@defichain/playground-api-client": "4.0.0-rc.1.2", - "@defichain/testcontainers": "4.0.0-rc.1.2", - "@defichain/whale-api-client": "4.0.0-rc.1.2", - "@defichain/whale-api-wallet": "4.0.0-rc.1.2", - "defichain": "4.0.0-rc.1.2" + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/@waveshq/standard-defichain-jellyfishsdk/-/standard-defichain-jellyfishsdk-2.20.0.tgz", + "integrity": "sha512-eHU2KNYxuENaM8df3LLXsX4smbJ/U9rKFOWQyMth7m2TbwKNv2LDQ5AWsMVjibVw80Jw7sx2Wukim7H/BOCInw==", + "dependencies": { + "@defichain/jellyfish-address": "4.0.0-beta.14.1", + "@defichain/jellyfish-api-core": "4.0.0-beta.14.1", + "@defichain/jellyfish-network": "4.0.0-beta.14.1", + "@defichain/jellyfish-testing": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction": "4.0.0-beta.14.1", + "@defichain/jellyfish-transaction-builder": "4.0.0-beta.14.1", + "@defichain/jellyfish-wallet": "4.0.0-beta.14.1", + "@defichain/jellyfish-wallet-encrypted": "4.0.0-beta.14.1", + "@defichain/jellyfish-wallet-mnemonic": "4.0.0-beta.14.1", + "@defichain/playground-api-client": "4.0.0-beta.14.1", + "@defichain/testcontainers": "4.0.0-beta.14.1", + "@defichain/whale-api-client": "4.0.0-beta.14.1", + "@defichain/whale-api-wallet": "4.0.0-beta.14.1", + "defichain": "4.0.0-beta.14.1" } }, "node_modules/@waveshq/standard-web": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/@waveshq/standard-web/-/standard-web-2.11.3.tgz", - "integrity": "sha512-M3IzfeSeSeJCjrw8oZO/YOMoTp8YKgqwj3YZgHmRQ4L4zjhX9msyWTvsdJN5PRyQAu4moVcmlQbqCpkEzQUUxQ==", - "dependencies": { - "@netlify/ipx": "^1.4.4", - "@reduxjs/toolkit": "^1.9.6", - "@tanstack/react-query": "^5.0.0-rc.1", - "@types/react": "18.2.22", - "@types/react-dom": "18.2.7", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/@waveshq/standard-web/-/standard-web-2.20.0.tgz", + "integrity": "sha512-viLmqNjPErgdjjWiAMyfZR9xN286ELoTLbOTg2r/tNM42IcTnE23dFhMQh0T1hJi86dMhLR1io3yCWTDBtbULA==", + "dependencies": { + "@netlify/ipx": "^1.4.5", + "@reduxjs/toolkit": "^1.9.7", + "@tanstack/react-query": "^5.0.5", + "@types/react": "18.2.31", + "@types/react-dom": "18.2.14", "follow-redirects": "^1.15.3", - "next": "13.5.3", + "next": "13.5.6", "next-sitemap": "^4.2.3", "nextjs-progressbar": "^0.0.16", "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.11.0", - "react-redux": "^8.1.2", + "react-redux": "^8.1.3", "react-responsive": "^9.0.2", "typescript": "*" } }, "node_modules/@waveshq/standard-web-linter": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/@waveshq/standard-web-linter/-/standard-web-linter-2.11.3.tgz", - "integrity": "sha512-+u+zQQpvQ8efX5ZkFsqBolKyjlFJpPat1c/w9aNXHLstgoeK7x4JiFKJw5c58d/X+B+sPJr33IjJKK3tn0la4A==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/@waveshq/standard-web-linter/-/standard-web-linter-2.20.0.tgz", + "integrity": "sha512-gWs0+EQh7C0SZwya9WxIX/DAPeTc/VjkDjdnQK5KI2H5jsvqncNUR1aD6lwPkkd5KnrNT2YQESdKBW5iitzVtQ==", "dependencies": { - "eslint": "^8.50.0", + "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", - "eslint-config-next": "13.5.3", + "eslint-config-next": "13.5.6", "eslint-config-prettier": "^9.0.0", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.28.1", + "eslint-plugin-import": "^2.29.0", "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-simple-import-sort": "^10.0.0", "husky": "^8.0.3", - "lint-staged": "^14.0.1", - "next": "13.5.3", + "lint-staged": "^15.0.2", + "next": "13.5.6", "prettier": "^3.0.3", "typescript": "^5.2.2" } }, + "node_modules/@waveshq/standard-web-linter/node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dependencies": { + "type-fest": "^1.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/lint-staged": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", + "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "2.1.0", + "listr2": "7.0.2", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.3" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/listr2": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^5.0.1", + "rfdc": "^1.3.0", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/log-update": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "dependencies": { + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/@waveshq/standard-web-linter/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@waveshq/standard-web-linter/node_modules/yaml": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "engines": { + "node": ">= 14" + } + }, "node_modules/@waveshq/walletkit-core": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@waveshq/walletkit-core/-/walletkit-core-1.3.5.tgz", - "integrity": "sha512-n8CX/+FBOl8v/8Xqdi3phlx0teleRxjwo1kmXPnT7SmGC0ASRa2l46YQRMxBrqBS4mXRSTyQU9ufnpzY31UjfQ==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@waveshq/walletkit-core/-/walletkit-core-1.3.7.tgz", + "integrity": "sha512-2ysEuTx+cO7Hz9oFoJUDtfet9rIHb/vENqgbLNlEtjhlvhMucYrSJcDF9RBeHqV9HmSgUeh3Kpz0EbqG4Tk17A==", "dependencies": { - "bignumber.js": "^9.1.1", + "bignumber.js": "^9.1.2", "ethers": "^5.7.2" } }, "node_modules/@waveshq/walletkit-ui": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@waveshq/walletkit-ui/-/walletkit-ui-1.3.5.tgz", - "integrity": "sha512-0EtBk44BTZA4MuGcmvr04o2TDskoYvxOhWv1rc701soD7jfbdfjbDup9vxEZF0OgXNdmW6A5ckTbg1qNS4geDg==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@waveshq/walletkit-ui/-/walletkit-ui-1.3.7.tgz", + "integrity": "sha512-cHuw96V2mtte4vFbjl25FyV8Pov+bq6lDMyLebe+6BRG+eDw2hlyg/wabDexD1+Vi5bkQEmeC6UiyJL3OcYXQA==", "dependencies": { "@stickyjs/jest": "^1.3.2", - "@waveshq/standard-defichain-jellyfishsdk": "^2.11.2", - "@waveshq/standard-web": "^2.11.2", - "@waveshq/standard-web-linter": "^2.11.2", - "@waveshq/walletkit-core": "1.3.5", - "bignumber.js": "^9.1.1", - "dayjs": "^1.11.9", + "@waveshq/standard-defichain-jellyfishsdk": "^2.14.0", + "@waveshq/standard-web": "^2.14.0", + "@waveshq/standard-web-linter": "^2.14.0", + "@waveshq/walletkit-core": "1.3.7", + "bignumber.js": "^9.1.2", + "dayjs": "^1.11.10", "immer": "^9.0.21", "reselect": "^4.1.8", "smart-buffer": "^4.2.0" @@ -10398,7 +10864,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } @@ -10676,14 +11142,14 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "is-string": "^1.0.7" }, "engines": { @@ -10702,15 +11168,15 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", - "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -10720,13 +11186,13 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -10737,13 +11203,13 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -10754,25 +11220,26 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.1" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", - "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1", "is-array-buffer": "^3.0.2", "is-shared-array-buffer": "^1.0.2" @@ -10887,9 +11354,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.15", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz", - "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "funding": [ { "type": "opencollective", @@ -10907,8 +11374,8 @@ "peer": true, "dependencies": { "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001520", - "fraction.js": "^4.2.0", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -10950,9 +11417,9 @@ "dev": true }, "node_modules/axe-core": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", - "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.2.tgz", + "integrity": "sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==", "engines": { "node": ">=4" } @@ -11018,11 +11485,11 @@ } }, "node_modules/babel-jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz", - "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dependencies": { - "@jest/transform": "^29.6.4", + "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", @@ -11201,12 +11668,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", - "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.2", + "@babel/helper-define-polyfill-provider": "^0.4.3", "semver": "^6.3.1" }, "peerDependencies": { @@ -11222,23 +11689,23 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", - "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2", - "core-js-compat": "^3.31.0" + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", - "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2" + "@babel/helper-define-polyfill-provider": "^0.4.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -11291,9 +11758,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-9.5.1.tgz", - "integrity": "sha512-dOLhi5C1hNOAMFYjRlsP1axswMSf9MxX7zsez9kmwrm46cyev2l2ThQ8VdDig/YdwhNScd7sQ/lovrOTObk4Hg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-9.5.2.tgz", + "integrity": "sha512-hU1G1TDiikuXV6UDZjPnX+WdbjbtidDiYhftMEVrZQSst45pDPVBWbM41TUKrpJMwv4FypsLzK+378gnMPRVWQ==", "dependencies": { "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", @@ -11302,7 +11769,7 @@ "@babel/preset-env": "^7.20.0", "babel-plugin-module-resolver": "^5.0.0", "babel-plugin-react-native-web": "~0.18.10", - "metro-react-native-babel-preset": "0.76.7" + "metro-react-native-babel-preset": "0.76.8" } }, "node_modules/babel-preset-fbjs": { @@ -11422,9 +11889,9 @@ } }, "node_modules/bignumber.js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", - "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", "engines": { "node": "*" } @@ -11727,9 +12194,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "funding": [ { "type": "opencollective", @@ -11745,10 +12212,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -12079,12 +12546,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12177,9 +12645,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001522", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz", - "integrity": "sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==", + "version": "1.0.30001554", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz", + "integrity": "sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==", "funding": [ { "type": "opencollective", @@ -12320,9 +12788,9 @@ } }, "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "funding": [ { "type": "github", @@ -12388,9 +12856,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", - "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", "engines": { "node": ">=6" }, @@ -13206,9 +13674,9 @@ } }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie-es": { "version": "1.0.0", @@ -13216,11 +13684,11 @@ "integrity": "sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==" }, "node_modules/core-js-compat": { - "version": "3.32.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz", - "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==", + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.1.tgz", + "integrity": "sha512-6pYKNOgD/j/bkC5xS5IIg6bncid3rfrI42oBH1SQJbsmYPKF7rhzcFzYCcxYMmNQQ0rCEB8WqpW7QHndOggaeQ==", "dependencies": { - "browserslist": "^4.21.10" + "browserslist": "^4.22.1" }, "funding": { "type": "opencollective", @@ -13330,6 +13798,90 @@ "sha.js": "^2.4.8" } }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/create-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/create-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -13569,9 +14121,9 @@ } }, "node_modules/cypress-image-diff-js": { - "version": "1.27.3", - "resolved": "https://registry.npmjs.org/cypress-image-diff-js/-/cypress-image-diff-js-1.27.3.tgz", - "integrity": "sha512-bKKe8va8UgEqbryAezvSa9COc4bdUQkT+x11/8/b6lJhvpp161Z4g0neKNgWOSG2ZNBmxLG7/CqfLTJD25hgbw==", + "version": "1.31.0", + "resolved": "https://registry.npmjs.org/cypress-image-diff-js/-/cypress-image-diff-js-1.31.0.tgz", + "integrity": "sha512-W/nSiAReSMrXimOYxi1A/lhoCgWoIMNcJlTfnNlaUjQ5A7wFLs7ItJcaeR6B9DN/8ObI4vHx05MIgkrw/r5MSA==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -13580,6 +14132,7 @@ "cypress-recurse": "^1.13.1", "fs-extra": "^9.0.1", "handlebars": "^4.7.7", + "lodash": "^4.17.21", "pixelmatch": "^5.1.0", "pngjs": "^3.4.0" }, @@ -13587,7 +14140,7 @@ "cypress-image-diff": "bin/cypress-image-diff.js" }, "peerDependencies": { - "cypress": "^9.6.1 || ^10 || ^11 || ^12" + "cypress": ">=9.6.1" } }, "node_modules/cypress-image-diff-js/node_modules/fs-extra": { @@ -13615,9 +14168,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.54.tgz", - "integrity": "sha512-uq7O52wvo2Lggsx1x21tKZgqkJpvwCseBBPtX/nKQfpVlEsLOb11zZ1CRsWUKvJF0+lzuA9jwvA7Pr2Wt7i3xw==", + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", "dev": true }, "node_modules/cypress/node_modules/ansi-styles": { @@ -13805,9 +14358,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", - "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -14276,13 +14829,26 @@ } }, "node_modules/defichain": { - "version": "4.0.0-rc.1.2", - "resolved": "https://registry.npmjs.org/defichain/-/defichain-4.0.0-rc.1.2.tgz", - "integrity": "sha512-GKZ14ci0X+kJyYqU+GXS3Bwcc9GJq8yrDR5WXbwKIKKbUJbkntQIWAUGNOrDUqjOkhHIcbdx/9JKOqvash5r5g==", + "version": "4.0.0-beta.14.1", + "resolved": "https://registry.npmjs.org/defichain/-/defichain-4.0.0-beta.14.1.tgz", + "integrity": "sha512-OUi91flnir9B9i4YEtSnBPlIB+n0whoxA1cjZc0S8c2ZvNtc/YznxgsaDnBe5UrbKhNtiblmveq9EjLHsI2cvA==", "engines": { "node": ">=v16.17.0" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -14292,10 +14858,11 @@ } }, "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -14315,9 +14882,9 @@ } }, "node_modules/defu": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.2.tgz", - "integrity": "sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==" + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.3.tgz", + "integrity": "sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==" }, "node_modules/del": { "version": "6.1.1", @@ -14402,9 +14969,9 @@ } }, "node_modules/destr": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.1.tgz", - "integrity": "sha512-M1Ob1zPSIvlARiJUkKqvAZ3VAqQY6Jcuth/pBKQ2b1dX/Qx0OnJ8Vux6J2H5PTMQeRzWrrbTu70VxBfv/OPDJA==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.2.tgz", + "integrity": "sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==" }, "node_modules/destroy": { "version": "1.2.0", @@ -14835,14 +15402,14 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.498", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.498.tgz", - "integrity": "sha512-4LODxAzKGVy7CJyhhN5mebwe7U2L29P+0G+HUriHnabm0d7LSff8Yn7t+Wq+2/9ze2Fu1dhX7mww090xfv7qXQ==" + "version": "1.4.566", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz", + "integrity": "sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg==" }, "node_modules/electron/node_modules/@types/node": { - "version": "16.18.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.41.tgz", - "integrity": "sha512-YZJjn+Aaw0xihnpdImxI22jqGbp0DCgTFKRycygjGx/Y27NnWFJa5FJ7P+MRT3u07dogEeMVh70pWpbIQollTA==" + "version": "16.18.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.59.tgz", + "integrity": "sha512-PJ1w2cNeKUEdey4LiPra0ZuxZFOGvetswE8qHRriV/sUkL5Al4tTmPV9D2+Y/TPIxTHHgxTfRjZVKWhPw/ORhQ==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -14911,7 +15478,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "devOptional": true, + "dev": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -14992,25 +15559,25 @@ } }, "node_modules/es-abstract": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", - "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dependencies": { "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -15018,23 +15585,23 @@ "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "safe-array-concat": "^1.0.0", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", "typed-array-buffer": "^1.0.0", "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.10" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -15063,14 +15630,14 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz", - "integrity": "sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", + "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", "dependencies": { "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.21.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.1", "es-set-tostringtag": "^2.0.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.2.1", @@ -15079,36 +15646,36 @@ "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "internal-slot": "^1.0.5", - "iterator.prototype": "^1.1.0", - "safe-array-concat": "^1.0.0" + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.0.1" } }, "node_modules/es-module-lexer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", - "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", "dev": true, "peer": true }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -15179,17 +15746,18 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -15716,11 +16284,11 @@ } }, "node_modules/eslint-config-next": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.5.3.tgz", - "integrity": "sha512-VN2qbCpq2DMWgs7SVF8KTmc8bVaWz3s4nmcFqRLs7PNBt5AXejOhJuZ4zg2sCEHOvz5RvqdwLeI++NSCV6qHVg==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.5.6.tgz", + "integrity": "sha512-o8pQsUHTo9aHqJ2YiZDym5gQAMRf7O2HndHo/JZeY7TDD+W4hk6Ma8Vw54RHiBeb7OWWO5dPirQB+Is/aVQ7Kg==", "dependencies": { - "@next/eslint-plugin-next": "13.5.3", + "@next/eslint-plugin-next": "13.5.6", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", "eslint-import-resolver-node": "^0.3.6", @@ -16266,9 +16834,9 @@ } }, "node_modules/eslint-plugin-cypress/node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dependencies": { "type-fest": "^0.20.2" }, @@ -16309,25 +16877,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", "tsconfig-paths": "^3.14.2" }, @@ -16366,9 +16934,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz", - "integrity": "sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==", + "version": "27.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.4.3.tgz", + "integrity": "sha512-7S6SmmsHsgIm06BAGCAxL+ABd9/IB3MWkz2pudj6Qqor2y1qQpWPfuFU4SG9pWj4xDjF0e+D7Llh5useuSzAZw==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -16597,9 +17165,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", - "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.8.5" @@ -16665,12 +17233,11 @@ } }, "node_modules/eslint-plugin-react-native": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.0.0.tgz", - "integrity": "sha512-kMmdxrSY7A1WgdqaGC+rY/28rh7kBGNBRsk48ovqkQmdg5j4K+DaFmegENDzMrdLkoufKGRNkKX6bgSwQTCAxQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz", + "integrity": "sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==", "dev": true, "dependencies": { - "@babel/traverse": "^7.7.4", "eslint-plugin-react-native-globals": "^0.1.1" }, "peerDependencies": { @@ -16695,11 +17262,11 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -16829,9 +17396,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/eslint/node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dependencies": { "type-fest": "^0.20.2" }, @@ -17094,39 +17661,39 @@ } }, "node_modules/expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dependencies": { - "@jest/expect-utils": "^29.6.4", + "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3" + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/expo": { - "version": "49.0.7", - "resolved": "https://registry.npmjs.org/expo/-/expo-49.0.7.tgz", - "integrity": "sha512-KGyZMuU83LNnWbfzdFrC45AhUDDAYKir7MawZJ7N8pBmHbLF8txlKq+KeZcwavD8fZREFYhSGJdTgfKPiXQymg==", + "version": "49.0.16", + "resolved": "https://registry.npmjs.org/expo/-/expo-49.0.16.tgz", + "integrity": "sha512-1TcpWUEpzCQ7FjtwO1j+l/UvNgrEDZWfQm4kOo9eVZVDNKavYo+KL4XXHeljSAOOGhI/plmpD3bvhfYoywOAFQ==", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "0.10.11", + "@expo/cli": "0.10.14", "@expo/config": "8.1.2", "@expo/config-plugins": "7.2.5", "@expo/vector-icons": "^13.0.0", - "babel-preset-expo": "~9.5.1", + "babel-preset-expo": "~9.5.2", "expo-application": "~5.3.0", "expo-asset": "~8.10.1", "expo-constants": "~14.4.2", - "expo-file-system": "~15.4.3", + "expo-file-system": "~15.4.4", "expo-font": "~11.4.0", "expo-keep-awake": "~12.3.0", - "expo-modules-autolinking": "1.5.0", - "expo-modules-core": "1.5.9", + "expo-modules-autolinking": "1.5.1", + "expo-modules-core": "1.5.11", "fbemitter": "^3.0.0", "invariant": "^2.2.4", "md5-file": "^3.2.3", @@ -17139,9 +17706,9 @@ } }, "node_modules/expo-application": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-5.3.0.tgz", - "integrity": "sha512-XLkaELwmiXW6JjFVkwuiFQaGZoNKAxNAcSJkFdz8s4rCljEwehylbzoPk37QHw3cxqb4v0/2EICtg4C4kpEVCA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-5.3.1.tgz", + "integrity": "sha512-HR2+K+Hm33vLw/TfbFaHrvUbRRNRco8R+3QaCKy7eJC2LFfT05kZ15ynGaKfB5DJ/oqPV3mxXVR/EfwmE++hoA==", "peerDependencies": { "expo": "*" } @@ -17206,9 +17773,9 @@ } }, "node_modules/expo-crypto": { - "version": "12.4.1", - "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-12.4.1.tgz", - "integrity": "sha512-/en03oPNAX6gP0bKpwA1EyLBnGG9uv0+Q7uvGYyOXaQQEvj31a+8cEvNPkv75x6GuK1hcaBfO25RtX9AGOMwVA==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-12.6.0.tgz", + "integrity": "sha512-wSq64eIJxk4lQBidtcW9wNF5AgO/UvV8W8mDhb7bo6P3xH41yvu/P4FcxevQY1taGA8VHD+fO+xQDrhPiHzFqQ==", "dependencies": { "base64-js": "^1.3.0" }, @@ -17222,9 +17789,9 @@ "integrity": "sha512-FSPy0ThcJBvzEzOZVhpOrYyHgQ8U1jJ4v7u7tr1x0KOVRqyf25APEQZFxxRPn3zAYW0tQ+uDTCbrwNymFqhQfw==" }, "node_modules/expo-file-system": { - "version": "15.4.3", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.4.3.tgz", - "integrity": "sha512-HaaCBTUATs2+i7T4jxIvoU9rViAHMvOD2eBaJ1H7xPHlwZlMORjQs7bsNKonR/TQoduxZBJLVZGawvaAJNCH8g==", + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.4.4.tgz", + "integrity": "sha512-F0xS88D85F7qVQ61r0qBnzh6VW/s6iIl+VaQEEi2nAIOQHw1JIEj4yCXPLTtbyn5VmArbe2dSL3KYz1V+BLkKA==", "dependencies": { "uuid": "^3.4.0" }, @@ -17253,9 +17820,9 @@ } }, "node_modules/expo-image": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.3.2.tgz", - "integrity": "sha512-5Dm6kPfAOptMpQSJZDaA1M+AGjRJT0b1eLjtWLLpf6Z7gG1SMAFPUNUKaQV4p9H57psqvloDNb5nPIjSdIA1HQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.3.4.tgz", + "integrity": "sha512-2N6etMJA5OWbbvL9IdPVchNoJd18kVo5gcN4uC9Xtv1VM/ik6PRB3Tz+qP/0Uglkzh/yyJjw7aDTqWozj5nLZw==", "peerDependencies": { "expo": "*" } @@ -17316,9 +17883,9 @@ } }, "node_modules/expo-local-authentication": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-13.4.1.tgz", - "integrity": "sha512-FWTUkMNo9aDT3cg02SWAcSFjTiDu20izhCn5CGwdtFNCBpPQUD0BJ/czhjrIFE70teMzE5wZUdbJuSKYonUaWA==", + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-13.6.0.tgz", + "integrity": "sha512-kvM3oZc+K0xHMBFdNAVEVUbynaq0A2coqxk8kECx25hJ3vxgIY1Dktx+UD6Y+H9zMyQwYtcGhRPW4BOK1cqRuA==", "dependencies": { "invariant": "^2.2.4" }, @@ -17327,9 +17894,9 @@ } }, "node_modules/expo-localization": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-14.3.0.tgz", - "integrity": "sha512-TML3TeVtwpfuSNwbhBspC9XsGJaa0TWJNh+UaR/35YP9fQiaJfVWUMSrAq84ba6rY1Pm3kti07LV8UUa505oqg==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-14.5.0.tgz", + "integrity": "sha512-hax+Gs5akRCKeMhDRugTW+n7ORYkKoLFWPUXviupsAioR9MXSoghRqE9nOJio8mFwhhMiUA8BflppdpUxxOiSA==", "dependencies": { "rtl-detect": "^1.0.2" }, @@ -17338,17 +17905,17 @@ } }, "node_modules/expo-manifests": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-0.7.1.tgz", - "integrity": "sha512-9+pTMWkQx3hPEmc7D3MzWM+fCqN4DnPxStfmO7daL562yw+VCiJ4gfmkioOW/optqj4AE9jWoEOVv/iXOZbPWw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-0.7.2.tgz", + "integrity": "sha512-xlhL0XI2zw3foJ0q2Ra4ieBhU0V2yz+Rv6GpVEaaIHFlIC/Dbx+mKrX5dgenZEMERr/MG7sRJaRbAVB2PaAYhA==", "dependencies": { "expo-json-utils": "~0.7.0" } }, "node_modules/expo-modules-autolinking": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.0.tgz", - "integrity": "sha512-i9zll5xNYh0/sjaa6hpZlTHodKEu2tMEFsJJYsfBMTt8G9J8gGhalOydrX/Ql1E8bQ4GxnLAqrM7duR0Tj2VTQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz", + "integrity": "sha512-yt5a1VCp2BF9CrsO689PCD5oXKP14MMhnOanQMvDn4BDpURYfzAlDVGC5fZrNQKtwn/eq3bcrxIwZ7D9QjVVRg==", "dependencies": { "@expo/config": "~8.1.0", "chalk": "^4.1.0", @@ -17448,37 +18015,236 @@ } }, "node_modules/expo-modules-core": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.5.9.tgz", - "integrity": "sha512-kQxllZfus7wM0O6X0Ud+SOnbH/kbxtEAQp2gkvDq3P3kqhtafue/H9CPDX04uWc/pypvp9vp/sZ+qvA0alaVuQ==", + "version": "1.5.11", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.5.11.tgz", + "integrity": "sha512-1Dj2t74nVjxq6xEQf2b9WFfAMhPzVnR0thY0PfRFgob4STyj3sq1U4PIHVWvKQBtDKIa227DrNRb+Hu+LqKWQg==", "dependencies": { "compare-versions": "^3.4.0", "invariant": "^2.2.4" } }, "node_modules/expo-secure-store": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-12.3.1.tgz", - "integrity": "sha512-XLIgWDiIuiR0c+AA4NCWWibAMHCZUyRcy+lQBU49U6rvG+xmd3YrBJfQjfqAPyLroEqnLPGTWUX57GyRsfDOQw==", + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-12.5.0.tgz", + "integrity": "sha512-Ow2ei+SB1w4zPLxmOg2PVPf2i45Eii0T9KUaER5iRLJAMcBWN4nyGCxzESOoN3OrvxVadP0hAn6RVE1G3gdD+Q==", "peerDependencies": { "expo": "*" } }, "node_modules/expo-splash-screen": { - "version": "0.20.5", - "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.20.5.tgz", - "integrity": "sha512-nTALYdjHpeEA30rdOWSguxn72ctv8WM8ptuUgpfRgsWyn4i6rwYds/rBXisX69XO5fg+XjHAQqijGx/b28+3tg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.22.0.tgz", + "integrity": "sha512-+iKesrtp8s3IQDXPgCwI6PZzQwhSGR/LLND1wOux8HrCmtveJQpomKBIdvwTb26GNKZiN1EtiQbnBZhn3EiKaA==", "dependencies": { - "@expo/prebuild-config": "6.2.6" + "@expo/prebuild-config": "6.4.0" }, "peerDependencies": { "expo": "*" } }, + "node_modules/expo-splash-screen/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/expo-splash-screen/node_modules/@expo/config": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.3.1.tgz", + "integrity": "sha512-5fNGAw5h/MDOc8Ulv9nonafPtOT042B7dF6vrVxSP3CY5qiVu0tCsmbL412wEcrAZ8MY7UMv9e6IzpGTgleYgg==", + "dependencies": { + "@babel/code-frame": "~7.10.4", + "@expo/config-plugins": "~7.5.0", + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/json-file": "^8.2.37", + "getenv": "^1.0.0", + "glob": "7.1.6", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0", + "semver": "7.5.3", + "slugify": "^1.3.4", + "sucrase": "^3.20.0" + } + }, + "node_modules/expo-splash-screen/node_modules/@expo/config-plugins": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.4.0.tgz", + "integrity": "sha512-/BwYRl6QQ9ZKYpVaIqHE5sSPqNZI9CUtfLfYHhpnShQUA1KHRMi6y9zjb3IXJisk0/fcrtRm2yP3A7F0l304sQ==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/json-file": "~8.2.37", + "@expo/plist": "^0.0.20", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/expo-splash-screen/node_modules/@expo/config-types": { + "version": "50.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0-alpha.2.tgz", + "integrity": "sha512-eAUMUg4wnw0bYovs+isibq4l9ssMacS/r0NolDxDdIX/N+ZjIEZ5DEl5GO8dnD0dKbN/DPWwUln7SG/nSYHfmw==" + }, + "node_modules/expo-splash-screen/node_modules/@expo/config/node_modules/@expo/config-plugins": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.5.0.tgz", + "integrity": "sha512-qOKjmgbddLh1vj9ytUT6AduhEans2cHgS42nopVgh5Wz8X+QUvPcCr1Yc8MvLM3OlbswBMCJceeosZa463i0uA==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/fingerprint": "^0.2.0", + "@expo/json-file": "~8.2.37", + "@expo/plist": "^0.0.20", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/expo-splash-screen/node_modules/@expo/prebuild-config": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.4.0.tgz", + "integrity": "sha512-RjKK7rd2H9P1pTcAcZFUd9tpxCwFNyyrlTdHZWlvZvZnBJWIyUZex7P3q7db7KLJ6UrVPmlM+B7OSc0Mxs4uoQ==", + "dependencies": { + "@expo/config": "~8.3.0", + "@expo/config-plugins": "~7.4.0", + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/image-utils": "0.3.22", + "@expo/json-file": "^8.2.37", + "debug": "^4.3.1", + "fs-extra": "^9.0.0", + "resolve-from": "^5.0.0", + "semver": "7.5.3", + "xml2js": "0.6.0" + }, + "peerDependencies": { + "expo-modules-autolinking": ">=0.8.1" + } + }, + "node_modules/expo-splash-screen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expo-splash-screen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/expo-splash-screen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expo-splash-screen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/expo-splash-screen/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo-splash-screen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/expo-splash-screen/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo-splash-screen/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo-splash-screen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/expo-status-bar": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.6.0.tgz", - "integrity": "sha512-e//Oi2WPdomMlMDD3skE4+1ZarKCJ/suvcB4Jo/nO427niKug5oppcPNYO+csR6y3ZglGuypS+3pp/hJ+Xp6fQ==" + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.7.1.tgz", + "integrity": "sha512-Wkm9uCmuQQBSU+l/AekWAQ1d0FYw560yL116+OAKJDyKBOUpPURoWkFbabM1EDxv+5scTuSThr/CvsA0nsSCow==" }, "node_modules/expo-structured-headers": { "version": "3.3.0", @@ -17486,9 +18252,9 @@ "integrity": "sha512-t+h5Zqaukd3Tn97LaWPpibVsmiC/TFP8F+8sAUliwCSMzgcb5TATRs2NcAB+JcIr8EP3JJDyYXJrZle1cjs4mQ==" }, "node_modules/expo-updates": { - "version": "0.18.11", - "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-0.18.11.tgz", - "integrity": "sha512-X7huYVAq7RhBUcoGQKk2P9K0LJdDr5EDBPQbHRM/zrQNXuW7DhCkQBVbhT6/L7pIqdVAsAxx0FqxcZcx44pDWA==", + "version": "0.18.16", + "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-0.18.16.tgz", + "integrity": "sha512-5/3Yh6FHG8oRDz1pqpn7NEO6GQBH5GV/sygnkkn3JxsiXzlOsuOY7+x+gFr4CdKVyreaoJV863ZxKvxplVE4fA==", "dependencies": { "@expo/code-signing-certificates": "0.0.5", "@expo/config": "~8.1.0", @@ -17587,9 +18353,9 @@ } }, "node_modules/expo-web-browser": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-12.3.2.tgz", - "integrity": "sha512-ohBf+vnRnGzlTleY8EQ2XQU0vRdRwqMJtKkzM9MZRPDOK5QyJYPJjpk6ixGhxdeoUG2Ogj0InvhhgX9NUn4jkg==", + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-12.5.0.tgz", + "integrity": "sha512-3uDzP19DqcEicLOB4ZH6pGWzxlCQ8mLHSmWMmfXEBhZjooUkHUrysbzkNvQQa24ijy3uoUybX4jW0xPss594kA==", "dependencies": { "compare-urls": "^2.0.0", "url": "^0.11.0" @@ -17614,9 +18380,9 @@ } }, "node_modules/expo/node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", + "version": "15.0.17", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.17.tgz", + "integrity": "sha512-cj53I8GUcWJIgWVTSVe2L7NJAB5XWGdsoMosVvUgv1jEnMbAcsbaCzt1coUcyi8Sda5PgTWAooG8jNyDTD+CWA==", "dependencies": { "@types/yargs-parser": "*" } @@ -17835,17 +18601,17 @@ "integrity": "sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==" }, "node_modules/fast-xml-parser": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz", - "integrity": "sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz", + "integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==", "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" } ], "dependencies": { @@ -18100,16 +18866,26 @@ "micromatch": "^4.0.2" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flat-cache/node_modules/rimraf": { @@ -18127,9 +18903,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, "node_modules/flow-enums-runtime": { "version": "0.0.5", @@ -18364,16 +19140,16 @@ } }, "node_modules/fraction.js": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.1.tgz", - "integrity": "sha512-/KxoyCnPM0GwYI4NN0Iag38Tqt+od3/mLuguepLgCAKPn0ZhC544nssAW0tG2/00zXEYl9W+7hwAIpLHo6Oc7Q==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "peer": true, "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/freeport-async": { @@ -18442,9 +19218,9 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", - "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", "dev": true }, "node_modules/fs.realpath": { @@ -18466,19 +19242,22 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -18518,14 +19297,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19047,14 +19826,14 @@ } }, "node_modules/h3": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.8.1.tgz", - "integrity": "sha512-m5rFuu+5bpwBBHqqS0zexjK+Q8dhtFRvO9JXQG0RvSPL6QrIT6vv42vuBM22SLOgGMoZYsHk0y7VPidt9s+nkw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.8.2.tgz", + "integrity": "sha512-1Ca0orJJlCaiFY68BvzQtP2lKLk46kcLAxVM8JgYbtm2cUg6IY7pjpYgWMwUvDO9QI30N5JAukOKoT8KD3Q0PQ==", "dependencies": { "cookie-es": "^1.0.0", "defu": "^6.1.2", "destr": "^2.0.1", - "iron-webcrypto": "^0.8.0", + "iron-webcrypto": "^0.10.1", "radix3": "^1.1.0", "ufo": "^1.3.0", "uncrypto": "^0.1.3", @@ -19091,12 +19870,9 @@ } }, "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "engines": { "node": ">= 0.4.0" } @@ -19118,11 +19894,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19211,6 +19987,17 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hermes-estree": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.12.0.tgz", @@ -19425,9 +20212,9 @@ } }, "node_modules/humanize-duration": { - "version": "3.29.0", - "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.29.0.tgz", - "integrity": "sha512-G5wZGwYTLaQAmYqhfK91aw3xt6wNbJW1RnWDh4qP1PvF4T/jnkjx2RVhG5kzB2PGsYGTn+oSDBQp+dMdILLxcg==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.30.0.tgz", + "integrity": "sha512-NxpT0fhQTFuMTLnuu1Xp+ozNpYirQnbV3NlOjEKBYlE3uvMRu3LDuq8EPc3gVXxVYnchQfqVM4/+T9iwHPLLeA==", "dev": true }, "node_modules/husky": { @@ -19817,12 +20604,12 @@ } }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -19882,9 +20669,9 @@ } }, "node_modules/ipx": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ipx/-/ipx-1.3.0.tgz", - "integrity": "sha512-Jfu+zQ0NGZwSeZ11CGMOnqWFlIyVcT8dW48e5UxKnMjQXXDy8VLTl8FIP7vRIJ9hd3ZPaJ/RIXXLJfZmBqRXWQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ipx/-/ipx-1.3.1.tgz", + "integrity": "sha512-hWRLXdMDOz2q81T2x9lowFtAGO3E5b2HtC8xOOBTrlnxygHNaVrZqJ5c1P3T7tDkC3oCocYRRz0VBffvJKeQlw==", "dependencies": { "@fastify/accept-negotiator": "^1.1.0", "consola": "^3.2.3", @@ -19892,11 +20679,11 @@ "destr": "^2.0.1", "etag": "^1.8.1", "image-meta": "^0.1.1", - "listhen": "^1.4.4", + "listhen": "^1.5.5", "node-fetch-native": "^1.4.0", "pathe": "^1.1.1", - "sharp": "^0.32.5", - "ufo": "^1.3.0", + "sharp": "^0.32.6", + "ufo": "^1.3.1", "xss": "^1.0.14" }, "bin": { @@ -19904,9 +20691,9 @@ } }, "node_modules/iron-webcrypto": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-0.8.2.tgz", - "integrity": "sha512-jGiwmpgTuF19Vt4hn3+AzaVFGpVZt7A1ysd5ivFel2r4aNVFwqaYa6aU6qsF1PM7b+WFivZHz3nipwUOXaOnHg==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-0.10.1.tgz", + "integrity": "sha512-QGOS8MRMnj/UiOa+aMIgfyHcvkhqNUsUxb1XzskENvbo+rEfp6TOwqd1KPuDzXC4OnGHcMSVxDGRoilqB8ViqA==", "funding": { "url": "https://github.com/sponsors/brc-dd" } @@ -20037,11 +20824,11 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20373,6 +21160,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "dev": true, "engines": { "node": ">=6" } @@ -20735,26 +21523,26 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.0.tgz", - "integrity": "sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", "dependencies": { - "define-properties": "^1.1.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", - "has-tostringtag": "^1.0.0", - "reflect.getprototypeof": "^1.0.3" + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" } }, "node_modules/jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz", - "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dependencies": { - "@jest/core": "^29.6.4", + "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", "import-local": "^3.0.2", - "jest-cli": "^29.6.4" + "jest-cli": "^29.7.0" }, "bin": { "jest": "bin/jest.js" @@ -20772,12 +21560,12 @@ } }, "node_modules/jest-changed-files": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz", - "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dependencies": { "execa": "^5.0.0", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "p-limit": "^3.1.0" }, "engines": { @@ -20826,27 +21614,27 @@ } }, "node_modules/jest-circus": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz", - "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^1.0.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "p-limit": "^3.1.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" @@ -20909,9 +21697,9 @@ } }, "node_modules/jest-circus/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -20949,21 +21737,20 @@ } }, "node_modules/jest-cli": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz", - "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dependencies": { - "@jest/core": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "chalk": "^4.0.0", + "create-jest": "^29.7.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "prompts": "^2.0.1", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "yargs": "^17.3.1" }, "bin": { @@ -21046,30 +21833,30 @@ } }, "node_modules/jest-config": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz", - "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.6.4", + "@jest/test-sequencer": "^29.7.0", "@jest/types": "^29.6.3", - "babel-jest": "^29.6.4", + "babel-jest": "^29.7.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.6.4", - "jest-environment-node": "^29.6.4", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-get-type": "^29.6.3", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -21143,9 +21930,9 @@ } }, "node_modules/jest-config/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21183,14 +21970,14 @@ } }, "node_modules/jest-diff": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", - "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21250,9 +22037,9 @@ } }, "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21290,9 +22077,9 @@ } }, "node_modules/jest-docblock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz", - "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dependencies": { "detect-newline": "^3.0.0" }, @@ -21301,15 +22088,15 @@ } }, "node_modules/jest-each": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz", - "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", - "jest-util": "^29.6.3", - "pretty-format": "^29.6.3" + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21369,9 +22156,9 @@ } }, "node_modules/jest-each/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21409,18 +22196,18 @@ } }, "node_modules/jest-environment-jsdom": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.3.tgz", - "integrity": "sha512-nMJz/i27Moit9bv8Z323/13Melj4FEQH93yRu7GnilvBmPBMH4EGEkEfBTJXYuubyzhMO7w/VHzljIDV+Q/SeQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", "dev": true, "dependencies": { - "@jest/environment": "^29.6.3", - "@jest/fake-timers": "^29.6.3", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", "jsdom": "^20.0.0" }, "engines": { @@ -21436,16 +22223,16 @@ } }, "node_modules/jest-environment-node": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz", - "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21521,9 +22308,9 @@ } }, "node_modules/jest-haste-map": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", - "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -21532,8 +22319,8 @@ "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -21545,12 +22332,12 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", - "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dependencies": { "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21568,9 +22355,9 @@ } }, "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21586,14 +22373,14 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/jest-matcher-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", - "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21653,9 +22440,9 @@ } }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21693,9 +22480,9 @@ } }, "node_modules/jest-message-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", - "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -21703,7 +22490,7 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -21765,9 +22552,9 @@ } }, "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -21805,13 +22592,13 @@ } }, "node_modules/jest-mock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", - "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", - "jest-util": "^29.6.3" + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21842,16 +22629,16 @@ } }, "node_modules/jest-resolve": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz", - "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" @@ -21861,12 +22648,12 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz", - "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dependencies": { "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.6.4" + "jest-snapshot": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -21937,29 +22724,29 @@ } }, "node_modules/jest-runner": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz", - "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==", - "dependencies": { - "@jest/console": "^29.6.4", - "@jest/environment": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.6.3", - "jest-environment-node": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-leak-detector": "^29.6.3", - "jest-message-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-util": "^29.6.3", - "jest-watcher": "^29.6.4", - "jest-worker": "^29.6.4", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -22032,16 +22819,16 @@ } }, "node_modules/jest-runtime": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz", - "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", - "@jest/globals": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", @@ -22049,13 +22836,13 @@ "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -22128,29 +22915,29 @@ } }, "node_modules/jest-snapshot": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz", - "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-jsx": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.6.4", + "expect": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "semver": "^7.5.3" }, "engines": { @@ -22211,9 +22998,9 @@ } }, "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -22251,9 +23038,9 @@ } }, "node_modules/jest-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", - "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -22331,16 +23118,16 @@ } }, "node_modules/jest-validate": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz", - "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -22411,9 +23198,9 @@ } }, "node_modules/jest-validate/node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -22711,17 +23498,17 @@ } }, "node_modules/jest-watcher": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz", - "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dependencies": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "string-length": "^4.0.1" }, "engines": { @@ -22793,12 +23580,12 @@ } }, "node_modules/jest-worker": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz", - "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dependencies": { "@types/node": "*", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -22861,9 +23648,9 @@ } }, "node_modules/joi": { - "version": "17.9.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz", - "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -23076,9 +23863,9 @@ } }, "node_modules/jsdom/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "dev": true, "engines": { "node": ">=10.0.0" @@ -23268,9 +24055,9 @@ } }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -23581,6 +24368,7 @@ "version": "14.0.1", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz", "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==", + "dev": true, "dependencies": { "chalk": "5.3.0", "commander": "11.0.0", @@ -23607,6 +24395,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, "dependencies": { "type-fest": "^1.0.2" }, @@ -23621,6 +24410,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, "engines": { "node": ">=12" }, @@ -23632,6 +24422,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { "node": ">=12" }, @@ -23643,6 +24434,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -23654,6 +24446,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, "dependencies": { "restore-cursor": "^4.0.0" }, @@ -23668,6 +24461,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^5.0.0" @@ -23683,6 +24477,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, "engines": { "node": ">=16" } @@ -23691,6 +24486,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", @@ -23713,6 +24509,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, "engines": { "node": ">=10" }, @@ -23724,6 +24521,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, "engines": { "node": ">=14.18.0" } @@ -23732,6 +24530,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, "engines": { "node": ">=12" }, @@ -23743,6 +24542,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -23754,6 +24554,7 @@ "version": "6.6.1", "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "dev": true, "dependencies": { "cli-truncate": "^3.1.0", "colorette": "^2.0.20", @@ -23778,6 +24579,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "dev": true, "dependencies": { "ansi-escapes": "^5.0.0", "cli-cursor": "^4.0.0", @@ -23796,6 +24598,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, "engines": { "node": ">=12" }, @@ -23807,6 +24610,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, "dependencies": { "path-key": "^4.0.0" }, @@ -23821,6 +24625,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, "dependencies": { "mimic-fn": "^4.0.0" }, @@ -23835,6 +24640,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "engines": { "node": ">=12" }, @@ -23846,6 +24652,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -23861,6 +24668,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "engines": { "node": ">=6" } @@ -23869,6 +24677,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -23883,6 +24692,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" @@ -23898,6 +24708,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -23914,6 +24725,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -23928,6 +24740,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { "node": ">=12" }, @@ -23939,6 +24752,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, "engines": { "node": ">=10" }, @@ -23950,6 +24764,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -24884,9 +25699,9 @@ } }, "node_modules/metro": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz", - "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.8.tgz", + "integrity": "sha512-oQA3gLzrrYv3qKtuWArMgHPbHu8odZOD9AoavrqSFllkPgOtmkBvNNDLCELqv5SjBfqjISNffypg+5UGG3y0pg==", "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/core": "^7.20.0", @@ -24910,22 +25725,22 @@ "jest-worker": "^27.2.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.76.7", - "metro-cache": "0.76.7", - "metro-cache-key": "0.76.7", - "metro-config": "0.76.7", - "metro-core": "0.76.7", - "metro-file-map": "0.76.7", - "metro-inspector-proxy": "0.76.7", - "metro-minify-terser": "0.76.7", - "metro-minify-uglify": "0.76.7", - "metro-react-native-babel-preset": "0.76.7", - "metro-resolver": "0.76.7", - "metro-runtime": "0.76.7", - "metro-source-map": "0.76.7", - "metro-symbolicate": "0.76.7", - "metro-transform-plugins": "0.76.7", - "metro-transform-worker": "0.76.7", + "metro-babel-transformer": "0.76.8", + "metro-cache": "0.76.8", + "metro-cache-key": "0.76.8", + "metro-config": "0.76.8", + "metro-core": "0.76.8", + "metro-file-map": "0.76.8", + "metro-inspector-proxy": "0.76.8", + "metro-minify-terser": "0.76.8", + "metro-minify-uglify": "0.76.8", + "metro-react-native-babel-preset": "0.76.8", + "metro-resolver": "0.76.8", + "metro-runtime": "0.76.8", + "metro-source-map": "0.76.8", + "metro-symbolicate": "0.76.8", + "metro-transform-plugins": "0.76.8", + "metro-transform-worker": "0.76.8", "mime-types": "^2.1.27", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", @@ -24945,9 +25760,9 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz", - "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.8.tgz", + "integrity": "sha512-Hh6PW34Ug/nShlBGxkwQJSgPGAzSJ9FwQXhUImkzdsDgVu6zj5bx258J8cJVSandjNoQ8nbaHK6CaHlnbZKbyA==", "dependencies": { "@babel/core": "^7.20.0", "hermes-parser": "0.12.0", @@ -24958,11 +25773,11 @@ } }, "node_modules/metro-cache": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz", - "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.8.tgz", + "integrity": "sha512-QBJSJIVNH7Hc/Yo6br/U/qQDUpiUdRgZ2ZBJmvAbmAKp2XDzsapnMwK/3BGj8JNWJF7OLrqrYHsRsukSbUBpvQ==", "dependencies": { - "metro-core": "0.76.7", + "metro-core": "0.76.8", "rimraf": "^3.0.2" }, "engines": { @@ -24970,9 +25785,9 @@ } }, "node_modules/metro-cache-key": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz", - "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.8.tgz", + "integrity": "sha512-buKQ5xentPig9G6T37Ww/R/bC+/V1MA5xU/D8zjnhlelsrPG6w6LtHUS61ID3zZcMZqYaELWk5UIadIdDsaaLw==", "engines": { "node": ">=16" } @@ -24992,17 +25807,17 @@ } }, "node_modules/metro-config": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz", - "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.8.tgz", + "integrity": "sha512-SL1lfKB0qGHALcAk2zBqVgQZpazDYvYFGwCK1ikz0S6Y/CM2i2/HwuZN31kpX6z3mqjv/6KvlzaKoTb1otuSAA==", "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.2.1", - "metro": "0.76.7", - "metro-cache": "0.76.7", - "metro-core": "0.76.7", - "metro-runtime": "0.76.7" + "metro": "0.76.8", + "metro-cache": "0.76.8", + "metro-core": "0.76.8", + "metro-runtime": "0.76.8" }, "engines": { "node": ">=16" @@ -25080,21 +25895,21 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/metro-core": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz", - "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.8.tgz", + "integrity": "sha512-sl2QLFI3d1b1XUUGxwzw/KbaXXU/bvFYrSKz6Sg19AdYGWFyzsgZ1VISRIDf+HWm4R/TJXluhWMEkEtZuqi3qA==", "dependencies": { "lodash.throttle": "^4.1.1", - "metro-resolver": "0.76.7" + "metro-resolver": "0.76.8" }, "engines": { "node": ">=16" } }, "node_modules/metro-file-map": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz", - "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.8.tgz", + "integrity": "sha512-A/xP1YNEVwO1SUV9/YYo6/Y1MmzhL4ZnVgcJC3VmHp/BYVOXVStzgVbWv2wILe56IIMkfXU+jpXrGKKYhFyHVw==", "dependencies": { "anymatch": "^3.0.3", "debug": "^2.2.0", @@ -25132,9 +25947,9 @@ } }, "node_modules/metro-file-map/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "version": "16.0.7", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.7.tgz", + "integrity": "sha512-lQcYmxWuOfJq4IncK88/nwud9rwr1F04CFc5xzk0k4oKVyz/AI35TfsXmhjf6t8zp8mpCOi17BfvuNWx+zrYkg==", "dependencies": { "@types/yargs-parser": "*" } @@ -25268,9 +26083,9 @@ } }, "node_modules/metro-inspector-proxy": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz", - "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.8.tgz", + "integrity": "sha512-Us5o5UEd4Smgn1+TfHX4LvVPoWVo9VsVMn4Ldbk0g5CQx3Gu0ygc/ei2AKPGTwsOZmKxJeACj7yMH2kgxQP/iw==", "dependencies": { "connect": "^3.6.5", "debug": "^2.2.0", @@ -25319,9 +26134,9 @@ } }, "node_modules/metro-minify-terser": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz", - "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.8.tgz", + "integrity": "sha512-Orbvg18qXHCrSj1KbaeSDVYRy/gkro2PC7Fy2tDSH1c9RB4aH8tuMOIXnKJE+1SXxBtjWmQ5Yirwkth2DyyEZA==", "dependencies": { "terser": "^5.15.0" }, @@ -25330,9 +26145,9 @@ } }, "node_modules/metro-minify-uglify": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz", - "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.8.tgz", + "integrity": "sha512-6l8/bEvtVaTSuhG1FqS0+Mc8lZ3Bl4RI8SeRIifVLC21eeSDp4CEBUWSGjpFyUDfi6R5dXzYaFnSgMNyfxADiQ==", "dependencies": { "uglify-es": "^3.1.9" }, @@ -25341,9 +26156,9 @@ } }, "node_modules/metro-react-native-babel-preset": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz", - "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz", + "integrity": "sha512-Ptza08GgqzxEdK8apYsjTx2S8WDUlS2ilBlu9DR1CUcHmg4g3kOkFylZroogVAUKtpYQNYwAvdsjmrSdDNtiAg==", "dependencies": { "@babel/core": "^7.20.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0", @@ -25393,14 +26208,14 @@ } }, "node_modules/metro-react-native-babel-transformer": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz", - "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz", + "integrity": "sha512-3h+LfS1WG1PAzhq8QF0kfXjxuXetbY/lgz8vYMQhgrMMp17WM1DNJD0gjx8tOGYbpbBC1qesJ45KMS4o5TA73A==", "dependencies": { "@babel/core": "^7.20.0", "babel-preset-fbjs": "^3.4.0", "hermes-parser": "0.12.0", - "metro-react-native-babel-preset": "0.76.7", + "metro-react-native-babel-preset": "0.76.8", "nullthrows": "^1.1.1" }, "engines": { @@ -25411,17 +26226,17 @@ } }, "node_modules/metro-resolver": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz", - "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.8.tgz", + "integrity": "sha512-KccOqc10vrzS7ZhG2NSnL2dh3uVydarB7nOhjreQ7C4zyWuiW9XpLC4h47KtGQv3Rnv/NDLJYeDqaJ4/+140HQ==", "engines": { "node": ">=16" } }, "node_modules/metro-runtime": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz", - "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.8.tgz", + "integrity": "sha512-XKahvB+iuYJSCr3QqCpROli4B4zASAYpkK+j3a0CJmokxCDNbgyI4Fp88uIL6rNaZfN0Mv35S0b99SdFXIfHjg==", "dependencies": { "@babel/runtime": "^7.0.0", "react-refresh": "^0.4.0" @@ -25431,16 +26246,16 @@ } }, "node_modules/metro-source-map": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz", - "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.8.tgz", + "integrity": "sha512-Hh0ncPsHPVf6wXQSqJqB3K9Zbudht4aUtNpNXYXSxH+pteWqGAXnjtPsRAnCsCWl38wL0jYF0rJDdMajUI3BDw==", "dependencies": { "@babel/traverse": "^7.20.0", "@babel/types": "^7.20.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.76.7", + "metro-symbolicate": "0.76.8", "nullthrows": "^1.1.1", - "ob1": "0.76.7", + "ob1": "0.76.8", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -25457,12 +26272,12 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz", - "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.8.tgz", + "integrity": "sha512-LrRL3uy2VkzrIXVlxoPtqb40J6Bf1mlPNmUQewipc3qfKKFgtPHBackqDy1YL0njDsWopCKcfGtFYLn0PTUn3w==", "dependencies": { "invariant": "^2.2.4", - "metro-source-map": "0.76.7", + "metro-source-map": "0.76.8", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -25484,9 +26299,9 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz", - "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.8.tgz", + "integrity": "sha512-PlkGTQNqS51Bx4vuufSQCdSn2R2rt7korzngo+b5GCkeX5pjinPjnO2kNhQ8l+5bO0iUD/WZ9nsM2PGGKIkWFA==", "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.0", @@ -25499,21 +26314,21 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz", - "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.8.tgz", + "integrity": "sha512-mE1fxVAnJKmwwJyDtThildxxos9+DGs9+vTrx2ktSFMEVTtXS/bIv2W6hux1pqivqAfyJpTeACXHk5u2DgGvIQ==", "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.0", "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", "babel-preset-fbjs": "^3.4.0", - "metro": "0.76.7", - "metro-babel-transformer": "0.76.7", - "metro-cache": "0.76.7", - "metro-cache-key": "0.76.7", - "metro-source-map": "0.76.7", - "metro-transform-plugins": "0.76.7", + "metro": "0.76.8", + "metro-babel-transformer": "0.76.8", + "metro-cache": "0.76.8", + "metro-cache-key": "0.76.8", + "metro-source-map": "0.76.8", + "metro-transform-plugins": "0.76.8", "nullthrows": "^1.1.1" }, "engines": { @@ -26058,18 +26873,17 @@ "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==" }, "node_modules/next": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.5.3.tgz", - "integrity": "sha512-4Nt4HRLYDW/yRpJ/QR2t1v63UOMS55A38dnWv3UDOWGezuY0ZyFO1ABNbD7mulVzs9qVhgy2+ppjdsANpKP1mg==", + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/next/-/next-13.5.6.tgz", + "integrity": "sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==", "dependencies": { - "@next/env": "13.5.3", + "@next/env": "13.5.6", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", + "postcss": "8.4.31", "styled-jsx": "5.1.1", - "watchpack": "2.4.0", - "zod": "3.21.4" + "watchpack": "2.4.0" }, "bin": { "next": "dist/bin/next" @@ -26078,15 +26892,15 @@ "node": ">=16.14.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.5.3", - "@next/swc-darwin-x64": "13.5.3", - "@next/swc-linux-arm64-gnu": "13.5.3", - "@next/swc-linux-arm64-musl": "13.5.3", - "@next/swc-linux-x64-gnu": "13.5.3", - "@next/swc-linux-x64-musl": "13.5.3", - "@next/swc-win32-arm64-msvc": "13.5.3", - "@next/swc-win32-ia32-msvc": "13.5.3", - "@next/swc-win32-x64-msvc": "13.5.3" + "@next/swc-darwin-arm64": "13.5.6", + "@next/swc-darwin-x64": "13.5.6", + "@next/swc-linux-arm64-gnu": "13.5.6", + "@next/swc-linux-arm64-musl": "13.5.6", + "@next/swc-linux-x64-gnu": "13.5.6", + "@next/swc-linux-x64-musl": "13.5.6", + "@next/swc-win32-arm64-msvc": "13.5.6", + "@next/swc-win32-ia32-msvc": "13.5.6", + "@next/swc-win32-x64-msvc": "13.5.6" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -26129,29 +26943,6 @@ "next": "*" } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/nextjs-progressbar": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/nextjs-progressbar/-/nextjs-progressbar-0.0.16.tgz", @@ -26180,9 +26971,9 @@ } }, "node_modules/node-abi": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.47.0.tgz", - "integrity": "sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", "dependencies": { "semver": "^7.3.5" }, @@ -26220,9 +27011,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.13", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", - "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -26554,6 +27345,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, "node_modules/nyc/node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -26757,9 +27554,9 @@ } }, "node_modules/ob1": { - "version": "0.76.7", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz", - "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ==", + "version": "0.76.8", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.8.tgz", + "integrity": "sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g==", "engines": { "node": ">=16" } @@ -26781,9 +27578,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -26829,26 +27626,26 @@ } }, "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -26858,36 +27655,36 @@ } }, "node_modules/object.groupby": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", - "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "es-abstract": "^1.21.2", + "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1" } }, "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -27734,9 +28531,9 @@ } }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -28112,9 +28909,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", "funding": [ { "type": "individual", @@ -28466,15 +29263,15 @@ } }, "node_modules/react-devtools": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/react-devtools/-/react-devtools-4.28.0.tgz", - "integrity": "sha512-nagHAiR9ZBZtXdjMdNWSiWCee7i0gYm/hPNYTS3fmxvlfbzU3PfKlID7wdZgSoO00I2/ZzhsPfr9fccg9uk5Yw==", + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/react-devtools/-/react-devtools-4.28.4.tgz", + "integrity": "sha512-V6oLo9xmkMPCcFFpXkObp+P/xUGHl3wLHxZBDy/u1eStpBr5s12Nrl1k9LGhuhe1MRNFLUgDtNDJh9qEjowJuQ==", "dependencies": { "cross-spawn": "^5.0.1", "electron": "^23.1.2", "ip": "^1.1.4", "minimist": "^1.2.3", - "react-devtools-core": "4.28.0", + "react-devtools-core": "4.28.4", "update-notifier": "^2.1.0" }, "bin": { @@ -28482,9 +29279,9 @@ } }, "node_modules/react-devtools-core": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.0.tgz", - "integrity": "sha512-E3C3X1skWBdBzwpOUbmXG8SgH6BtsluSMe+s6rRcujNKG1DGi8uIfhdhszkgDpAsMoE55hwqRUzeXCmETDBpTg==", + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.4.tgz", + "integrity": "sha512-IUZKLv3CimeM07G3vX4H4loxVpByrzq3HvfTX7v9migalwvLs9ZY5D3S3pKR33U+GguYfBBdMMZyToFhsSE/iQ==", "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" @@ -28574,9 +29371,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.45.4", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.45.4.tgz", - "integrity": "sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ==", + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.47.0.tgz", + "integrity": "sha512-F/TroLjTICipmHeFlMrLtNLceO2xr1jU3CyiNla5zdwsGUGu2UOxxR4UyJgLlhMwLW/Wzp4cpJ7CPfgJIeKdSg==", "engines": { "node": ">=12.22.0" }, @@ -28607,20 +29404,20 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-native": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.3.tgz", - "integrity": "sha512-QqISi+JVmCssNP2FlQ4MWhlc4O/I00MRE1/GClvyZ8h/6kdsyk/sOirkYdZqX3+DrJfI3q+OnyMnsyaXIQ/5tQ==", + "version": "0.72.6", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.6.tgz", + "integrity": "sha512-RafPY2gM7mcrFySS8TL8x+TIO3q7oAlHpzEmC7Im6pmXni6n1AuufGaVh0Narbr1daxstw7yW7T9BKW5dpVc2A==", "dependencies": { "@jest/create-cache-key-function": "^29.2.1", - "@react-native-community/cli": "11.3.5", - "@react-native-community/cli-platform-android": "11.3.5", - "@react-native-community/cli-platform-ios": "11.3.5", + "@react-native-community/cli": "11.3.7", + "@react-native-community/cli-platform-android": "11.3.7", + "@react-native-community/cli-platform-ios": "11.3.7", "@react-native/assets-registry": "^0.72.0", - "@react-native/codegen": "^0.72.6", + "@react-native/codegen": "^0.72.7", "@react-native/gradle-plugin": "^0.72.11", "@react-native/js-polyfills": "^0.72.1", "@react-native/normalize-colors": "^0.72.0", - "@react-native/virtualized-lists": "^0.72.6", + "@react-native/virtualized-lists": "^0.72.8", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", @@ -28631,8 +29428,8 @@ "jest-environment-node": "^29.2.1", "jsc-android": "^250231.0.0", "memoize-one": "^5.0.0", - "metro-runtime": "0.76.7", - "metro-source-map": "0.76.7", + "metro-runtime": "0.76.8", + "metro-source-map": "0.76.8", "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", @@ -28682,9 +29479,9 @@ } }, "node_modules/react-native-confirmation-code-field": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/react-native-confirmation-code-field/-/react-native-confirmation-code-field-7.3.1.tgz", - "integrity": "sha512-5vI6BclB31e4vTYg0HmV/Vy9zI5MQZfHr1EN3kYzvaZq4GMIsyr6lrSmnQW1TtWR7Z8oURrhCpwo+JsWXxCoug==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/react-native-confirmation-code-field/-/react-native-confirmation-code-field-7.3.2.tgz", + "integrity": "sha512-uuJKxR+pQrXSx8lmRpekA+Hlle/nkoQKppS8jH7ApqY00+c11nCJg9kuFM0++vdbXg1rKm2P6jPZoSEJK2EaKw==", "peerDependencies": { "react": ">=16.4.0", "react-native": ">=0.64.0" @@ -28699,9 +29496,9 @@ } }, "node_modules/react-native-gesture-handler": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.12.1.tgz", - "integrity": "sha512-deqh36bw82CFUV9EC4tTo2PP1i9HfCOORGS3Zmv71UYhEZEHkzZv18IZNPB+2Awzj45vLIidZxGYGFxHlDSQ5A==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.13.4.tgz", + "integrity": "sha512-smpYOVbvWABpq2H+lmDnfOLCTH934aUPO1w2/pQXvm1j+M/vmGQmvgRDJOpXcks17HLtNNKXD6tcODf3aPqDfA==", "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", @@ -28796,15 +29593,10 @@ "react-native": "*" } }, - "node_modules/react-native-reanimated/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, "node_modules/react-native-redash": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-native-redash/-/react-native-redash-18.1.0.tgz", - "integrity": "sha512-bdCFl/ZB7Rf2raIlU6SLV+Dc/rL6UXsQNjEVwTGBukHMeSKp1zs4zVtWaGimbN8P22N4qYvb9Jmw/K94ZWYG0Q==", + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/react-native-redash/-/react-native-redash-18.1.1.tgz", + "integrity": "sha512-52k4VSpJO5uFFNLbZhUj1KrOUsbxF/vP4AvnTGXUVx1PyRubpPiGbtTMCFShQ2T01bAB9JRSZwX0LWfzcG55pQ==", "dependencies": { "abs-svg-path": "^0.1.1", "normalize-svg-path": "^1.0.1", @@ -28861,18 +29653,18 @@ } }, "node_modules/react-native-toast-notifications": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/react-native-toast-notifications/-/react-native-toast-notifications-3.3.1.tgz", - "integrity": "sha512-yc1Q2nOdIYvAf0GAIlmg8q42hiwpEHnLxkxJ6P+tN6jpcKZ1qzMXlgnmNdyF9cm9VOyHQexEP8952IKNAv1Olw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-native-toast-notifications/-/react-native-toast-notifications-3.4.0.tgz", + "integrity": "sha512-ZvB//jLhRiBRemtcH7vGP1maiKCikqtW4aDqo+QYvEIOcX0y3GrjxRayVAqI4oh0qJgd/26DkbM8COobj+0MEQ==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/react-native-web": { - "version": "0.19.7", - "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.7.tgz", - "integrity": "sha512-AaU4EKCrhdXaKJT3oVm3DH1LJxbA7VEe4TWKBSabGA6+b+CVH2SrCSEKc1pJjqK9iq3gxPcRWnPgrTQ6eHLRmQ==", + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.9.tgz", + "integrity": "sha512-m69arZbS6FV+BNSKE6R/NQwUX+CzxCkYM7AJlSLlS8dz3BDzlaxG8Bzqtzv/r3r1YFowhnZLBXVKIwovKDw49g==", "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-color": "^2.1.0", @@ -28909,9 +29701,9 @@ } }, "node_modules/react-native/node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", + "version": "15.0.17", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.17.tgz", + "integrity": "sha512-cj53I8GUcWJIgWVTSVe2L7NJAB5XWGdsoMosVvUgv1jEnMbAcsbaCzt1coUcyi8Sda5PgTWAooG8jNyDTD+CWA==", "dependencies": { "@types/yargs-parser": "*" } @@ -29040,9 +29832,9 @@ } }, "node_modules/react-number-format": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.0.tgz", - "integrity": "sha512-3h5kuO5x9HpifEgCzvw6kDljzjsI3OhgnT/BRzZbzdbHVb755eVzJuNnRUZr3h/ATu3Sct9O+XrYc9HrAj/6bQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.1.tgz", + "integrity": "sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ==", "dependencies": { "prop-types": "^15.7.2" }, @@ -29089,9 +29881,9 @@ } }, "node_modules/react-redux": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", - "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", + "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", "dependencies": { "@babel/runtime": "^7.12.1", "@types/hoist-non-react-statics": "^3.3.1", @@ -29497,14 +30289,14 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz", - "integrity": "sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.1", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -29521,9 +30313,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dependencies": { "regenerate": "^1.4.2" }, @@ -29545,13 +30337,13 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" }, "engines": { "node": ">= 0.4" @@ -29705,9 +30497,9 @@ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -29859,9 +30651,9 @@ } }, "node_modules/rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", + "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==" }, "node_modules/run-applescript": { "version": "5.0.0", @@ -29959,12 +30751,12 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", - "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -30019,9 +30811,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, "node_modules/saxes": { "version": "6.0.0", @@ -30269,6 +31061,33 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -30704,9 +31523,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==" }, "node_modules/split": { "version": "1.0.1", @@ -30742,9 +31561,9 @@ } }, "node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "optional": true }, "node_modules/ssh-remote-port-forward": { @@ -30783,9 +31602,9 @@ } }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -30961,6 +31780,7 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.13.tgz", "integrity": "sha512-8SCJ0Ddrpwv4T7Gwb33EmW1V9PY5lggTO+A8WjyIwxrSHDUyBw4MtF96ifn1n8H806YlxbVCoKXbbmzD6RD+cA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.12.13", @@ -31238,6 +32058,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/standard-version-expo/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, "node_modules/standard-version-expo/node_modules/crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", @@ -31521,17 +32347,18 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", "side-channel": "^1.0.4" }, "funding": { @@ -31539,13 +32366,13 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -31555,26 +32382,26 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -32245,9 +33072,9 @@ } }, "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -32502,9 +33329,9 @@ } }, "node_modules/terser": { - "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -32935,9 +33762,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", - "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "engines": { "node": ">=16.13.0" }, @@ -33256,9 +34083,9 @@ } }, "node_modules/ua-parser-js": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", - "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==", + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", + "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", "funding": [ { "type": "opencollective", @@ -33267,6 +34094,10 @@ { "type": "paypal", "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" } ], "engines": { @@ -33274,9 +34105,9 @@ } }, "node_modules/ufo": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.0.tgz", - "integrity": "sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz", + "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==" }, "node_modules/uglify-es": { "version": "3.3.9", @@ -33345,6 +34176,11 @@ "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==" + }, "node_modules/unenv": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/unenv/-/unenv-1.7.4.tgz", @@ -33551,9 +34387,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -33674,12 +34510,12 @@ "deprecated": "Please see https://github.com/lydell/urix#deprecated" }, "node_modules/url": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz", - "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==", + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", "dependencies": { "punycode": "^1.4.1", - "qs": "^6.11.0" + "qs": "^6.11.2" } }, "node_modules/url-join": { @@ -33745,9 +34581,9 @@ "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==" }, "node_modules/use-latest-callback": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz", - "integrity": "sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.7.tgz", + "integrity": "sha512-Hlrl0lskgZZpo2vIpZ4rA7qA/rAGn2PcDvDH1M47AogqMPB0qlGEdsa66AVkIUiEEDpfxA9/N6hY6MqtaNoqWA==", "peerDependencies": { "react": ">=16.8" } @@ -33807,13 +34643,13 @@ "devOptional": true }, "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" + "convert-source-map": "^2.0.0" }, "engines": { "node": ">=10.12.0" @@ -33955,9 +34791,9 @@ } }, "node_modules/webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", "dev": true, "peer": true, "dependencies": { @@ -34003,12 +34839,13 @@ } }, "node_modules/webpack-merge": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { @@ -34093,9 +34930,9 @@ } }, "node_modules/whatwg-fetch": { - "version": "3.6.17", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.17.tgz", - "integrity": "sha512-c4ghIvG6th0eudYwKZY5keb81wtFz9/WeAHAoy8+r18kcWlitUIrmGFQ2rWEl4UCKUilD3zCLHOIPheHx5ypRQ==" + "version": "3.6.19", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", + "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" }, "node_modules/whatwg-mimetype": { "version": "3.0.0", @@ -34193,12 +35030,12 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" @@ -34672,14 +35509,6 @@ "funding": { "url": "https://github.com/sponsors/isaacs" } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/package.json b/package.json index 1b100fe310..a3db823391 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "start:web": "expo start --clear --web", "playground:start": "docker-compose rm -fsv && docker-compose up", "test:ci": "jest --ci --coverage --detectOpenHandles --debug", - "cypress:open": "cypress open", + "cypress:open": "cypress open --project mobile-app", "cypress:run": "cypress run --headless --browser chrome --project mobile-app", "react-devtools:open": "react-devtools", "translation:missing": "ts-node shared/translations/reporter/index.ts" @@ -22,57 +22,58 @@ "@expo-google-fonts/ibm-plex-sans": "^0.2.3", "@expo-google-fonts/sora": "^0.2.3", "@expo/vector-icons": "^13.0.0", - "@gorhom/bottom-sheet": "^4.4.7", + "@gorhom/bottom-sheet": "^4.5.1", "@mealection/react-native-boring-avatars": "1.1.2", "@react-native-async-storage/async-storage": "1.18.2", - "@react-native-community/netinfo": "9.3.10", - "@react-native-community/slider": "4.4.2", - "@react-native-masked-view/masked-view": "0.2.9", - "@react-navigation/bottom-tabs": "^6.5.8", - "@react-navigation/native": "^6.1.7", - "@react-navigation/stack": "^6.3.17", - "@reduxjs/toolkit": "^1.9.5", + "@react-native-community/netinfo": "9.4.1", + "@react-native-community/slider": "4.4.3", + "@react-native-masked-view/masked-view": "0.3.0", + "@react-navigation/bottom-tabs": "^6.5.11", + "@react-navigation/native": "^6.1.9", + "@react-navigation/stack": "^6.3.20", + "@reduxjs/toolkit": "^1.9.7", "@shopify/flash-list": "1.4.3", - "@waveshq/standard-defichain-jellyfishsdk": "^2.2.0", - "@waveshq/walletkit-core": "^1.3.5", - "@waveshq/walletkit-ui": "^1.3.5", - "bignumber.js": "^9.1.1", + "@waveshq/standard-defichain-jellyfishsdk": "^2.20.0", + "@waveshq/walletkit-core": "^1.3.7", + "@waveshq/walletkit-ui": "^1.3.7", + "bignumber.js": "^9.1.2", "buffer": "^6.0.3", "classnames": "^2.3.2", - "dayjs": "^1.11.9", - "expo": "^49.0.7", + "dayjs": "^1.11.10", + "ethers": "^5.7.2", + "expo": "^49.0.16", "expo-asset": "~8.10.1", "expo-barcode-scanner": "~12.5.3", "expo-checkbox": "~2.4.0", "expo-clipboard": "~4.3.1", "expo-constants": "~14.4.2", - "expo-crypto": "~12.4.1", - "expo-file-system": "~15.4.3", + "expo-crypto": "~12.6.0", + "expo-file-system": "~15.4.4", "expo-font": "~11.4.0", - "expo-image": "~1.3.2", + "expo-image": "~1.3.4", "expo-linear-gradient": "~12.3.0", "expo-linking": "~5.0.2", - "expo-local-authentication": "~13.4.1", - "expo-localization": "~14.3.0", - "expo-secure-store": "~12.3.1", - "expo-splash-screen": "~0.20.5", - "expo-status-bar": "~1.6.0", - "expo-updates": "~0.18.11", - "expo-web-browser": "~12.3.2", + "expo-local-authentication": "~13.6.0", + "expo-localization": "~14.5.0", + "expo-secure-store": "~12.5.0", + "expo-splash-screen": "~0.22.0", + "expo-status-bar": "~1.7.1", + "expo-updates": "~0.18.16", + "expo-web-browser": "~12.5.0", "i18n-js": "^3.9.2", "install": "^0.13.0", "lodash": "^4.17.21", "lru-cache": "^7.18.3", "react": "18.2.0", "react-content-loader": "^6.2.1", - "react-devtools": "^4.28.0", + "react-devtools": "^4.28.4", "react-dom": "18.2.0", - "react-hook-form": "^7.45.4", - "react-native": "0.72.3", + "react-hook-form": "^7.47.0", + "react-native": "0.72.6", "react-native-circular-progress-indicator": "^4.4.2", "react-native-collapsible": "^1.6.1", - "react-native-confirmation-code-field": "^7.3.1", - "react-native-gesture-handler": "~2.12.1", + "react-native-confirmation-code-field": "^7.3.2", + "react-native-gesture-handler": "~2.13.4", "react-native-get-random-values": "~1.9.0", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-popover-view": "^5.1.8", @@ -82,12 +83,12 @@ "react-native-screens": "~3.22.1", "react-native-svg": "13.9.0", "react-native-swiper-flatlist": "^3.2.3", - "react-native-toast-notifications": "^3.3.1", - "react-native-web": "~0.19.7", - "react-number-format": "^5.3.0", + "react-native-toast-notifications": "^3.4.0", + "react-native-web": "~0.19.9", + "react-number-format": "^5.3.1", "react-overlays": "^5.2.1", "react-qr-code": "^2.0.12", - "react-redux": "^8.1.2", + "react-redux": "^8.1.3", "semver": "^7.5.4", "smart-buffer": "^4.2.0", "stream-browserify": "^3.0.0", @@ -95,51 +96,51 @@ "tailwindcss": "^2.2.19" }, "devDependencies": { - "@babel/core": "^7.22.10", + "@babel/core": "^7.23.2", "@babel/plugin-transform-private-methods": "^7.22.5", - "@cypress/code-coverage": "^3.11.0", + "@cypress/code-coverage": "^3.12.5", "@expo/metro-config": "0.10.7", "@testing-library/cypress": "^8.0.7", "@testing-library/react-native": "^11.5.4", - "@types/find-in-files": "^0.5.1", - "@types/i18n-js": "^3.8.4", - "@types/jest": "^29.5.3", - "@types/lodash": "^4.14.195", - "@types/randomcolor": "^0.5.7", - "@types/react-native": "~0.72.2", - "@types/react-native-loading-spinner-overlay": "^0.5.3", - "@types/react-test-renderer": "^18.0.0", - "@types/semver": "^7.5.0", + "@types/find-in-files": "^0.5.2", + "@types/i18n-js": "^3.8.7", + "@types/jest": "^29.5.6", + "@types/lodash": "^4.14.200", + "@types/randomcolor": "^0.5.8", + "@types/react-native": "~0.72.5", + "@types/react-native-loading-spinner-overlay": "^0.5.4", + "@types/react-test-renderer": "^18.0.5", + "@types/semver": "^7.5.4", "babel-plugin-istanbul": "^6.1.1", "babel-plugin-transform-remove-console": "^6.9.4", "colors": "1.4.0", "cypress": "^10.11.0", - "cypress-image-diff-js": "^1.27.3", - "eslint": "^8.47.0", + "cypress-image-diff-js": "^1.31.0", + "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-node": "^4.1.0", "eslint-config-prettier": "^9.0.0", - "eslint-plugin-cypress": "^2.14.0", - "eslint-plugin-jest": "27.2.3", - "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-jest": "27.4.3", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-native": "^4.0.0", + "eslint-plugin-react-native": "^4.1.0", "find-in-files": "^0.5.0", "husky": "^8.0.3", - "jest": "^29.6.3", + "jest": "^29.7.0", "jest-expo": "^49.0.0", - "lint-staged": "^14.0.0", + "lint-staged": "^14.0.1", "randomcolor": "^0.6.2", "react-dev-utils": "^12.0.1", "react-test-renderer": "18.1.0", "standard-version": "^9.5.0", "standard-version-expo": "^1.0.3", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "wait-on": "^6.0.1", - "webpack-merge": "^5.9.0" + "webpack-merge": "^5.10.0" }, "standard-version": { "skip": { diff --git a/shared/assets/images/onboarding/welcome-screen-e-dark.png b/shared/assets/images/onboarding/welcome-screen-e-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4d64db7d62cab30d028cc3a549b6a5f2a392803e GIT binary patch literal 13761 zcmX9_cRX9)`?sP-sG31rdy~diRja5G)ZQdS%&JvX6)}Rus8L&oz4r*JX6(HcwMtvF zs?_$&=llEPzV7Rud(Ly7=iGCi=lzTu^Gxq44HX*|5fKrMmZq8^5fO1Z;i94-C$v0x z_v9YoM(L?(;X_2k%=h0#tYygio6tz?WB62+sB-k~FTw+vlZvhi5m8M7^(7oYL?msh zrKVyWK)jdp=B@E&+mDbRzPBYgNgtClGUhuSjPQSnT=OUo^;oZt!CXWsFFQj`gn=JT z{_T4J=#EnxV*aLEIaX+gPA_YhG9on_P2;}Ne{SG&-Je7xf0SK-@D__N&^!+3Dx6UuiyiAJTq2yt*)!e)CgN@(TJP?cnJ3oBEL~*(zCGpNIG?uESI1 zse0nWCR$c>;?R$yC(oZhf5I-~4&p|8btda8X6W(K3wbFP_}b`WkA&i$AI_>`9^O{E z{B39tisHr7H0db#8$sz<0`)F+Ee?a8S)Y;)AiP7>BMy`M?!Oi_+iNR&A6QDA`y|rM zl?(s#t39ZRSIaBnEs#=Wf$#ml80yz7SV{)I1jX~8p#fbEX;)vT^p%#yM#q@!kNggQ za-&`7Qy9~8i+3ZcDUu)S0C~g{6#i(MDy*qkHM*m8Dy*_w%c3jT`L_glAfm$1yL8Nc zdJ4xIaBSTCH{Q`5DRJoVTU!{N(H)jGy*tLsgZmHo^-?gp6LGUVjb?Ycd&n{X{36Jg zZSED2k%DO|49{2~#K4Ron@#eqglToT1) z3&($_^qnHc-MP^Qp_-!UxihuI&jm1*L}>V3PW$8xHSURlSzsQC0R^x;RefD`K^xeO zBTtrqANzMTKne20sfT46EkV5;un`ctCc1)E!&LPS2-njyrOgH2iGhPwln*4=?kGoX z5Zi+WD6Cx9WbV&@%u`!&W%!WU+^{bIzSzdIazxx4$--jal0!*!ZN zK;03y)HDKUOc}a0m7kH+G2r2%U?77cK5X-yvH8F|ICr-{N=T-7mkSN&CKcE3hR|I) zB@$X+pccp(azN;qyNL9feu%+(QOE9gDFix^IyyFbz?~BvL)1=&3|+Pd@(4r^R1>ke|`R>s^p-&d)SE z&Hk(m%G8vRb|4L|XIZAZHoX~+(A5B@bkQOn$=J+}oeq@{exNlqRJ?esLJ*_@ z$IM(WM#D*Zuz;x{F9K-}af4w`1vDkS83~VG@Adj{6dZ(CQRsyLPc$H?HFFq7XdwIP z7(`sP$FQ!aWC*G(#|#pmTIj75N5^nz+VGDGJCJlFc60>Zk<6*+fk1ad%b?a9yE(9+ zzQm4?ACm~{Am+^1O&rquBAWu5N-fOFf9=`v;V`R(q+9v{aOy52>9vJD=tHp(L{n$0 zL$O=x_L5h|VR9x34-~0qhe+oSs{r-tyHY|M18T*AQ)(1r0DVzbyJBHTP?9**$8dMH z^QAbn+n5oQFXF8OLc7?iiK5xz5;R5zFu9X1$cU~)#`iAQLbxzhtX%VX3_QIMFmu(@ z8C<9$ObJajN@hi`$%#%0CX=D{h0*ZP%AKF9ot?qGlF4Km*~SFc3V#W;43I~|6%4_U z-TMw8_9A`-`y(abp-Iqd&CjV%G8+RFDcmaC z+8*oBcWxvw&-5KI;|Bhm1#yVS-l}(c|EkbVp{gsSC$jG6#8ZyA94%4s$@D^<(_D;` zXnBhF*~Y`e{>J+Hzj`_H(ogSnZ2UNU8iRYf%cQ?NAAGtNB~8#fDJ}izb$&2TJeu_f z^C5_Fk<~lIhsfpdC+od?kAt>`GrlAyCQ3z;C9H7kDqI&o)C6vzyij*o#uYJl(!DV3 z-D~URQx81z=0!XhA2UJ}t}(w)d6a{0eZJ4Q5o1WruOm)er?r%`b5;& z$I#WoIbH&_XIlKp*;>5;xyG;*rI^)8y1MQ*#WDG^H?!wcMfx0|yLbQY@%L=_A6qC~ zzg2FLcu+JP0Jny%Lv-$V#2vyAplEERNTTLvRmIK?|62)43hP^{PF~pDro~#x+eY3)+=C!OAd4iIqb-a@Cd>DMm zo^seB;c+StUfIklsoURHuT-uv^Ybm>q%X#64igQ<83Dl z2Qp%Cpr%Ab^nt{VuigFj8>y+&ZjC?d#u}=kC~+WtezD7V@C}VzJo`Ytsg>yT|X!O@8;gh?R9!3q!&zt|RM~826ZnT9nn)i1> zxBtH5$-w{bnrK0mBFEf5TZxBaP#E6^1aIN|ou!cOm+gZ({rl}oQah*Js&g;*e-Go3 z3c9a+eWi3U5yiTk0hgm|hf!3wPFeM1sewV|!Y90CY7?8)^3j#`=4sXn zGGxDIR}ami`ZyHr|1@WVdPx}q6Zw({m>3!8q#`d=tcM>B2tali+v^xq;8dXdH;91C zHKSqh9zXi9gA5h32nD!&ShwH5^W|7?N$~TqCRTFP_VAHBWCu7^(D|QciUau*_)4H^(Y7Hw7Mx}I3ws?9fU_FrZcUti25o~bw#|D=(&;~0zae%05g*@b&!1Hg zy>|E%yS?#(3@VRbQ3Y;9dZV;ru(v#FgE2yQy#@wn_a-{;+YR+Te>02m)cd;LS9{a5_5D-%Me<%-2Fe*wV zA`rPX&-FXqkQ$A-W3e8HqM;eAJm<8>A>F+0)zQ}d^?B+I$#^m}4vdDc)3$c8u6PMU zs_oBlPg%QrZo}K$*IQWlDeh7O^^|E(C83`MPwo!Ub(4iUporJitj8)P&@s2|Cvj;Y zeokx3*kjUNVFKljN^yQ?YieNYAV}lQymW5_$_+*A`R?)2u;gdZoo+#jo=6)9C@6qF zo!hE84%l5BMVBVF%jVGa@eWE0&fIedLK{TcFF69lp%hZw5K{#L3T#&;D2N14x2g>s zH3L5lB{b1PTx8u;f`Gxgrb2_mtYYA*J-1OcVb_p00_^%FNPfI9)e#Z@fP@qlSl17U zwVr2nxI68X+aZf079|Y3EeeKCp9(`l)zR?WD12lh@d|*P0ED2voFB*5yZV(mNl48R zApW57*i^#X$PO}cWyJeeTN!3JP%=F1)=O|^p^EisphG_AGn7!R>Tofwrxh!jGTvT{ zZLS$&cn94v&vbJOvlA={++aw@Q4Rr2hXVftf$A_!evkTipUDkDb>Rbsh-(&ffjnGV zR2lX&H&ixrX&&>{Tu%u=lSEv%d?3P2OCcJL;Db^lvvY@bAx;_Mv5(x#B5mwrsUkc& zQw*Vw`**V1*kwI-1<-I|L(%LWd9cX5E8LjN5Jij+deejSVDYH4^~(|;cEs#gzg(|* zKb62b6Wyb3O6hg@mvI^SCVO%iV!G{>K$qHG{nx@8#1yj>CR8LS^>}@K+X;(yk-;$Q zB+Og)&78(=YYISQ3RHQ(xSap6e=3N-uv#QGhG&v0mL@`DN{T{P@3P6vT-u`1H60gP z4)F?pV%}n5o{r;c>zJP(AnGbr87r_^&s`GhL8j4VaoK|+LyMz*{F~=@Yt$npyVK=z zV>?n%#v@Fs?&lHnh{*X}#zoTqJQ5=DSVYGa->AO1aFdaNvH7!fr1FKO@HeM(z!e3} z&cQf9p1Uz&BHb?&?EKVO?U7}Gox54?NcM}z`qDoPCbPM&L+&-O&Ka_g6qWQUWO^*A zd2L0#HqLo1moKd=^_*)W1+Wgo?nOX&Em;`vpIp4drHd$rD5r1;E7;Lh*_?m;{p~EA z(WxH)Dh|}kRnvl1hU#s<{^`DMqhmbkdhpiFeXWFF8P@WOr-5D8P`F)9VTJDXgaLE3 z`u6=?k(M3@xQaR3nN7jiyU_k@h6Krro)hI=^(c7hr+R>7Va})In8#8n^Dii=uQ~Xt z139JY{tOj&<4nvIjx9`*(4IFHW1(ZzRwG6s5urcho*SBjv*vT9A?3 zdkcNA{`6~0RiZ>^iMLfyxhGAY^O_Yx^EFL#T-jRfDJzOq`!buhDd=gSK}qlKrA?}% zq!~p#6~QUoQ-y9l2DcX*J9zqc);?@VHs-7(sZ*3pmrv$k3R7*$Dr{6WXEP{@{UJ5N z7?!v9KFN6?SZOMe2asq9gH_zsQWUvAroMmuhZ;Arl~7r*(7SACC2dFzEPq$lt|Ik= zeWJDfk|cFFYK1B6sC3#?H=C@GQ`q5gm$n6XKWv#-ysIshX?8?!rbj~?6_ZzOZ0~Wc zxP5n7uwYzM2;#+mgi$q-fXZs5s_G{L6PTzQ9%L1zOSxnhoXBwa$u^^cO^B?}LNqndH(pWg zsPBILwnwf870QJfTX6qrWPcFvl9R)PY{fHOn7y#5qw|w$SIhcT+l2^zZ`8w#pq${9 z+7e`&mLv*96T!cY2<->GEN%0_{urK__Klc@Hb(J8 zieZB_+Kce$I;pxx!<3%y7Ch>zW7J@)RIMk6TYgawiN#!3WuDAh^!JNGD88|y7oN^g z-_N2E(Wu*4G&?p@ix7s;rL5Ff!prb{2Ii8Vs0h<0-}IYet+=a^2u2XD8$D8^DAmD- zq&H|8QMHm_jZC_k^b^2hZ^a7)tF^mcN#xA5{WDEwX4L-nSBIJ9!SJ>G#IX|iubG?S zZ17PY6ZfolI=(=@E8=G}B6i>AsDj}!qr@k3h-b`|hc-IB7c~T&g^owqcXseKerz_J zBqaq)noAP%U;z$*!;u=@_5J4epuV4(jW3}(Cnrwws#;pWrLeQB6kSoUVi+4&P|+YM z9PV{^dz!*#?(WKu6$JT|Q|tt(D0pAI$G;GJK)b>fsSG0t4;X5PwoR2jhhG9#guYnu zCG*m~Xg<4PE@$br+X~M6z1%COWxux}U}_`LOG|g_4?CBbHS$)MX9j>9qN$?sxghb_ zJpJoxE8agyMM--wlo8QmRVe*pnA7w3^7^BA_!Zq`LZniAd(2eA6|XwmF_TdXDZ$G} z;Vw(}Y{A(;;+Mri zjFIjO`I&`vF7eDw$jd`VyQ%ayG=J)FYNV5CD;G&sF2nF!XVgOdc~!;J>3^;Z_VODt z{$9E{X)%qv@>l6v?D_v*k)=lC`Q-B(5$4vpPYw^h(X%-CR%x$$j|e3B4izo_)WH@_ z7EOxfQ<;+raDCaif0&b;aLNr41yAr4^jG855_0=s*48ApT9YqKSKc%m?3o?B*Aqq^ ze0`DVVh(#d(6i2cOOCwV!-nUnAFD)$x%GFVzSWiMJc$LzQp}J|lQkS~=e{+jHF*zP zl&F0wCP70z{Mu-?4yQ?0JLC!FF7kPV#X>n-fx2o;9j+I-={RL`#Sovx{J8@Q`8Z?& zeLj6^e>9HeO!*0k56)3C2l`nr)_OI4bzY4eb6shz7mI*VM!0R-);}L9Otvz1zwrLy zR5UR?JJ4i=NM5c=F9UM!H_Q$$xdF#Wd=$>|3awrl@_D)|GWH4jA}f-v`Ddq*riKa>gGt+zfn5wDiNs+ z8$e1HZxQ2nWd=VCM{}B{6Y9z>7Al`ThYBH)&kuygBf^4t7&gMWq_3iaYc`1y9|#}L6o5YASv zxQdqI+>W75gn`w;nXk(Jf`x+G{()YzLrfs?4fm}0pCpSdZCG_7b)U^N>4@(QLyZ`9e%Ds5%DXRbXHJ534&e<9Y)o4aZ{I!6BNr$j{?B>NY+ zQ}mjU%MRHUCteR46ZL_)%`%w$4eB=)NiODwy;t-oJFgd8zG|wEZ*x$8Za!n}Bk|!q z6K(BfB<};$nX!J|uXBUic3d1@_cvoN?@WnoRK+i ztGKpOyvHV+?4*p?%i_yls)9^->Ravfv}YW3lLMpiWc$!?#Fqb{$AUn2Zhc+RxY?BiLD)qYd8U@>gm!~UQ`l;!N=d!1C?a8OHsY) zw-I`NN@*E66-_T}SXilqn=O?Tf!h~Xl&5(gCDvWvPz<4I*o*V>!X+|dAFNN-591zx z4sFk^6#v~cqht6)V^{*q1zNhxVE(nX<;yHHoBsITc8arKF)V|q9&p|BXz>Mn9}azXEB?2;ll8Hq^y$8}MRJ+8UcfJZ;Is(Dw`)(MHNF9}uFhm|p zIP?O);=Fj;u1*$xcjv`-4tv>OjHilOIbUC%^_<>{uP8EyM$A%6bVC*ssOi$KuY=v# zXVV$E!yVX_MagHerKqdG5m9!)OL1YDZqa9pn37C&zkI%>_2!HH)`Y;Ml#XrLUoiZEUakeIP1+suiIEB5#VB^FjUjN%~Ff8C9 zeI61tDkx(4KzmYi1Z(tcZRMg(MLwjH7hheG4lR&vs45uN3b|w1by<3BONG6~5i~wX z;!T3ARysEzd;Zg5(9R|(!|;qR+4g4bJ(bUG1e?vx7$bm=ne5mtQLo5lx#eXlwXU?6 z5Wpe98u5*ZMDp{C$)T_7pLaru%hPnWeiBP)H7~u8s`H(CG0ZO=WnK6B;9;Qj>-UU^ z{&6e$3(0%QVYy5;h(3k~2Id{d$Ky{%t;UUOy+H>bpM*P*0Ey;E``VastQ>Nlp|e$X zRrNR`p(RH}%hI$zdCS5W>>@HXF4tRf*tI5Ii-dIL@{o?DGz^Ek1KhpnAiYiZ-x_&M z=K;T*E!Y(m7n^L53;`sA7qC1z(OBK@+@x+ZRreh+vu&d7VoUN&4Owv49pN^4Ef{(D zZi^L)-2;bO3JajwxJ{QvfQ>r`Ao$#JV1=E`^RJ8|UNtesh-&0;d9MJYTl*`jkvmiQ zAd20U=>=_gIP4}@KkBAg@vZ91kTYyD8UL=M-;0)C{NB_~DQ80^`QdsrcPt+qdsNpJ ziM_tVlBKC$*d3)uLuoX6oZ&X^EIFjne6uf-QXVI+>yuOgdW^^k5BXXlau$r(9r}#26^4hlB{O3Z!B}7&`*_G3M3&4Lbev z4Evbj+V1?rf8+5i_fBtyV5q|nnI5$i%MPXMMYwr2ZV4LPfK*P3Pr}*4aIL|YQdner z;SPgdx)%zC<)!*J?=$xJsne*Ooy(nz+|{JRv{DZVve!;(Zk@#%bnEsEE&Tz$$xI^u zTD7?7<`X8RP2({mkfCM72H|ME1}a0|0=}mZaz+GHyc8-)f&TkJKR6MOXHvmnb$@bi zbgGwTz82l?2$nW>N0iS{pVitrc&pr!iaN zA*?gKkQM%c-G6ENA>TNGdRSmvc70dku4z2|HEo z?@tas1Z;HEu%?CzE6Z_W8swQ*A1?*u){mo){rP+0bRnH=Tu|LhMi%xGwJl6!GM{4TMY2+QrFmpXseq3{9E}cabbA7;BQ{%ZAt{u@nyNf487xpd>$X>JoAk*a zfYo^%M)w~PWa*I)*9QT|au%t&lnH55T33htU#0@9RX?PMFhUfu{Qh4bEFtW!|D*}T z0KxNoI;n4m31pt*rjs0Z3it`%Ax?^W!@l;@yVF%i{@wqMqp>8^rb!Q^1Jm&RhmVJo z{$mx*_>(>yfA3Mg$Gtqus)o84{|7e$U5<&4w?<^cnOWFnxf$le+^4KTe1(M(0EP%0 zZxNktdy=#N$=%IsDUIMB_L@y3n`4?I!(H1zpQP|2%1mCCMJdQwNiYbsEth=ObejvtZIKJUL=DCt|N zN=msu%OhC3Pcr1F;CmKN@-mOK16hmfeI+K}?1*VI0ZNZ8yU$>bNnGKgtm7lX8piY) zoIUu$q<%6mxMS@M7W>O3Df>ZCVNGTlbzUK#s3ek!Ok-;21{eWQB`qW0uhWPi_X6dE zhxEcMTmDjKW||!0LQOR7Ol#&c`5?4T<-=-;l!n&s+Uop_UNu_NH$WqHo#Y-V`uU~} z5uYu$_{f606x2&j)y|w!A#&Sddg1Fj3#8Y`U?B6biy;%!WSU*ba;K#TU;nt3XZs_}r{$JP8@WZVqf+V5jZngd&ZX7X43+9}K^ zxM!Ck(f!-Td{Cv)!XF}CNvI|%(=_+QVawuda$8k%l7^0xrF7IT${y)Q<|6+ zl9FNlq2}G{5RM37`>je5+~&#df>F~8HtUxjRHA!@A2jXXk}!jM846Pb;-`?Qbg8p0 zkxx4TTb;MJ?mW^^QMxWK8?)2p{^0yR@K}*@f2@z5|@SXv( z=)ubCgEnb(a@AVDJGvgZ zSZ-5 z-BvZGC8Oi+frT z9w`VOg^LGdo}~UsUw~WzMcv%TVG zJ459o+|R+O5<>hiY7&|1w|f6r#3*v>C#L>b7#}~S>}-2;c6Jz;dFGR3NPg+C!7bu= zb$*;&PPu5Q!nvaFRf5h^p9Y~1IVgsHyzrO-_76 z+TNyFg#N=zT~h}m^4O+WN-KKs1kpvu(t{ZHeT$ET=WZx{Blt{XGh(tJGJf#7VZ06Q z>`#`H%RrZDQcQaAW|{+s!P56cpcsVMa*F~pEzV1sAL@lRGz!Er0}3K zl!JM7sg7Jv6pn*mLe1`zqmsK`)+ZH7($=0DsUmZAK(u z)p|Uc*G`$Oi&&%}6%hLG*^%LkS8IYhvq zTgOEH6Y7&5FJflqvfjkoeWFbn!iTK5?rR0}=sL}9+N=mTThVd;!*EOJE9-}zZ<<}` zV@L+Qxw;Oj#c~LH@?CDO;Sgw{^DOk%W)uknYxK}$flkF!bMCspV^_;&?}8NUq!6n6 zNM(tlK>W?kdM0z(crA1En8LEG+KYW9eF^(Mi&ff3j|^?hci$u4Sq`XajtbYi7wkBv z&?W+vt(SVh)elO4CW@PW13Yv!9_DqE)loZ~y!EBZ)dfrap1855Q0r~QJ{S1v>T0&J z&6XMiV`a&H^wU{(M9RCCG5fB3&;WhL&3S{!uQFa4^K$^r>I|#P9&_fDF5@- z&s$_}NCbA=Bi|{tMS|2euUo4=k{;O9Qi(aLNJe6T?0aYIn#|)a^J1RrotCJMenxXM z@%|5@4aj@njI#~FV3@PB;4_^XNW^RpGQ^Dz&PZx>#Z^bH`&_PlSvqYVFLKj? zpVi}pFj?=5#1cNR3|)r1j7}`+=&nz_RS439a3=Ia?&mElwSKmxGHvXc9I!iu?rptQ z3U=#h@rp{E4cfBi8V&nlxm1G?zG|W|vlKgj{%nQE=tey2df0^26j;dfK);dUJgRw* z1$|0A>!|Y2{`Ij|)+D~Ii+{Typ$*a*<`rP%rD|tqXF}cE%bcO%AfeX-;G~^eUe=8z z)yQtuk)9-nN_5*Owa_Y^9aAh%FSz0nM55`NO*SeYZlG4nr@$p-@u#z~E~b~ucS9~n zc}Bx5Qv);L)yA{s?nM?QF{v!}U{IF3Gn<8^`cN2Z#U?dX{K1z~?qt>DY7fPrt6deSC4q+GDC0Y^}5h3L`NC-QQdf^ZNWd)7p!L{gB0m z8N`WY+VJ}Y+oj$qU^A%1=YExkOpQ>v%s2(B2H&YC#IVSEUik-p$|yAU0%avc9jPLO zSF8x((4a!!t8{Hn#i@(71hJ+R7VX8>X-vkvOP^=df>)}yZMD7HpXOdssoEuu4U%Mu z?{pvvbQYsweQ(t!MwO$s*q+Paud-VNCK<@FjNlYZgnLoGh5P>qO@tIwIA7g_urck| zZi5RRDLop&j468(P=kv=s()@ye@JT6>z3+*Xs731fK6KY4`^MiT`SZ+Iuc0q4?5g}Lq7 z%Sw-)hR92s9=}<9PLA!>vOH2!2x%!?9QHWyUUzVE>5FcFx=pzSRdP8lIo^%)rugmP zb6FL7(DsC0gj`wfKd)d%BQ6%gZZ1-7sravX%;Ml7{NiMfQKn(ZPa^D8C(D4VnZyh9 zp#rq3foOcbNSKM2hOo92>ksa)dltH!D@h(EetGQV{M~-foT>*;-~hE^TRQL8tM{mq z#R>JueFSqt>C!h7dK@t$a46`UTve*fmg;^~O^714(R zOL7Zc79ne1Ne_Yc8udb3Ka0F-oK#13(?BHB)j~YkMm;Gk0EmI4t;n?PfALIPPVp$X zIm)^dc*Qc~@F05Z^9S|@Yb#Az#mDZmzL6^C`{ojHU+Qrcg?K|uxzIp?bBp3Wcg}CK zm!OH`Jt{VH#!Vf;Tf`CS_$)$P>UCK=Ybd~BV>;=O3ab;I{Z-2rLN7My&#b=v=TrCS zI>Snr{NR9uJQ!r!KQsi22UEEFJDA4K2BpxJNlf2VbZ#q3a}MMuFX zH#ybG*S!zg{w29WnfiiS4Dw7VNH&aGy!pcDS(($wJH`LagNv1>#PeNJ_y%6V557-t zTFxJ4%nTuCeX~p)uCoy{^&6JvUTJOgeKwfY^fcy0y`<4hNeg^U+A~^J#P8M`OaTV} z&L{isk&)6z&O<8%f`z3gHU9^~p>IhFSh4{jsz8($falf=M}^|oC1w0xr^QxVZsRS4 z4K#V*E=rR_o>#ma|yE2**1n~P1&T_k01-km?XcLN5**>UHE;id;; zt*T+fS}NhmR6G-3^{GM$+}6CaoPX}*+B_oM;O|Ac4mNMs0BA2ez>+%pQ+1ii=pr8N zH6Pw61vsJ{ZiYTlApD8==FrjW!a;rvW814P;%K^JeK8=ol@ZHSbm3O{6191& zBcVWK_N#>R+gAj)H?Haj3Gvwm$Bpx`^plG;!B)~!%CHL^jc=u=-){diZicj6a~QZ~ zc6~I(-gq0|Nec`aJ3rp3*zDo~qz-l1nFi@tWzY5Vxyj^!7^kc#jq4PnD>y?}1WO)H zLyF5(w$kaHQx+#)n>d{fnQStlR=UMpnW$w*$VgLTt=u#m<)7v}(0xpcY@AcngRj=> z@dLeF^7U>VroOp2nV7Ax+SzaQSeD0RJFM{AiH|&Ar_Jx7&ou`yR3Nq+{@l)#{g+V8 z16Iz%q`I1*RH|>B|2$-ynf_2BnT$G?=!<(jOx}52*1mROI5<-*AOVljadHv>(Dd*X z2Xgjx1U~##aZ^veb6=;q?2B!zg5tA^Bp${j?u?0Km4hU2uy|Uue|bps?u^GK>eL5gkfCJY$%X8KG%HC4kPzG=`apmk!E;ZoeKKb z;fiA7kJ}{q->7=~&y7i5L-A&#f{nyYrDpML}5F4WFLc>6Xb|5vbc!~na8;wCUc{WYGJuMBrgY+ zy!u{X%jUW`<}!pKnKS3S$99dYsWycg#sH1=I|d=Tk+p$KM04{so*OPLg%vVTp9ex@ zrk$5VZiVC0b)U_)%v8^3gvtyG_6zRz#e8$#7$XjOiEwN!=d#^yP-+}zdeJU%Av$u>47^jxbP|1{FQdi>|iA5xq~jZ-8a zX3*IAty{uYg-_ONcz+!)ndb5tQaGYb=Zr_VBGtY|Flm>B-#6RU$XlP z6|4bnmw&v$?`2!?6U&j)r9BHfKklHRNd-Eks*k0!g(VDn#tl3FDSR9@y~%PyJGXpb z0~5G)pCVc^u_mG{!YAu)!wqzAussp92u!HtEcn6Lj)cPt;+)3;vEBbczr zYO~IAw0D^iiSFXezn*OL1?yQOf*lL>onH@g;Jha)F#*R?$D>rgH>AE(MUZQ9JqxuE zddXT@!*Wu*$=2=v!rAFfiNT+jy3d$1ekWR5yPG4ro*H-&_lq)c*BSFA)|hpQCiE50 zQjxE`vVHVJ$f2D6%LDllZif5X(O4QRG(b=kEF+8ons$ml=Q|?gMc-jsPsP9;{wQMH z+Oqc=%_x|fE~u%=I>?B|tEQ9YVBG0ptElFGd0bO-Yj-dFl3@wJPZg5>pt$2aF0P5|rp&D#Bt#U%ZY(z?D^3Dje;A->p5TWb!;BDPmixUj!;GtF&`~>*CwE-r;W_djMp@5F$XxhtDZ% z-y9V~)mN&6UP{m&iZMC_|EBu~J|YcD2r*~4I88N4h9`MHzb;UlLiZ0>dDM>GbFpxM z(O~9_oS%25zU#V=Osn8}>Oa>6UaZ*NbJegdCa_@MmBv6M>|iBk5Tlb1qqNf_Dvo{L z@Y|bWWB2sLV7*&q%^oq9!VnwY(}^=0XAy zt&Z$WArV1#A`kJRMTO*HBxUMhK=B39bi?^fp(j0-zPeUd)=0lpZdEE&&BJ&9U)k|% z2}#F{SQtRmXmUYh2+o0SUGvB;lPX`WIf5CK^dnrQT zQ?Arf+8O##pX}gA!sCx>pYo?k97uJxzV=0~2C3MTk>e9N-Zas5n0~Z<8Ldw|wcATq|CX!RQF4oa>Il+|`u1x_Iik>o0cpaUTq;Jf{ z8(xJ;epTen3NNLC3b{!ZnNqkR-??OpXsV2-8&1`K6Ab^SXP^huuEA^Y50T^Z>yCzc zHo#?ahBJ-eK}y1An(s#}aFPOZC2+0J?v^-PrO8pm#yy{LmZz-wf4gP{aPQmDs4%J@}50h3(M@nsKs1O~f$NejQ0~4t> z#cU|3{A~0xANC1&fYoIflq1ZThS#w2NLpZOW~YfvMC?n@e0Aa--80lO){cqmNRi}U za&kKMFaH7G8$UgX_M4{XkyTc+bk>;Q&JcS4;-gNiKrKnlopkS2#qfS!%viu` z!z^IG;$F1IwG<&`9l4bgps1wm`zw52=6!5gN6HawOU+DC-=+}hx0BiUY>AIhdWE4b zqoEMlTxDciJidBs*-S=5R+yFfmg`)Irr~Px>nNXWLi>9*E2vOQMfIDtI{S+iBgsGA zbC$(IS}_}sudtDOuU0-^o-dTkxddA-UH=$b)I~QUM0Iqj)cQCdi-~5}yL_K&Nu{f! zXE6Hf>y_sFj$>qvgNu9Jf?Zb^iewX}BOJ`qBu)SeS2*6H=(k-c^bhC7~bW3-$Gz&po}0K^Rc z6(l9i_os+XBzH{(X~6d>%6&uw#YRe13IM2&$9gnF1ps*Clw_r}y^xM_9iWuIQa7fL z@(L8ivhf+_Fe!-=6|Y~fbI3}w7(>T>(|xL(jl-jgv_5IxxaDF2al*n-c}TE~!Z-5!+n;&7>|0qC zKAGpQt)us|yY=78tE{ygJGWyGvFDqdm-au=uc^HtYUuU(4XQHYU{*p*hZ^0gclk$G zS6A{C+VU%bE%3uYu(<$trcAoz&ieJD0 z#GXxQ__ytU5F%rp7?F|{pgqWV55y&ch=P4;hTobx?g)u-y?nw0kik%b>UUASWPMm- z6a#|TXIS{b#EVZ>bh+}kue*|KG%k7iYm&`jW z%)$&svqZ{88BSvf4nrVYEf3hCM8_FLM%7f8k>|jgw01u~8=R+p;tS#!5zzG~8wY?prV)uTrFSU}-S} zuuJkhFz53m9)Om=?Ix3u?AWDC9$+g^j%;zkKEca^1mNB-fiouZyy{3S?;9n^v(Zad zj6zBf&EW|d1>`DfLfQfr3GXA25~$gE;*1U_y+hS zMJ|g+%6~NzjSL7m(|zE=17P4ALIgjcZJ+`!5-S>5`{R)?@O2^f>+shAh~VMKsE0rU z9xe9(I(GW|qB!b6?6d!IRmlYHJ7g?q&OZCQ4``Ctr^@LXI%wuh<$a58rHzV!KzM%z z&$TW_UxH4f#C;|pzu^EN!PLv_0}_x<3>9q#3vg#`Vety9s(r~Lk(n@I3_xEm2T7oQ1ppo#9IW=gvX+R169*;k*9#*7+~U(2jpzY%vm8Lh zcq9P7R2DXLK>v?vDDDXJ_Th4K6?;(=#$D%e@_rx2T}jdn#B11k;$-REmuYuMN8;K9wc0(v)>_a7j`bBo@2Ub8EL$C65(NkX;!IId14}Lrsu=T zB?&J%&ZJjoXJ=u0reA+DqCy@?dzE*@%yq<5@2)K3#Td~813gMd$qfiddbo`Po~|Nx zCpV#w4ygkhl&dfDQ}S#iTwu}9FdPB)llAVE!j!(-l^2}h+MHw*Nfdrmc`(Wdi_9nm zth$Rkr|`O(m$-{!sIp5#o7oKbTmyNuPrxI+4na;_BqW_8(USjdQ0BLlI;vrv1N%+3 z-vA$?DGlwreI0yO1|J?qV;z%xFRW!boG+U*o6smTMKZ#Fa2Ubo^JgdaFUkuj8UrdJ zNE+bdwL8v_gqx%q)PDc3Dwc#ab5=jK5yn$8GT83^Cr%Rtc`WF^ouk)c@kn^{y>FEA zz_8iSDWTuXE*3+XtmoZO;&I zMTs|OWk|J0?*P(U3P64`%=EA0OFu;`Y{ZqtskY-|jpHOZvL+enNO8%xQLVpz&2@f5 zTv6un{CM|6fE6mi?i@LER;Pz!}Qk<58DOt$dy!OL_{L75`rf?q}K2$y*`_0pOhr z>hRzrt7kKVnA@MVl&*Rllx=mWG1L^#84vJ|IiX3rFZE15)NMVLgfli| z79QN_;0hv3w^d&yt>9uX@OftxcB=!a)We!Lb3~!%l8)hH7@fr0R*w^f(f|m6x)8lmNSS?>K}Z0=H*Q8O=v24`ed$d( zf=RL99tjwj!r8epKkn$7UUj|RR(~VX=L@2d04!TLqQHC?6G|0ls5_pJhVv=CNqaG| z^PtFbZOFU=0yc?eqsb;KRM)|)UH`vEB3CLTTx1LS4C#VzN7&kNHPpYwNCTvI%pRj9 zKU1KGu>pt7HGVA+eii!fj9kKtR@N8Mg3p-bIfrY}V*uzuY(TeR%YSgosLLYit!~nQ z$9b8qUzcZPv2ut#AR^V8?9{DlR?K=g(uDipXZViYqn&x7I@bI)7M#P976)Vh16Ix0 zyCta&=-G(c_u+g-3kwTkBwYNB9j@epQ8Lri%h8e*4eNZ;0LLA-N4tVEVq{4Rzo7cc zpOuN?Pys9*e>2Q?#D#Ei?q{#jgWEY|syrz|{)rSW<2FcQLD$`0c8-c(+P?&njadrk zE{&o{$p7E3)l0%5lwq1TPzfq(pT7kNIT19K`e?;NIaM~1`S*QE!tv=Wxfb}11TpaW zH{@|2DTGG0L<>?~J>TKGA4jHK%EqyQ`-UNN;s1{&^pX9V0D#w4O@c5l7Wu4D_*J_v zVR+FPd7sB$+~aL9nJ|ZYiJ%f+cZ!p%R3;E|fs=rAA7*J^I$)K5ZvOpLPW6Z)Om)+B zLVx$AKG`PMu9Oe>d>tS|+RGC?WS$9#9M%7|!Q>?d^&|a^hYd3_{kZw7^UD$IL`*ka z4#!R2PNVa2*7Vh2ucwT^v#S4zpy%q(f-~CTTH?782|C62pivJj(EdOeRt{s8hWr`l ztuPtp|31`>Q=F3}+bumh|fLu+Li0N9c#y$3F#(9ftql>bcU z*Wv)@EJGdDSw49i)di1W(>i~h2L1PS&F;d7f2qhpm0~p0yFKz$<1|`i#Z`dNu0i$m- zw1Wl77=ePDfKd#0clXt_UTMJKAVP;}_dM=$SxBG*c+~3kMG-KHxIvrO+=6F-QQ%wA zQ^~O3-3Uea9vJ$W8(>LZ?Te&@s|{)Ma3vEP2aHm?osVvr;{mt{^davT?k@gtPax6C zxTKcnh$8eS3OYTIatQuT2Tk&ezNx7x0|1{cr4Oi>ij;tpK>kXJzz~97!2^K4uHa5U z(?A(kO%=QS9kK{T2fQ+Km9ob!mU%W7Rq|q6dbO$w8Dwv4Uw{1qylf zOz9!|cekR^|kxXmqav#U+gc?ahh)SNEai zlzeSY^1r(9;*W?n0F|OFgftQxun(KGEh%{Gie#9O(FbJbc`JVVTZ4TVh1R?4GbcM| z+j=1JdsZOz+@Gmjk)ReH!21X|@u?wSwL6kwVt60WQ84fH`Uwp%h@!q~xzoVfi0Y0K zXpJ!VKuTbg3H__LlA?7R0|Wwhh|RPeB`tye`WN8i=jZp&XyZOj6%hEbuFU)TaLKzT z4IN=P@&@mRYFU?kv_g{<6tp)}Ct%@*AXg{=bG>w|iG&D@ydKX+98ds%qgq|g>$-G* z*wc`PXa=3tEoLW5H>#IT5-0G#`i&13cGQi=QebD6K$99=B06=tNqPwPiCbe@U4W!JW_d)xXhS4}Tg4_QZJGvC( z31fzu6{x)}V*x*~)dIZn#>FEsM+vs_lD0pFq8fOCw|Tj!t=!0H(C&1*~LiM^H8!UZ6WrSuWj3d!g_Zs*S};&9E~UIm

gx-nJR2iKWSnd1Ld@@;hN8~x7b$}U`)(sL>n!L7xX zEw3lvpSk>GkqgM%a%?K+x~=8HPedeOawj#H%*tVn*ePV#%=m0PmEohSiuXMmr(jZM zXQ$-D$-GGASW;h;oK+EBQOeUfr#@qB;(l`n^iy00BflXgh&Zf-#FSl#=#Hr?J86YcwV^w~uAvxz4G7hlPx+{mGt{+E`S!li#?K{+9_0%*{TAz| zqFJmgoM<08fW|mqZ0nobPq|NA2w~Di9i)APL1Phhj&eR9KIDeVXZCrq9om3uFjdHZ z+VScj!-9D(aNMf~lH@-x!%>3TZw_iNbPwC{(>NWyi|y6L{kD-=5nfcTl$^&K)kqZ-dx_7s|5PRieXI82UrnE`nl261q>S(BWg^Fi7ViIb zoBGyBvn1=Hz)D8kQRIiK__E7FmFR;vQx;b@{Zgr!P|M(ZC+gyDKNx~tRsC!%!0TeJ zrWjIEkwZA#Eg!3nK|^_pqQQy(KBI5p({#xzf;S^ZUEXj=8*hbnvwiQFc-3nnW|8Yu zlONa?TE-yJ82os6%UevS2!bp+C%XS0ds)VfK{1yrh2QG(u$YqTz3=y**dfVoy2T!3 z_(YuVx?_`lL>KkY^Ss<2Qxi*oLLWfLp2;JUC_m1Q7qp3Qd2M8m6GX*Gu%&R`XoYmc zufdDVDP`SjbtH$3(eIBPFl=BfF}ORzL$5jEdgq#xvJ>mG#I~;nT|^xwNM~Ws0Z~6g z?;81~EN{a{!ug2R7}bd-4t)QZ8l??rGQ4Vg&Z0AEUrPypt#emX&^2O9k`)aJS%vV6G zdjXDk*n@IZ!U{aNB%d>$mpZp*4NX5N8Gq_AgNi>F99?pW*N2GP#wN3zQVYu68R+fU zsBz=R^hp}e7Zr^no)-VO7YWltJ(Hl>nbY9TyL+ts?krHS#6g>!wdH>?hR7J|Q|^R{ zhF8T>pUL!iq>L{E+nQNt;8rHwB) z6^_Qc$u!|`ff)<~rnU}fd=y5TlPNX<331xSC5AMYEzZ=`(zh6`Fk+ot0GMJ zz*`FG2a})Y;hvzB&zdG)1FkDaueyI*42;Oz9Oni+)kQg(ia*t}*^LkxIhPr$erYwU z;0ga)`>;CRJrl_e*9Wh;*x3)eQFgWR`KC{AT;erS#vAI8wIWW;snwe);ucumd8w1!a_;p{a_gMH zwp&&Onp}6`Hs5is{M8a&E8!oj>#yrEs`6{Zhcl;1?dePgm0vU14_uL8$Um?r90+yd>gZl#0i_=77b+ z@UZyYXl;WPPbL5DuJ+eKFl*Tu%$58j$5jTx)ZDzp9cW~E^SRe@V+y9T>;RPy-oZ(O3L z#ai8_vmr11O|@_D^TEG50UScoI56bU=56ge>m7a`%I$lXRid9urpHPxf1u?TT zK5nce{u+M2BwyOCKV6X!)Hca3LH;7G^eNn~a+8b5{7c5B#778jwPj}8kRYf<|C zzMarPg@&#^82qIONDQKqWgIJv6{UE10ydMCDpdUF5Cn$((1Q@laaD)=;pfq{w)B0? zNq9STV}N1~6KVO388!Ylj1A`1l24>>%$gegkX6J@B^w^^gb&76;3_45fMprPVb;cQ z*OOUi_iKPQSQ{8;@Jq1Lr_ZA=j{DWT-hzKO{_cJ~_$nZ87x)tRtGnFX-(TG2j$1Ei z-xyjNe2@LIf{*Ao7^K8vou2Gwfw&XSY-~_S25Wj+sc5Ab-l(xcNDEm}_WB>UbF7 zHBFSl?|7~5&-|26@rnVww(&H?fxKOO;w;HXr@3d?e39it(UnHddy!&CP#CfOEM~hWU z?{MVZ|G-lCG98X7zk=wLHqH5qDK%q=G(<8X4E-KUCjz=xA zJPrb)$8bGUGO{cz9qUScu;M}Izt$-o?)Z;|J+mCOAUhm8f)zo|_GTRq4Q-1k<_edJ ziPRBop>#?JFcV9)P>I(dmG}z&>jyJ)UbwXT*E!DvDCA#p9C@=GqvCrDx2T4N?gc|J zMzSjc6l8pDB={dWEmT4cu ziaH`eDd@wllpok+=}$MsR`8vyg;*VLDSl$l6>#8zU@P>p9}vz$3p?L{?_qI`fVh9W zQdNj|szWTAC;RUc*D8n=o?*?`H;$OXf7XBbqXv=5|3}*7(NiJZ;fTAMe-5IgG1z7= zRQK8Y;WejRI+eBhj{_v6YgG+ze&}wLC|fr{>qo1>4%vSOmSa%D6GGc=Z5epD(DH5h zvQt(i&BL<|{$-FKg#Q}$>v4?RG_}PPh(1Hzd%uq}UD@8*xOVk9?<`%(8FbLx;?0@k zhc`1pn?y)LVpetumSK*)Qbzee7vE8YRtozM?vYtWwjja zP)HxF(azCu>~b+#JT$}v9ev;Y&Zu0wf*u+PNy1I9caqgJRrjd&4?0X2U{(X!hqH7& zfcqa}Sg=UEbJiFpMYl~EzRC?FW*V9zBzsKnaUoiS!{L25g9zr7k_~TV7j*dzV35l2 zsF1m*cyv9{6zb{bV1I-p3f)b_T!u)9Dr`JB+w30PFmo;*3iO|P=DZ0a<8`p|i*4a- zYAUB1E5GDy2tMl7mx*?yUA1h?A00$UzYy8*A%-yytV6xvT&%qQ+7BY%aqFwS6DuT_ z{Xfin7Qi#nvBy#osO?@#nSrld=KEi!vGK*a7oAiLYCtg@EEfOT1lf6Utf&?$8wreW z5g3i&tTgqgh z8*n@N-qII2a2fy`7?6f(;FL|vaZBD&jOFRd*MSz!m2S~;muH9u8&Q^J-Vs!t>q@iRj=3x)h<(R47Us8hrJKm3DAhi zdX_HeafCh3Kn{(~w8?K22-$O!1vIh@8tUr4T`C8~B4go5RA-Oao;a=8p1g)R@eNlr zICCBNK72tjKrQ>q%TKg6k={=3_+eFIrtsIYigRwr3w~PD;827d<7BSr##iTCZv)&d z;@K47B>UF@tCi*&)opQ>w&m)%GVg~q$ge!4NubHwJ?zX_)w2{X_aMozWhYxf)~)HG z6Ou3CoLAUYAM4DK;|%QyyG{c~roD+d=xTZYU<9HI8WJy~I9cyw#hla{ds~Hy>dX4& z??t`%^Vg{tx%0wrzW|1Bkynx?gE>6&W7kw!ersx0FS*KAJL>|Q%;Sv8djf(k{ zZ=LYt?<#ikH0nhQ=s-P|^XlTf9>Ibxp?_;NpI9~saZgC>si^jPW>WcgzJuP z&9>vAB=tj(nLeLxM~`lS3LOj?_hvjG#>ZDY2h+l}f&f7KSvcF^%RQS&@g53SIejZe)Uh;emnkY?`HG zdFGWbxUr@M3r0}{#Ay;Qy(jJQ-88H65B?Sr4!8NYL%tpzGw)4CEBj7WbJ-?3=u-tX z&7~mfrOE(+)niq_7lyUl=U_aRI*q@VcH-?fm;$M#SO!F-!=+z*qPx?YRG473d&q#n zarb~{eiP5`Zz~dnpOA_w9?$1HpkVov&%{h!KQvduG`JyJB1uXVaVhLPBnN3X1b}qc zt2ZNbA-}a}0{rjU#k?N>)St1EuK;M^uYSV!4wEzQax>WF3| ze&0^(3jDTuO{&oF>vh^z?9lyLYwf2tJ6^3vGPQ_q*V3a#+pIS$(i3*wL)4%O&Dlz+ zT)9nUKkqQVijkL11z{^qg$~ajq^DD1_|v*77)~#fTMZo@|HNnUGk15bgncfVC#Mfu zOcKaY#AtS6KW49ozwGR}dKT=`F6Mh%wo3(^+uWyIf7yCq&v_&Aq84Cw=9{GYPlwy4 zlkr8ad)CtLH9Ec5BN!~Vv4na@7EZ@bG*|g33!v)hIhOt%F9yx6gAhSM>C8VP+8lpq~!ns zUl!3+hAR1)#PeGP#^B@UKfivwda?e~7dPG`Q6%g{+;o_66LPnfiT@PAq@3tXss!C-1Gk+qao6W935->4LZnhV~!1w)fK5IoWxz%kF|dX{QmZ+B;!F<(7hD z<;7#oOP zG^&TC5~@orMSKg68c#21#jnPwE*~Pkdm3FnoZeIC z-pAj~R|?d$Bhz12eraG4C6c*abW36zd^eg2SPmLnpLb z_?fg@0|+bmV>g%ym;>C`l#;Gu4)=bpT`zdKIWKwA6bwfAyE;J#?#r&1xDcrQ^l|mp zYJ{>K``kcK)6A^>fmd$=eQ);O>)P1sYy2nlnRV?M8oT}DBz`B_xQ|}{=Hqm4(;GT_ zJd@@N*24HBmB-rQu&pj%V|j^~iTQc$Ejj{uW5Hk~SZ14QXeDz>t8(fuW7E7l(?5SF zzpuSBuobl8XLlNwZbW!J^>@67HC@kprw!XCC573T+pl|j{6HK&dj{QpBs3A6B&6he zMpG*o=~NL)9A~~HXnwtF{{+?0W)3$4QZ1n7NyKE4Dm6DH9ldJi8tlo9SD&;Bc{ z*A!RmZ*t$YsvebxO+J#NT4bOz^dpm@JaBbaVhG((+hoBJ_9J|1>iS7suT;u7DdZ`g z`RhLAh>$#ayHdsSbAh+E=eG4axXM$IFVF{x^lG zh{|^}QrHgrf%`}<1Gecw#x;w*{3U$OT53E_-?L2ztqH|L!eSY>M7qeuy{jc)ZZ+_rv}K8+Zo&XxO8* z8d+Tr`R);!an8;xM5OJ(-64?R5m%HTwHOZuB=Awx!y7CMt(} zVqVi+ObxXd6}wmGCXKW5H@ALlVevmic{!0?LU)0)<*TScGTP+iJzdS5l|1Fe_SC9M zn%^RleKP$^CPHpc^PCU|lBTy?MMs_k=9dO;!os*zi{*}M>-tuy=eV$;F^Ogj#Pxh{ z;rmjifyMT9@Ko%x?e%v{)bJ=3OAv0lRI00zucnlcU}0ZVwBGzEpv~hh{)KM2gShty z{;kQN_L|cSva#z-@Ru$DC3l~@G`;Vyu4)2wWE#Px{*UJRst4#~4ViFV0pO$M- zRvyOUp>QX^mX=cgyjiuFS;dSbMvKMM6GsMu@Tmst^^oBRdZIY}j+M^PpfI_Eq@6dE z_EZPQa=%Vmr)07Xt}Pd#e=3{m4lHjsIK5xK#K9fy_wnERoMrY(cn6skMnf^S2CROD zbO<)K@sa;iFAL!=kqyHgPC0OA%QQof1X6G}`<%qa-!nasr=q>+c^6U!D?8EFV21u| z@vE8kok%^*dRkkYzou=IV&q!A{I%u*-pyUhyc6rGTeJlFL345QjApF^n9Ssc30?PF zt%9b{wnvmc_(8YNSM$o(^?!NKSTTKKBeT1Y$1IyDyk%c|91Kj_QAJtWs6AfR6k5~+ zi*2_m-vx06lcSn;*@;e~C$esMRjL;^o`iDoz&?%JMNWLnm%zR@x;|P_aCe7Q{URaJ zsmAEZS)|t)Nu22c(yc}I-da=)7pY$&bAv2r@zb@+)HG(=Gl5AKMs+9y|m6+gQIO;i=a_0`B!NNLy$> zJt>8qB!x~7TL*|lbB9cs0Cm1?AE&&+YnpW~YB%%5j5CL3d=C5_dIj#-WM+gv)4KlP z;4#1_;lH}`)N(pz!t1_uA+(4lfq9$+XA(0u1@D(KWPQaF3daCdWX4A~7<2#QwsOtv z<$Agd;^K*TLp7e$_P6euVT@I3u8_3UmjqsHHa(Q`ADMrmIVFo-a=x?aa2Kj%o)9gP z=Ms1KEYs6iz}SfV3>?@FY<0-X$(c7_Q%RbMiMP|hM#vd%cp%h(U`nyqT!fs$t zX~Ara0b>Hj7F034H?6175-HA55Oa>f&1_bG+tQqnpg9$!pC{_G&^DhTnx=pz#|8Q! zs&JQ=#H-q8+oSKsss`=e^D=>7ibukM`X2?AH(9xfQxRAE_C#T>J4qgwTNgX9ld5xg zI=1;DXGYOL&ji=erKW2=ZG3?*djzgmW`*d}n~6(hDys?Wfr|R~k4-Rl)XLr;pc+R5 zR7xxKMAdh@^NWv9`}cOJ@2m~u8kN!dJ0Z_=*{w5^orSgVld$Vft!o*Sm5=$4s1g(ECX@_>$pQ)fM@7%+9 zc$w7wlodb_FPh$~tN7IkJ2EbMUZ3emZ6b_}2bzo>!LO+QBsl4Id6US>8wPXVFB|UI+>2BbHL@-qua^*$(A;lGWEk6N z**3+@BEN|8QTScSbIY9t8&L%JRp`99X0g|#J<|&NK|Ly--7&X^by8yuJK#MrQ5D=} zr)sIvJmV>im=f})T@B}~B_N$rliwqMv9MIG{J+wvs-=$QJg3yhm~^C!>;- zD`V!Dt|l+G(x$h>Dl1RZb;Vi5^P#jFH)Qhp=ZU1HM{qnU4S@+3_j3E!k&HF2uffN` zV?7h+Gnd&madC~f3!eLyJNr=Q`=SPrm>;&NYrP`(_x%^Apm81?W)phRex{nu)Xm_W zx|MV`hQFK{@<(d>n_2frx(9FRzI%C_7g3E#S`zl>KZP@HZSlHRtvBw8LZaJl{a!Y2 zbV9!glZEzTSxZ1ya+C1Pt?oA0=uch~+ej1B6``9N?@VCKVn;%S{aiEKQlW(`!*3N6 zH8#wJQMv$)diy+O!+G9Q)$^nQ*Bq|mX&;nbMf`CyQ)Uc|{b+giEh^i9#s-XX*5mIJ z&pi7NuPs0hsIYu*E#pXS?uD55%F47nEM~#~+2XS>OV=}Q4NET)_>?Y>x`gjK^9I8w zSF@x_gPa7K0}SnSh6p{5FTvQjBs9dC1QN`J9qdxKjbdl78i$7dB#mawkLrS zH~H`K0H+-r?~m!4JLRW12{ucsVPu0a#C5(72XWeNgmV_JRW8E#*ef2+2`e59Q?f8{ zjuK##Icb==GanOTmzc;JmrHT&2V*~?$5IpqI8~{AadM{!~J+or@aa`8=WIQgDhPa2jW$?B* zs^(b-R&`;tHDF1;HBe06Z+soH>rGdbi7Lz6eO5^PN#B4GwV15mL-V0R21{Kq()#{4 zfAwQl2bJvSNQiLzjYF-@4xcym3>?=|8N_GAyYaI3pjk7jwP2XqdMbw`=`38B#JuvIy=28rv}%hE>wC@Ok$Wr0H%R z4Yld*D9EVQ87@--DhVPN8}5sKcPmX`5(3=s-_|Qcs~#xX})R!Uf9!)Ws^i< z_`p_CXJ1>L0)0L)B70xpL**H{*3|fh)l_I$k}wwZtuG&zdQbsEH4c41?>-#P~_54fO`iD8v^oOvNf}o7Z|XRx3?8O z6iRA3UgiNB$_1q<9cJ#bzRxIgfk-k`yZ8)E#N#H)&5jgs634~y^S-4R$v$A7FYPd< z~0>#qw%x&2e8_NRh1dra~OTU+xR8|0+YP)d_k%;~R1c0kPPMP~zw zZn`RFfES>- string; @@ -14,13 +19,14 @@ interface DeFiScanContextI { const DeFiScanContext = createContext(undefined as any); const baseDefiScanUrl = "https://defiscan.live"; +const baseMetaScanUrl = "https://meta.defiscan.live"; export function useDeFiScanContext(): DeFiScanContextI { return useContext(DeFiScanContext); } export function DeFiScanProvider( - props: React.PropsWithChildren + props: React.PropsWithChildren, ): JSX.Element | null { const { network } = useNetworkContext(); @@ -70,6 +76,8 @@ function getNetworkParams(network: EnvironmentNetwork): string { case EnvironmentNetwork.LocalPlayground: case EnvironmentNetwork.RemotePlayground: return `?network=${EnvironmentNetwork.RemotePlayground}`; + case EnvironmentNetwork.Changi: + return `?network=${EnvironmentNetwork.Changi}`; default: return ""; } @@ -78,7 +86,7 @@ function getNetworkParams(network: EnvironmentNetwork): string { export function getTxURLByNetwork( network: EnvironmentNetwork, txid: string, - rawtx?: string + rawtx?: string, ): string { let baseUrl = `${baseDefiScanUrl}/transactions/${txid}`; @@ -98,7 +106,24 @@ export function getTxURLByNetwork( export function getURLByNetwork( path: string, network: EnvironmentNetwork, - id: number | string + id: number | string, ): string { return `${baseDefiScanUrl}/${path}/${id}${getNetworkParams(network)}`; } + +export function getMetaScanTokenUrl( + network: EnvironmentNetwork, + id: string, +): string { + const networkParams = getNetworkParams(network); + const tokenId = stripEvmSuffixFromTokenId(id); + + // DFI token + if (tokenId === 0) { + return `${baseMetaScanUrl}/token/${TD_CONTRACT_ADDR}${networkParams}`; + } + + // DST20 token + const tokenAddress = getAddressFromDST20TokenId(tokenId); + return `${baseMetaScanUrl}/token/${tokenAddress}${networkParams}`; +} diff --git a/shared/contexts/StatsProvider.tsx b/shared/contexts/StatsProvider.tsx index c4afaaf567..cea800837e 100644 --- a/shared/contexts/StatsProvider.tsx +++ b/shared/contexts/StatsProvider.tsx @@ -9,7 +9,7 @@ import { useAppDispatch } from "@hooks/useAppDispatch"; import { useWhaleApiClient } from "@waveshq/walletkit-ui/dist/contexts"; export function StatsProvider( - props: PropsWithChildren + props: PropsWithChildren, ): JSX.Element | null { const { network } = useNetworkContext(); const logger = useLogger(); @@ -24,6 +24,7 @@ export function StatsProvider( // isPolling is a good indicator of background polling // we can use AppState to suspend and activate polling based on user activity let intervalID: NodeJS.Timeout; + let timeoutID: NodeJS.Timeout; function refresh(): void { dispatch(block.actions.setPolling(true)); @@ -38,7 +39,7 @@ export function StatsProvider( lastSync: new Date().toString(), lastSuccessfulSync: new Date().toString(), tvl: tvl?.dex ?? 0, - }) + }), ); dispatch(block.actions.setConnected(true)); }) @@ -49,7 +50,7 @@ export function StatsProvider( count: 0, masternodeCount: 0, lastSync: new Date().toString(), - }) + }), ); dispatch(block.actions.setConnected(false)); logger.error(err); @@ -57,14 +58,19 @@ export function StatsProvider( } if (!isPolling) { - refresh(); - intervalID = setInterval(refresh, interval); + timeoutID = setTimeout(() => { + refresh(); + intervalID = setInterval(refresh, interval); + }, 1000); } return () => { dispatch(block.actions.setPolling(false)); if (intervalID !== undefined) { clearInterval(intervalID); } + if (timeoutID !== undefined) { + clearTimeout(timeoutID); + } }; }, [api, interval, network, dispatch]); diff --git a/shared/contexts/WalletContext.tsx b/shared/contexts/WalletContext.tsx index fa9e9f868f..aacdea42ba 100644 --- a/shared/contexts/WalletContext.tsx +++ b/shared/contexts/WalletContext.tsx @@ -29,6 +29,10 @@ interface WalletContextI { * Default address of the above wallet */ address: string; + /** + * Default EVM address of the above wallet + */ + evmAddress: string; /** * Available address length of the above wallet */ @@ -65,12 +69,13 @@ export function useWalletContext(): WalletContextI { } export function WalletContextProvider( - props: WalletContextProviderProps + props: WalletContextProviderProps, ): JSX.Element | null { const { api } = props; const logger = useLogger(); const { provider } = useWalletNodeContext(); const [address, setAddress] = useState(); + const [evmAddress, setEvmAddress] = useState(""); const [account, setAccount] = useState(); const [addressIndex, setAddressIndex] = useState(); const [addressLength, setAddressLength] = useState(0); @@ -88,6 +93,7 @@ export function WalletContextProvider( useEffect(() => { if (addressIndex !== undefined) { const account = wallet.get(addressIndex); + // DVM address account .getAddress() .then((address) => { @@ -95,6 +101,14 @@ export function WalletContextProvider( setAddress(address); }) .catch(logger.error); + + // EVM address + account + .getEvmAddress() + .then((evmAddress) => { + setEvmAddress(evmAddress); + }) + .catch(logger.error); } }, [wallet, addressIndex]); @@ -129,7 +143,7 @@ export function WalletContextProvider( const lastDiscoveredAddressIndex = Math.max( 0, activeAddress.length - 1, - addressLength + addressLength, ); await setWalletAddressLength(lastDiscoveredAddressIndex); }; @@ -142,6 +156,7 @@ export function WalletContextProvider( wallet: wallet, account: account, address: address, + evmAddress: evmAddress, activeAddressIndex: addressIndex, setIndex: setIndex, addressLength: addressLength, diff --git a/shared/contracts/DST20V1.json b/shared/contracts/DST20V1.json new file mode 100644 index 0000000000..c611c8bc9d --- /dev/null +++ b/shared/contracts/DST20V1.json @@ -0,0 +1,298 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "DST20V1", + "sourceName": "contracts/DST20V1.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b50604051620017f0380380620017f08339818101604052810190620000379190620001fa565b818181600390816200004a9190620004ca565b5080600490816200005c9190620004ca565b5050505050620005b1565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000d08262000085565b810181811067ffffffffffffffff82111715620000f257620000f162000096565b5b80604052505050565b60006200010762000067565b9050620001158282620000c5565b919050565b600067ffffffffffffffff82111562000138576200013762000096565b5b620001438262000085565b9050602081019050919050565b60005b838110156200017057808201518184015260208101905062000153565b60008484015250505050565b6000620001936200018d846200011a565b620000fb565b905082815260208101848484011115620001b257620001b162000080565b5b620001bf84828562000150565b509392505050565b600082601f830112620001df57620001de6200007b565b5b8151620001f18482602086016200017c565b91505092915050565b6000806040838503121562000214576200021362000071565b5b600083015167ffffffffffffffff81111562000235576200023462000076565b5b6200024385828601620001c7565b925050602083015167ffffffffffffffff81111562000267576200026662000076565b5b6200027585828601620001c7565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002d257607f821691505b602082108103620002e857620002e76200028a565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000313565b6200035e868362000313565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003ab620003a56200039f8462000376565b62000380565b62000376565b9050919050565b6000819050919050565b620003c7836200038a565b620003df620003d682620003b2565b84845462000320565b825550505050565b600090565b620003f6620003e7565b62000403818484620003bc565b505050565b5b818110156200042b576200041f600082620003ec565b60018101905062000409565b5050565b601f8211156200047a576200044481620002ee565b6200044f8462000303565b810160208510156200045f578190505b620004776200046e8562000303565b83018262000408565b50505b505050565b600082821c905092915050565b60006200049f600019846008026200047f565b1980831691505092915050565b6000620004ba83836200048c565b9150826002028217905092915050565b620004d5826200027f565b67ffffffffffffffff811115620004f157620004f062000096565b5b620004fd8254620002b9565b6200050a8282856200042f565b600060209050601f8311600181146200054257600084156200052d578287015190505b620005398582620004ac565b865550620005a9565b601f1984166200055286620002ee565b60005b828110156200057c5784890151825560018201915060208501945060208101905062000555565b868310156200059c578489015162000598601f8916826200048c565b8355505b6001600288020188555050505b505050505050565b61122f80620005c16000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461016857806370a082311461019857806395d89b41146101c8578063a457c2d7146101e6578063a9059cbb14610216578063dd62ed3e14610246576100a9565b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100fc57806323b872dd1461011a578063313ce5671461014a575b600080fd5b6100b6610276565b6040516100c39190610b0c565b60405180910390f35b6100e660048036038101906100e19190610bc7565b610308565b6040516100f39190610c22565b60405180910390f35b61010461032b565b6040516101119190610c4c565b60405180910390f35b610134600480360381019061012f9190610c67565b610335565b6040516101419190610c22565b60405180910390f35b610152610364565b60405161015f9190610cd6565b60405180910390f35b610182600480360381019061017d9190610bc7565b61036d565b60405161018f9190610c22565b60405180910390f35b6101b260048036038101906101ad9190610cf1565b6103a4565b6040516101bf9190610c4c565b60405180910390f35b6101d06103ec565b6040516101dd9190610b0c565b60405180910390f35b61020060048036038101906101fb9190610bc7565b61047e565b60405161020d9190610c22565b60405180910390f35b610230600480360381019061022b9190610bc7565b6104f5565b60405161023d9190610c22565b60405180910390f35b610260600480360381019061025b9190610d1e565b610518565b60405161026d9190610c4c565b60405180910390f35b60606003805461028590610d8d565b80601f01602080910402602001604051908101604052809291908181526020018280546102b190610d8d565b80156102fe5780601f106102d3576101008083540402835291602001916102fe565b820191906000526020600020905b8154815290600101906020018083116102e157829003601f168201915b5050505050905090565b60008061031361059f565b90506103208185856105a7565b600191505092915050565b6000600254905090565b60008061034061059f565b905061034d858285610770565b6103588585856107fc565b60019150509392505050565b60006012905090565b60008061037861059f565b905061039981858561038a8589610518565b6103949190610ded565b6105a7565b600191505092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546103fb90610d8d565b80601f016020809104026020016040519081016040528092919081815260200182805461042790610d8d565b80156104745780601f1061044957610100808354040283529160200191610474565b820191906000526020600020905b81548152906001019060200180831161045757829003601f168201915b5050505050905090565b60008061048961059f565b905060006104978286610518565b9050838110156104dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d390610e93565b60405180910390fd5b6104e982868684036105a7565b60019250505092915050565b60008061050061059f565b905061050d8185856107fc565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610616576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060d90610f25565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610685576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067c90610fb7565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107639190610c4c565b60405180910390a3505050565b600061077c8484610518565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107f657818110156107e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df90611023565b60405180910390fd5b6107f584848484036105a7565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361086b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610862906110b5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190611147565b60405180910390fd5b6108e5838383610a72565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561096b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610962906111d9565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a599190610c4c565b60405180910390a3610a6c848484610a77565b50505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ab6578082015181840152602081019050610a9b565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ade82610a7c565b610ae88185610a87565b9350610af8818560208601610a98565b610b0181610ac2565b840191505092915050565b60006020820190508181036000830152610b268184610ad3565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610b5e82610b33565b9050919050565b610b6e81610b53565b8114610b7957600080fd5b50565b600081359050610b8b81610b65565b92915050565b6000819050919050565b610ba481610b91565b8114610baf57600080fd5b50565b600081359050610bc181610b9b565b92915050565b60008060408385031215610bde57610bdd610b2e565b5b6000610bec85828601610b7c565b9250506020610bfd85828601610bb2565b9150509250929050565b60008115159050919050565b610c1c81610c07565b82525050565b6000602082019050610c376000830184610c13565b92915050565b610c4681610b91565b82525050565b6000602082019050610c616000830184610c3d565b92915050565b600080600060608486031215610c8057610c7f610b2e565b5b6000610c8e86828701610b7c565b9350506020610c9f86828701610b7c565b9250506040610cb086828701610bb2565b9150509250925092565b600060ff82169050919050565b610cd081610cba565b82525050565b6000602082019050610ceb6000830184610cc7565b92915050565b600060208284031215610d0757610d06610b2e565b5b6000610d1584828501610b7c565b91505092915050565b60008060408385031215610d3557610d34610b2e565b5b6000610d4385828601610b7c565b9250506020610d5485828601610b7c565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610da557607f821691505b602082108103610db857610db7610d5e565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610df882610b91565b9150610e0383610b91565b9250828201905080821115610e1b57610e1a610dbe565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000610e7d602583610a87565b9150610e8882610e21565b604082019050919050565b60006020820190508181036000830152610eac81610e70565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000610f0f602483610a87565b9150610f1a82610eb3565b604082019050919050565b60006020820190508181036000830152610f3e81610f02565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000610fa1602283610a87565b9150610fac82610f45565b604082019050919050565b60006020820190508181036000830152610fd081610f94565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b600061100d601d83610a87565b915061101882610fd7565b602082019050919050565b6000602082019050818103600083015261103c81611000565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061109f602583610a87565b91506110aa82611043565b604082019050919050565b600060208201905081810360008301526110ce81611092565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000611131602383610a87565b915061113c826110d5565b604082019050919050565b6000602082019050818103600083015261116081611124565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006111c3602683610a87565b91506111ce82611167565b604082019050919050565b600060208201905081810360008301526111f2816111b6565b905091905056fea2646970667358221220111835cf5177d466ff04d1477368807f060bf7fab712e923b43a54116fd1f5e764736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461016857806370a082311461019857806395d89b41146101c8578063a457c2d7146101e6578063a9059cbb14610216578063dd62ed3e14610246576100a9565b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100fc57806323b872dd1461011a578063313ce5671461014a575b600080fd5b6100b6610276565b6040516100c39190610b0c565b60405180910390f35b6100e660048036038101906100e19190610bc7565b610308565b6040516100f39190610c22565b60405180910390f35b61010461032b565b6040516101119190610c4c565b60405180910390f35b610134600480360381019061012f9190610c67565b610335565b6040516101419190610c22565b60405180910390f35b610152610364565b60405161015f9190610cd6565b60405180910390f35b610182600480360381019061017d9190610bc7565b61036d565b60405161018f9190610c22565b60405180910390f35b6101b260048036038101906101ad9190610cf1565b6103a4565b6040516101bf9190610c4c565b60405180910390f35b6101d06103ec565b6040516101dd9190610b0c565b60405180910390f35b61020060048036038101906101fb9190610bc7565b61047e565b60405161020d9190610c22565b60405180910390f35b610230600480360381019061022b9190610bc7565b6104f5565b60405161023d9190610c22565b60405180910390f35b610260600480360381019061025b9190610d1e565b610518565b60405161026d9190610c4c565b60405180910390f35b60606003805461028590610d8d565b80601f01602080910402602001604051908101604052809291908181526020018280546102b190610d8d565b80156102fe5780601f106102d3576101008083540402835291602001916102fe565b820191906000526020600020905b8154815290600101906020018083116102e157829003601f168201915b5050505050905090565b60008061031361059f565b90506103208185856105a7565b600191505092915050565b6000600254905090565b60008061034061059f565b905061034d858285610770565b6103588585856107fc565b60019150509392505050565b60006012905090565b60008061037861059f565b905061039981858561038a8589610518565b6103949190610ded565b6105a7565b600191505092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6060600480546103fb90610d8d565b80601f016020809104026020016040519081016040528092919081815260200182805461042790610d8d565b80156104745780601f1061044957610100808354040283529160200191610474565b820191906000526020600020905b81548152906001019060200180831161045757829003601f168201915b5050505050905090565b60008061048961059f565b905060006104978286610518565b9050838110156104dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d390610e93565b60405180910390fd5b6104e982868684036105a7565b60019250505092915050565b60008061050061059f565b905061050d8185856107fc565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610616576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060d90610f25565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610685576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161067c90610fb7565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107639190610c4c565b60405180910390a3505050565b600061077c8484610518565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107f657818110156107e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df90611023565b60405180910390fd5b6107f584848484036105a7565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361086b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610862906110b5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190611147565b60405180910390fd5b6108e5838383610a72565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561096b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610962906111d9565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a599190610c4c565b60405180910390a3610a6c848484610a77565b50505050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ab6578082015181840152602081019050610a9b565b60008484015250505050565b6000601f19601f8301169050919050565b6000610ade82610a7c565b610ae88185610a87565b9350610af8818560208601610a98565b610b0181610ac2565b840191505092915050565b60006020820190508181036000830152610b268184610ad3565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610b5e82610b33565b9050919050565b610b6e81610b53565b8114610b7957600080fd5b50565b600081359050610b8b81610b65565b92915050565b6000819050919050565b610ba481610b91565b8114610baf57600080fd5b50565b600081359050610bc181610b9b565b92915050565b60008060408385031215610bde57610bdd610b2e565b5b6000610bec85828601610b7c565b9250506020610bfd85828601610bb2565b9150509250929050565b60008115159050919050565b610c1c81610c07565b82525050565b6000602082019050610c376000830184610c13565b92915050565b610c4681610b91565b82525050565b6000602082019050610c616000830184610c3d565b92915050565b600080600060608486031215610c8057610c7f610b2e565b5b6000610c8e86828701610b7c565b9350506020610c9f86828701610b7c565b9250506040610cb086828701610bb2565b9150509250925092565b600060ff82169050919050565b610cd081610cba565b82525050565b6000602082019050610ceb6000830184610cc7565b92915050565b600060208284031215610d0757610d06610b2e565b5b6000610d1584828501610b7c565b91505092915050565b60008060408385031215610d3557610d34610b2e565b5b6000610d4385828601610b7c565b9250506020610d5485828601610b7c565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610da557607f821691505b602082108103610db857610db7610d5e565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610df882610b91565b9150610e0383610b91565b9250828201905080821115610e1b57610e1a610dbe565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000610e7d602583610a87565b9150610e8882610e21565b604082019050919050565b60006020820190508181036000830152610eac81610e70565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000610f0f602483610a87565b9150610f1a82610eb3565b604082019050919050565b60006020820190508181036000830152610f3e81610f02565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000610fa1602283610a87565b9150610fac82610f45565b604082019050919050565b60006020820190508181036000830152610fd081610f94565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b600061100d601d83610a87565b915061101882610fd7565b602082019050919050565b6000602082019050818103600083015261103c81611000565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b600061109f602583610a87565b91506110aa82611043565b604082019050919050565b600060208201905081810360008301526110ce81611092565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000611131602383610a87565b915061113c826110d5565b604082019050919050565b6000602082019050818103600083015261116081611124565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b60006111c3602683610a87565b91506111ce82611167565b604082019050919050565b600060208201905081810360008301526111f2816111b6565b905091905056fea2646970667358221220111835cf5177d466ff04d1477368807f060bf7fab712e923b43a54116fd1f5e764736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} + \ No newline at end of file diff --git a/shared/contracts/README.md b/shared/contracts/README.md new file mode 100644 index 0000000000..8420d3a638 --- /dev/null +++ b/shared/contracts/README.md @@ -0,0 +1,19 @@ +# ABI Source Explanation + +**`/contracts`** directory contains the ABI (Application Binary Interface) for the "TransferDomainV1" smart contract. The ABI was generated based on the corresponding Solidity (.sol) file. + +## Contract Information + +- **Contract Name**: TransferDomainV1 +- **Solidity File**: [TransferDomainV1.sol](https://github.com/DeFiCh/ain/blob/master/lib/ain-contracts/transfer_domain_v1/TransferDomainV1.sol) + +## ABI Generation + +The ABI provided in this repository was generated from the linked Solidity file. This ABI is essential for interacting with the TransferDomainV1 smart contract on the Ethereum blockchain or other compatible blockchains. + +## Disclaimer + +Please note that the ABI provided here is based on the linked Solidity file at the time of generation. Ensure that the Solidity code and the ABI are up-to-date and compatible with the version of the smart contract deployed on the blockchain you intend to interact with. + +For any updates or changes to the contract, refer to the original source repository: +[TransferDomainV1.sol](https://github.com/DeFiCh/ain/blob/master/lib/ain-contracts/transfer_domain_v1/TransferDomainV1.sol) diff --git a/shared/contracts/TransferDomainV1.json b/shared/contracts/TransferDomainV1.json new file mode 100644 index 0000000000..756a77ba7e --- /dev/null +++ b/shared/contracts/TransferDomainV1.json @@ -0,0 +1,181 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TransferDomainV1", + "sourceName": "contracts/TransferDomainV1.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "vmAddress", + "type": "string" + } + ], + "name": "VMTransfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "vmAddress", + "type": "string" + } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "vmAddress", + "type": "string" + } + ], + "name": "transferDST20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610a77806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806370a082311161005b57806370a08231146100dc578063917e9b691461010c57806395d89b4114610128578063d57b2826146101465761007d565b806306fdde031461008257806318160ddd146100a0578063313ce567146100be575b600080fd5b61008a610162565b60405161009791906104e6565b60405180910390f35b6100a861019f565b6040516100b59190610521565b60405180910390f35b6100c66101a9565b6040516100d39190610558565b60405180910390f35b6100f660048036038101906100f191906105e5565b6101b2565b6040516101039190610521565b60405180910390f35b610126600480360381019061012191906107b1565b6101fa565b005b6101306102b9565b60405161013d91906104e6565b60405180910390f35b610160600480360381019061015b9190610848565b6102f6565b005b60606040518060400160405280600e81526020017f5472616e73666572446f6d61696e000000000000000000000000000000000000815250905090565b6000600154905090565b60006012905090565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b8473ffffffffffffffffffffffffffffffffffffffff166323b872dd8585856040518463ffffffff1660e01b815260040161023793929190610939565b6020604051808303816000875af1158015610256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027a91906109a8565b507f5b494f8e62c9b3ea113ad3af9830e30a412c97a58a1237f83b3a515c94bc5577816040516102aa91906104e6565b60405180910390a15050505050565b60606040518060400160405280600381526020017f4446490000000000000000000000000000000000000000000000000000000000815250905090565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146103b4578147101561036c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161036390610a21565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156103b2573d6000803e3d6000fd5b505b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516104119190610521565b60405180910390a37f5b494f8e62c9b3ea113ad3af9830e30a412c97a58a1237f83b3a515c94bc55778160405161044891906104e6565b60405180910390a150505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610490578082015181840152602081019050610475565b60008484015250505050565b6000601f19601f8301169050919050565b60006104b882610456565b6104c28185610461565b93506104d2818560208601610472565b6104db8161049c565b840191505092915050565b6000602082019050818103600083015261050081846104ad565b905092915050565b6000819050919050565b61051b81610508565b82525050565b60006020820190506105366000830184610512565b92915050565b600060ff82169050919050565b6105528161053c565b82525050565b600060208201905061056d6000830184610549565b92915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105b282610587565b9050919050565b6105c2816105a7565b81146105cd57600080fd5b50565b6000813590506105df816105b9565b92915050565b6000602082840312156105fb576105fa61057d565b5b6000610609848285016105d0565b91505092915050565b600061061d82610587565b9050919050565b61062d81610612565b811461063857600080fd5b50565b60008135905061064a81610624565b92915050565b61065981610508565b811461066457600080fd5b50565b60008135905061067681610650565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6106be8261049c565b810181811067ffffffffffffffff821117156106dd576106dc610686565b5b80604052505050565b60006106f0610573565b90506106fc82826106b5565b919050565b600067ffffffffffffffff82111561071c5761071b610686565b5b6107258261049c565b9050602081019050919050565b82818337600083830152505050565b600061075461074f84610701565b6106e6565b9050828152602081018484840111156107705761076f610681565b5b61077b848285610732565b509392505050565b600082601f8301126107985761079761067c565b5b81356107a8848260208601610741565b91505092915050565b600080600080600060a086880312156107cd576107cc61057d565b5b60006107db888289016105d0565b95505060206107ec888289016105d0565b94505060406107fd8882890161063b565b935050606061080e88828901610667565b925050608086013567ffffffffffffffff81111561082f5761082e610582565b5b61083b88828901610783565b9150509295509295909350565b600080600080608085870312156108625761086161057d565b5b6000610870878288016105d0565b94505060206108818782880161063b565b935050604061089287828801610667565b925050606085013567ffffffffffffffff8111156108b3576108b2610582565b5b6108bf87828801610783565b91505092959194509250565b6108d4816105a7565b82525050565b6000819050919050565b60006108ff6108fa6108f584610587565b6108da565b610587565b9050919050565b6000610911826108e4565b9050919050565b600061092382610906565b9050919050565b61093381610918565b82525050565b600060608201905061094e60008301866108cb565b61095b602083018561092a565b6109686040830184610512565b949350505050565b60008115159050919050565b61098581610970565b811461099057600080fd5b50565b6000815190506109a28161097c565b92915050565b6000602082840312156109be576109bd61057d565b5b60006109cc84828501610993565b91505092915050565b7f496e73756666696369656e7420636f6e74726163742062616c616e6365000000600082015250565b6000610a0b601d83610461565b9150610a16826109d5565b602082019050919050565b60006020820190508181036000830152610a3a816109fe565b905091905056fea26469706673582212205fe56b2a0619cb16b206a81a57cd7b92c45b2b0c7fb4d0763da20ae5e2e073c964736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c806370a082311161005b57806370a08231146100dc578063917e9b691461010c57806395d89b4114610128578063d57b2826146101465761007d565b806306fdde031461008257806318160ddd146100a0578063313ce567146100be575b600080fd5b61008a610162565b60405161009791906104e6565b60405180910390f35b6100a861019f565b6040516100b59190610521565b60405180910390f35b6100c66101a9565b6040516100d39190610558565b60405180910390f35b6100f660048036038101906100f191906105e5565b6101b2565b6040516101039190610521565b60405180910390f35b610126600480360381019061012191906107b1565b6101fa565b005b6101306102b9565b60405161013d91906104e6565b60405180910390f35b610160600480360381019061015b9190610848565b6102f6565b005b60606040518060400160405280600e81526020017f5472616e73666572446f6d61696e000000000000000000000000000000000000815250905090565b6000600154905090565b60006012905090565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b8473ffffffffffffffffffffffffffffffffffffffff166323b872dd8585856040518463ffffffff1660e01b815260040161023793929190610939565b6020604051808303816000875af1158015610256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027a91906109a8565b507f5b494f8e62c9b3ea113ad3af9830e30a412c97a58a1237f83b3a515c94bc5577816040516102aa91906104e6565b60405180910390a15050505050565b60606040518060400160405280600381526020017f4446490000000000000000000000000000000000000000000000000000000000815250905090565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146103b4578147101561036c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161036390610a21565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156103b2573d6000803e3d6000fd5b505b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516104119190610521565b60405180910390a37f5b494f8e62c9b3ea113ad3af9830e30a412c97a58a1237f83b3a515c94bc55778160405161044891906104e6565b60405180910390a150505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610490578082015181840152602081019050610475565b60008484015250505050565b6000601f19601f8301169050919050565b60006104b882610456565b6104c28185610461565b93506104d2818560208601610472565b6104db8161049c565b840191505092915050565b6000602082019050818103600083015261050081846104ad565b905092915050565b6000819050919050565b61051b81610508565b82525050565b60006020820190506105366000830184610512565b92915050565b600060ff82169050919050565b6105528161053c565b82525050565b600060208201905061056d6000830184610549565b92915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105b282610587565b9050919050565b6105c2816105a7565b81146105cd57600080fd5b50565b6000813590506105df816105b9565b92915050565b6000602082840312156105fb576105fa61057d565b5b6000610609848285016105d0565b91505092915050565b600061061d82610587565b9050919050565b61062d81610612565b811461063857600080fd5b50565b60008135905061064a81610624565b92915050565b61065981610508565b811461066457600080fd5b50565b60008135905061067681610650565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6106be8261049c565b810181811067ffffffffffffffff821117156106dd576106dc610686565b5b80604052505050565b60006106f0610573565b90506106fc82826106b5565b919050565b600067ffffffffffffffff82111561071c5761071b610686565b5b6107258261049c565b9050602081019050919050565b82818337600083830152505050565b600061075461074f84610701565b6106e6565b9050828152602081018484840111156107705761076f610681565b5b61077b848285610732565b509392505050565b600082601f8301126107985761079761067c565b5b81356107a8848260208601610741565b91505092915050565b600080600080600060a086880312156107cd576107cc61057d565b5b60006107db888289016105d0565b95505060206107ec888289016105d0565b94505060406107fd8882890161063b565b935050606061080e88828901610667565b925050608086013567ffffffffffffffff81111561082f5761082e610582565b5b61083b88828901610783565b9150509295509295909350565b600080600080608085870312156108625761086161057d565b5b6000610870878288016105d0565b94505060206108818782880161063b565b935050604061089287828801610667565b925050606085013567ffffffffffffffff8111156108b3576108b2610582565b5b6108bf87828801610783565b91505092959194509250565b6108d4816105a7565b82525050565b6000819050919050565b60006108ff6108fa6108f584610587565b6108da565b610587565b9050919050565b6000610911826108e4565b9050919050565b600061092382610906565b9050919050565b61093381610918565b82525050565b600060608201905061094e60008301866108cb565b61095b602083018561092a565b6109686040830184610512565b949350505050565b60008115159050919050565b61098581610970565b811461099057600080fd5b50565b6000815190506109a28161097c565b92915050565b6000602082840312156109be576109bd61057d565b5b60006109cc84828501610993565b91505092915050565b7f496e73756666696369656e7420636f6e74726163742062616c616e6365000000600082015250565b6000610a0b601d83610461565b9150610a16826109d5565b602082019050919050565b60006020820190508181036000830152610a3a816109fe565b905091905056fea26469706673582212205fe56b2a0619cb16b206a81a57cd7b92c45b2b0c7fb4d0763da20ae5e2e073c964736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/shared/store/evm.ts b/shared/store/evm.ts new file mode 100644 index 0000000000..ec5fd0b9d5 --- /dev/null +++ b/shared/store/evm.ts @@ -0,0 +1,137 @@ +import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { getAddressFromDST20TokenId } from "@api/transaction/transfer_domain"; +import { EnvironmentNetwork, isPlayground } from "@waveshq/walletkit-core"; +import { ethers, providers } from "ethers"; +import DST20V1 from "@shared-contracts/DST20V1.json"; + +interface EvmWalletDetails { + hash: string; + name: string; + coin_balance: string; + exchange_rate: string; + implementation_address: string; + block_number_balance_updated_at: number; + creator_address_hash: string; + creation_tx_hash: string; +} + +interface EvmToken { + address: string; + decimals: string; + name: string; + symbol: string; + type: string; +} + +interface EvmTokenBalance { + token_id: string; + value: string; + token: EvmToken; +} + +interface EvmState { + evmWalletDetails: EvmWalletDetails | null; + evmTokenBalances: EvmTokenBalance[]; + hasFetchedEvmTokens: boolean; +} + +const initialState: EvmState = { + evmWalletDetails: null, + evmTokenBalances: [], + hasFetchedEvmTokens: false, +}; + +export const fetchEvmWalletDetails = createAsyncThunk( + "wallet/fetchEvmWalletDetails", + async ({ + evmUrl, + network, + evmAddress, + provider, + }: { + evmUrl: string; + network: EnvironmentNetwork; + evmAddress: string; + provider: providers.JsonRpcProvider | null; + }) => { + // If playground then use rpc calls + if (isPlayground(network) && provider !== null) { + const balance = await provider.getBalance(evmAddress); + return { + coin_balance: balance.toString(), + }; + } + const response = await fetch(`${evmUrl}/api/v2/addresses/${evmAddress}`); + const data = await response.json(); + if (data.message === "Not found") { + return {}; + } + return data; + }, +); + +export const fetchEvmTokenBalances = createAsyncThunk( + "wallet/fetchEvmTokenBalances", + async ({ + evmUrl, + network, + evmAddress, + provider, + tokenIds, + }: { + evmUrl: string; + network: EnvironmentNetwork; + evmAddress: string; + provider: providers.JsonRpcProvider | null; + tokenIds: string[]; + }) => { + // If playground then use rpc calls + if (isPlayground(network) && provider !== null) { + const tokens = tokenIds.map(async (id) => { + const address = getAddressFromDST20TokenId(id); + const contract = new ethers.Contract(address, DST20V1.abi, provider); + const balance = await contract.balanceOf(evmAddress); + const decimals = await contract.decimals(); + return { + token: { + decimals, + address, + }, + value: balance.toString(), + }; + }); + const res = await Promise.all(tokens); + return res.filter((each) => each.value !== "0"); + } + + const response = await fetch( + `${evmUrl}/api/v2/addresses/${evmAddress}/token-balances`, + ); + const data = await response.json(); + if (data.message === "Not found") { + return []; + } + return data; + }, +); + +export const evm = createSlice({ + name: "evm", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase( + fetchEvmWalletDetails.fulfilled, + (state, action: PayloadAction) => { + state.evmWalletDetails = action.payload; + }, + ); + builder.addCase( + fetchEvmTokenBalances.fulfilled, + (state, action: PayloadAction) => { + state.evmTokenBalances = action.payload; + state.hasFetchedEvmTokens = true; + }, + ); + }, +}); diff --git a/shared/store/index.ts b/shared/store/index.ts index b67de7067c..d12dce4261 100644 --- a/shared/store/index.ts +++ b/shared/store/index.ts @@ -13,6 +13,7 @@ import { authentication } from "./authentication"; import { loans } from "./loans"; import { auctions } from "./auctions"; import { futureSwaps } from "./futureSwap"; +import { evm } from "./evm"; /** * RootState for DeFiChain Wallet App * @@ -36,6 +37,7 @@ export function initializeStore() { [statusWebsiteSlice.reducerPath]: statusWebsiteSlice.reducer, userPreferences: userPreferences.reducer, futureSwaps: futureSwaps.reducer, + evm: evm.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }) diff --git a/shared/store/userPreferences.ts b/shared/store/userPreferences.ts index e75ebcd445..60161dca87 100644 --- a/shared/store/userPreferences.ts +++ b/shared/store/userPreferences.ts @@ -6,18 +6,25 @@ import { } from "@reduxjs/toolkit"; import { LocalStorageProvider } from "@api/local_storage/provider"; import { EnvironmentNetwork } from "@waveshq/walletkit-core"; +import { DomainType } from "@contexts/DomainContext"; export interface LabeledAddress { - [address: string]: LocalAddress; + [address: string]: LocalAddress | WhitelistedAddress; } -export interface LocalAddress { +export interface WhitelistedAddress { address: string; label: string; - isMine: boolean; + addressDomainType: DomainType; isFavourite?: boolean; } +export interface LocalAddress { + address: string; + evmAddress: string; + label: string; +} + export interface UserPreferences { addresses: LabeledAddress; addressBook: LabeledAddress; @@ -31,8 +38,10 @@ const initialState: UserPreferences = { export const fetchUserPreferences = createAsyncThunk( "userPreferences/fetchUserPreferences", async (network: EnvironmentNetwork) => { - return await LocalStorageProvider.getUserPreferences(network); - } + const { addresses, addressBook } = + await LocalStorageProvider.getUserPreferences(network); + return { addresses, addressBook: prePopulateWhitelistedField(addressBook) }; + }, ); export const setUserPreferences = createAsyncThunk( @@ -45,21 +54,21 @@ export const setUserPreferences = createAsyncThunk( preferences: UserPreferences; }) => { await LocalStorageProvider.setUserPreferences(network, preferences); - } + }, ); export const setAddresses = createAsyncThunk( "userPreferences/setAddresses", async (addresses: LabeledAddress) => { return addresses; - } + }, ); export const setAddressBook = createAsyncThunk( "userPreferences/setAddressBook", async (addressBook: LabeledAddress) => { return addressBook; - } + }, ); export const userPreferences = createSlice({ @@ -83,40 +92,66 @@ export const userPreferences = createSlice({ (state, action: PayloadAction) => { state = action.payload; return state; - } + }, ); builder.addCase( setAddresses.fulfilled, (state, action: PayloadAction) => { state.addresses = action.payload; return state; - } + }, ); builder.addCase( setAddressBook.fulfilled, (state, action: PayloadAction) => { state.addressBook = action.payload; return state; - } + }, ); }, }); export const selectAddressBookArray = createSelector( (state: UserPreferences) => state.addressBook, - (addressBook) => { - return prepopulateField(addressBook); - } + (addressBook): WhitelistedAddress[] => { + return prePopulateField(addressBook) as WhitelistedAddress[]; + }, ); export const selectLocalWalletAddressArray = createSelector( (state: UserPreferences) => state.addresses, - (walletAddress) => { - return prepopulateField(walletAddress); - } + (walletAddress): LocalAddress[] => { + return prePopulateField(walletAddress) as LocalAddress[]; + }, ); -const prepopulateField = (addresses: LabeledAddress): LocalAddress[] => { +// to get wallet label for saved all (DFI and EVM) wallet address, adding all relevant address type in object +export const selectAllLabeledWalletAddress = createSelector( + (state: UserPreferences) => state.addresses, + (walletAddress): LabeledAddress => { + try { + if (walletAddress === undefined) { + return {} as LabeledAddress; + } + return (Object.values(walletAddress) as LocalAddress[]).reduce( + (allAddress, each) => { + return { + ...allAddress, + [each.address]: each, + [each.evmAddress]: each, + }; + }, + {}, + ); + } catch (e) { + return {} as LabeledAddress; + } + }, +); + +const prePopulateField = ( + addresses: LabeledAddress, +): (LocalAddress | WhitelistedAddress)[] => { const _addresses: LabeledAddress = { ...addresses }; // pre-populate address and isFavourite flag for older app version, used for UI data model only @@ -132,3 +167,23 @@ const prepopulateField = (addresses: LabeledAddress): LocalAddress[] => { } return Object.values(_addresses); }; + +const prePopulateWhitelistedField = ( + addressBook: LabeledAddress, +): LabeledAddress => { + const address = Object.values(addressBook); + return (address as WhitelistedAddress[]).reduce( + (all: LabeledAddress, each: WhitelistedAddress) => { + return { + ...all, + [each.address]: { + address: each.address, + label: each.label, + addressDomainType: each.addressDomainType ?? DomainType.DVM, + isFavourite: each.isFavourite, + }, + }; + }, + {}, + ); +}; diff --git a/shared/translations/languages/de.json b/shared/translations/languages/de.json index 8c7b775302..22be1a0a20 100644 --- a/shared/translations/languages/de.json +++ b/shared/translations/languages/de.json @@ -109,7 +109,8 @@ "AVAILABLE ASSETS": "VERFÜGBARE AKTIVA", "Asset value": "Wert der Aktiva", "Sort by": "Sortieren nach", - "ASSETS": "AKTIVA" + "ASSETS": "AKTIVA", + "network": "netzwerk" }, "screens/GetDFIScreen": { "Get DFI": "DFI erhalten", @@ -212,7 +213,8 @@ "Address deleted!": "Adresse gelöscht!", "It may take a few seconds to delete": "Das Löschen kann einige Sekunden dauern", "It may take a few seconds to update": "Die Aktualisierung kann ein paar Sekunden dauern", - "It may take a few seconds to save": "Das Speichern kann ein paar Sekunden dauern" + "It may take a few seconds to save": "Das Speichern kann ein paar Sekunden dauern", + "ADDRESS TYPE": "ADRESSTYP" }, "screens/ReceiveScreen": { "Receive": "Empfangen", @@ -223,7 +225,7 @@ "Copy": "Kopieren", "Share": "Teilen", "WALLET ADDRESS": "WALLETADRESSE", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Verwende den QR-Code oder die Wallet-Adresse, um Token (DST) oder DFI zu erhalten", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "Scanne den QR-Code, um dToken (z.B. DUSD, dBTC...) oder DFI zu erhalten", "Get DFI": "DFI erwerben" }, "components/toaster": { @@ -326,6 +328,7 @@ "Available {{unit}}": "Verfügbare {{unit}}", "Resulting {{unit}}": "Resultierende {{unit}}", "TO RECEIVE": "ZU ERHALTEN", + "TO CONVERT": "UMWANDELN", "tokens": "Token" }, "screens/ConvertConfirmScreen": { @@ -345,11 +348,13 @@ "CONFIRM TRANSACTION": "TRANSAKTION BESTÄTIGEN", "You are converting to {{unit}}": "Du wandelst in {{unit}} um", "Transaction fee": "Transaktionsgebühren", + "Resulting Tokens (EVM)": "Resultierende Token (EVM)", "Resulting Tokens": "Resultierende Token", "Resulting UTXO": "Resultierende UTXO", "Convert {{amount}} DFI to {{target}}": "Wandle {{amount}} DFI in {{target}} um", "Converting": "Umwandeln", - "Converted": "Umgewandelt" + "Converted": "Umgewandelt", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "{{amount}} {{symbolA}}- in {{symbolB}}-Token umwandeln" }, "screens/SettingsNavigator": { "Settings": "Einstellungen" @@ -419,7 +424,9 @@ "Cancel transaction": "Transaktion abbrechen", "By cancelling, you will lose any changes you made for your transaction.": "Wenn du die Transaktion abbrichst, gehen alle Änderungen, die du für deine Transaktion vorgenommen hast, verloren.", "View on Scan": "Ansicht auf Scan", - "Go back": "Zurück" + "Go back": "Zurück", + "Service Providers": "Dienstanbieter", + "Custom (3rd-party)": "Benutzerdefiniert (\"Drittanbieter\")" }, "screens/AboutScreen": { "About": "Über", @@ -538,6 +545,19 @@ "Are there other ways to submit proposals?": "Gibt es noch andere Möglichkeiten, Proposals einzureichen?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "Wenn du eine Full-Node-Wallet besitzt, kannst du die Proposals auch über Befehle per Befehlszeile einreichen. Befehle können auf DeFiScan unter dem Reiter Governance > Submit proposal erstellt werden." }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "HÄUFIG GESTELLTE FRAGEN", + "About MetaChain (EVM)": "MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "Der MetaChain-Layer bietet eine EVM-kompatible Umgebung, die es Entwicklern, die mit Ethereum vertraut sind, ermöglicht, Anwendungen innerhalb des DeFiChain-Ökosystems zu entwickeln.", + "What tokens are supported between DVM and EVM bidirectionally?": "Welche Token werden zwischen DVM und EVM bidirektional unterstützt?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "Alle dToken werden akzeptiert. dToken bestehen aus:\ndStocks (dTSLA, dGOOG.) + DFI\n\nDie vollständige Liste findest du unter https://defiscan.live/tokens unter der Kategorie DAT.", + "How can I access the MetaChain layer from the Light Wallet?": "Wie kann ich von der Lightwallet aus auf den MetaChain-Layer zugreifen?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "Bewege deine dToken zwischen dem nativen Layer von DeFiChain (DVM) und dem MetaChain-Layer (EVM) bidirektional.\n\nÜbertrage z.B. DFI/DUSD/dBTC oder jeden anderen dToken von DVM zu EVM und zurück, alles direkt in der Lightwallet.", + "Why would I need to move dTokens from DVM to EVM?": "Warum sollte ich dToken von DVM zu EVM verschieben?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "Mit dem Gateway kannst du deine dToken von der Lightwallet zu jeder EVM-kompatiblen Wallet auf dem MetaChain-Layer (z. B. MetaMask) verschieben. So kannst du mit dem ständig wachsenden EVM-Ökosystem auf MetaChain und den verschiedenen Projekten interagieren.", + "How can I move dTokens from DVM to EVM?": "Wie kann ich dToken von DVM zu EVM verschieben?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "Du kannst dies entweder über die Funktionen \"Umwandeln\" oder \"Senden\" in der Lightwallet tun. Mit der Option \"Konvertieren\" kannst du alle DVM-dToken in deine eigene EVM-Adresse in der Lightwallet umwandeln (und umgekehrt).\n\nDeine Seed-Phrase kann auch verwendet werden, um deine Lightwallet-EVM-Adresse in externe Wallets zu importieren, die eine 24-Wörter-Wiederherstellungsphrase wie MetaMask unterstützen.\n\nMit der Option \"Senden\" kannst du dToken von deiner DVM-Adresse an eine beliebige EVM-Adresse auf dem MetaChain-Layer senden und umgekehrt. Beachte, dass du deine dToken vor dem Senden nicht umwandeln musst, das geschieht automatisch für dich." + }, "screens/NetworkSelectionScreen": { "NETWORK": "NETZWERK", "Select network": "Netzwerkauswahl", @@ -609,6 +629,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "Handle auf der DEX und verdiene Rewards aus dem Liquiditäts-Mining mit Kryptos und dToken.", "Decentralized loans": "Dezentrale Darlehen", "Access financial opportunities with dTokens minted through decentralized vaults.": "Erhalte Zugang zu finanziellen Gelegenheiten mit dToken, die in dezentralen Vaults gemintet wurden.", + "EVM compatible": "EVM-kompatibel", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "Nahtlose Übertragung zwischen DeFiChain und MetaChain durch generierte EVM-Adresse.", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "Die DeFiChain-Wallet ist völlig non-custodial. Nur du hast Zugang zu deinem Guthaben." }, "screens/CreateMnemonicWallet": { @@ -641,7 +663,8 @@ "Don’t share to anyone. Keep the recovery words only to yourself.": "Teile sie niemandem mit. Nur du solltest den Wiederherstellungssatz kennen.", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "In der nächsten Ansicht werden dir 24 Wiederherstellungswörter angezeigt. Bewahre deine 24 Wiederherstellungswörter sicher auf, denn mit ihnen kannst du den Zugang zur Wallet wiederherstellen.", "Write the words on paper. Take note of their correct spelling and order.": "Schreibe die Wörter auf Papier. Achte auf die richtige Schreibweise und Reihenfolge.", - "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Bewahre sie an einem sicheren Ort auf. Speichere sie offline an einem Ort, zu dem nur du Zugang hast. Schütze sie vor fremden Einblicken und teile sie mit niemandem." + "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Bewahre sie an einem sicheren Ort auf. Speichere sie offline an einem Ort, zu dem nur du Zugang hast. Schütze sie vor fremden Einblicken und teile sie mit niemandem.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "Eine zugeordnete EVM-Adresse wird generiert, um eine nahtlose Übertragung zwischen DeFiChain und MetaChain zu gewährleisten." }, "screens/GuidelinesRecoveryWords": { "What are recovery words?": "Was ist der Wiederherstellungssatz (Seed Phrase)?", @@ -735,7 +758,9 @@ "Display payback DUSD loan with DUSD collateral": "Rückzahlungen von DUSD-Darlehen mit DUSD-Sicherheiten anzeigen", "CFP/DFIP proposal(s)": "CFP/DFIP-Anträge", "Allows the submission of CFP/DFIP proposals": "Ermöglicht die Einreichung von CFP/DFIP-Anträgen", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Nach der Aktivierung kannst du CFP/DFIP-Anträge direkt über den aktiven Account deiner mobilen Lightwallet einreichen. Möchtest du fortfahren?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Nach der Aktivierung kannst du CFP/DFIP-Anträge direkt über den aktiven Account deiner mobilen Lightwallet einreichen. Möchtest du fortfahren?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Die Beta-Funktionen der Lightwallet befinden sich in der Endphase der Tests, bevor sie offiziell veröffentlicht werden. Die Nutzung der Beta-Funktionen wird empfohlen, aber bei der Verwendung deiner Aktiva ist Vorsicht geboten.", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "Ermöglicht die Anpassung der Dienstanbieter für DVM und EVM. Gehe mit Vorsicht vor." }, "BottomTabNavigator": { "Balances": "Guthaben", @@ -828,7 +853,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Darlehensaufnahme von {{amount}} {{symbol}} mit Vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "{{amount}} {{symbol}} ausgeliehen", "Requested amount is higher than available amount.": "Der beantragte Betrag ist höher als der verfügbare Betrag.", - "tokens": "Token" + "tokens": "Token", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "Umwandlung von {{amount}} {{symbolA}}- in {{symbolB}}-Token", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} {{symbolA}}- in {{symbolB}}-Token umgewandelt" }, "components/BarCodeScanner": { "Requesting for camera permission": "Kameranutzung erlauben", @@ -838,6 +865,10 @@ "HALF": "1/2", "MAX": "MAX" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "Resultierende UTXO", + "Resulting Tokens": "Resultierende Token" + }, "screens/common": { "CANCEL": "ABBRECHEN", "Cancel": "Abbrechen", @@ -2137,6 +2168,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "Das Hinzufügen von betrügerischen Dienstanbietern kann zu unwiederbringlichen Guthaben führen. Du handelst auf eigenes Risiko.", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "Bitte füge lediglich vertrauenswürdige und gesicherte URLs hinzu. Das Hinzufügen von betrügerischen Dienstanbietern kann zu unwiederbringlichen Guthaben führen. Die Änderungen werden erst nach einem manuellen Neustart der App wirksam.", "Adding custom service provider": "Hinzufügen eines benutzerdefinierten Dienstanbieters", + "Adding custom service providers": "Hinzufügen eines benutzerdefinierten Dienstanbieters", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "Hiermit kehrst du zum Standard-Endpunkt der Lightwallet zurück. Willst du fortfahren?", "Enter passcode to continue": "Passwort eingeben, um fortzufahren", "Invalid URL": "Ungültige URL", @@ -2147,7 +2179,17 @@ "Reset Service Provider": "Dienstanbieter zurücksetzen", "Go back": "Zurück", "GO BACK": "ZURÜCK", - "Reset": "Zurücksetzen" + "Reset": "Zurücksetzen", + "Save changes": "Änderungen sichern", + "Custom Service Provider": "Benutzerdefinierte Dienstanbieter", + "Reset providers": "Dienstanbieter zurücksetzen", + "ENDPOINT URL (DVM)": "ENDPUNKT-URL (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "Wird verwendet, um den Native-DFC-Saldo (MainNet und TestNet) abzurufen", + "ENDPOINT URL (EVM)": "ENDPUNKT-URL (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "Wird verwendet, um den EVM-Saldo (MainNet und TestNet) abzurufen", + "ENDPOINT URL (ETH-RPC)": "ENDPUNKT-URL (ETH-RPC)", + "Used to get Nonce and Chain ID": "Wird verwendet, um Nonce und Chain ID abzurufen", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "Füge nur URLs hinzu, die vollständig vertrauenswürdig und sicher sind. Das Hinzufügen von bösartigen Dienstanbietern kann dazu führen, dass Guthaben unwiederbringlich verloren gehen. Das Vorgehen erfolgt auf eigene Gefahr." }, "components/QuickBid": { "QUICK BID": "SCHNELLES GEBOT", @@ -2194,7 +2236,9 @@ "Swap": "Tausch", "Transactions": "Transaktionen", "Future swap": "Future Swap", - "Get DFI": "DFI erhalten" + "Get DFI": "DFI erhalten", + "Convert": "Umwandeln", + "Governance": "Governance" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "{{poolPair}}-Pool", diff --git a/shared/translations/languages/es.json b/shared/translations/languages/es.json index 3437080c7d..89f6dd06d3 100644 --- a/shared/translations/languages/es.json +++ b/shared/translations/languages/es.json @@ -112,7 +112,8 @@ "AVAILABLE ASSETS": "ACTIVOS DISPONIBLES", "Asset value": "Valor del activo", "Sort by": "Ordenar por", - "ASSETS": "ACTIVOS" + "ASSETS": "ACTIVOS", + "network": "red" }, "screens/GetDFIScreen": { "Get DFI": "Obtener DFI", @@ -221,7 +222,8 @@ "Address deleted!": "Dirección borrada!", "It may take a few seconds to delete": "Puede tardar unos segundos en borrarse", "It may take a few seconds to update": "Puede tardar unos segundos en actualizarse", - "It may take a few seconds to save": "Puede tardar unos segundos en guardarse" + "It may take a few seconds to save": "Puede tardar unos segundos en guardarse", + "ADDRESS TYPE": "ADDRESS TYPE" }, "screens/ReceiveScreen": { "Receive": "Recibir", @@ -232,7 +234,7 @@ "Copy": "Copiar", "Share": "Compartir", "WALLET ADDRESS": "DIRECCIÓN DE LA BILLETERA", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Usar QR or direccion de billetera para recibir cualquier token (DST) o DFI", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI", "Get DFI": "Get DFI" }, "components/toaster": { @@ -336,7 +338,8 @@ "Available {{unit}}": "Disponible {{unit}}", "Resulting {{unit}}": "Resultando {{unit}}", "TO RECEIVE": "A RECIBIR", - "tokens": "tokens" + "tokens": "tokens", + "TO CONVERT": "TO CONVERT" }, "screens/ConvertConfirmScreen": { "Confirm": "Confirmar", @@ -355,11 +358,13 @@ "CONFIRM TRANSACTION": "CONFIRMAR TRANSACCIÓN", "You are converting to {{unit}}": "Esta convirtiendo a {{unit}}", "Transaction fee": "Comisión de transacción", + "Resulting Tokens (EVM)": "Resultando Tokens (EVM)", "Resulting Tokens": "Resultando Tokens", "Resulting UTXO": "Resultando UTXO", "Convert {{amount}} DFI to {{target}}": "Convirtiendo {{amount}} DFI a {{target}}", "Converting": "Convirtiendo", - "Converted": "Convertido" + "Converted": "Convertido", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens" }, "screens/SettingsNavigator": { "Settings": "Configuración" @@ -432,7 +437,9 @@ "Cancel transaction": "Cancel transaction", "By cancelling, you will lose any changes you made for your transaction.": "By cancelling, you will lose any changes you made for your transaction.", "View on Scan": "View on Scan", - "Go back": "Vuelve atrás" + "Go back": "Vuelve atrás", + "Service Providers": "Service Providers", + "Custom (3rd-party)": "Custom (3rd-party)" }, "screens/AboutScreen": { "About": "Más información", @@ -554,6 +561,19 @@ "Are there other ways to submit proposals?": "Are there other ways to submit proposals?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal." }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "PREGUNTAS FRECUENTES", + "About MetaChain (EVM)": "About MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.", + "What tokens are supported between DVM and EVM bidirectionally?": "What tokens are supported between DVM and EVM bidirectionally?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.", + "How can I access the MetaChain layer from the Light Wallet?": "How can I access the MetaChain layer from the Light Wallet?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.", + "Why would I need to move dTokens from DVM to EVM?": "Why would I need to move dTokens from DVM to EVM?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.", + "How can I move dTokens from DVM to EVM?": "How can I move dTokens from DVM to EVM?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you." + }, "screens/NetworkSelectionScreen": { "NETWORK": "RED", "Select network": "Seleccionar red", @@ -625,6 +645,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "Intercambia tokens para obtener recompensas del liquidity mining con los tokens descentralizados.", "Decentralized loans": "Préstamos descentralizados", "Access financial opportunities with dTokens minted through decentralized vaults.": "Crea y accede a nuevos dTokens usando Vaults sobre-colateralizados", + "EVM compatible": "EVM compatible", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "Seamless transfers between DeFiChain and MetaChain via generated EVM address.", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "La Billeter DeFiChain es non-custodial. Solo tu tendrás acceso a tus fondos." }, "screens/CreateMnemonicWallet": { @@ -660,7 +682,8 @@ "Create wallet": "Crear Billetera", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "Vas a ver 24 palabras de recuperación en la siguiente pantalla. Manten estas 24 palabras de recuperación seguras ya que estas te permitiran recuperar el acceso a tu billetera.", "Write the words on paper. Take note of their correct spelling and order.": "Escribe las palabras en papel. Manten el orden y la ortografía correctos.", - "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Guardalas en un lugar seguro. Mantenlas offline en un sitio al que solo tu tengas acceso. Mantenlas privadas y no las compartas con nadie." + "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Guardalas en un lugar seguro. Mantenlas offline en un sitio al que solo tu tengas acceso. Mantenlas privadas y no las compartas con nadie.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain." }, "screens/GuidelinesRecoveryWords": { "What are recovery words?": "Qúe son las palabras de recuperación?(Seed Phrase)", @@ -754,7 +777,9 @@ "Display payback DUSD loan with DUSD collateral": "Mostrar pago de préstamo de DUSD con el DUSD del colateral", "CFP/DFIP proposal(s)": "CFP/DFIP proposal(s)", "Allows the submission of CFP/DFIP proposals": "Allows the submission of CFP/DFIP proposals", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "Allows to customize the service providers for both DVM and EVM. Proceed with caution." }, "BottomTabNavigator": { "Balances": "Saldos", @@ -847,7 +872,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "Borrowed {{amount}} {{symbol}}", "Requested amount is higher than available amount.": "Requested amount is higher than available amount.", - "tokens": "tokens" + "tokens": "tokens", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} {{symbolA}} converted to {{symbolB}} tokens" }, "components/BarCodeScanner": { "Requesting for camera permission": "Pidiendo acceso a la cámara", @@ -2170,6 +2197,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "Añadir proveedores de servicio malignos puede resultar en la perdida de los fondos. Actua bajo tu propia responsabilidad.", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "Añade solo URLs en las que tengas plena confianza y sean seguras.", "Adding custom service provider": "Añadiendo proveedor de servicios personalizado", + "Adding custom service providers": "Añadiendo proveedor de servicios personalizado", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "i procedes, tu proveedor de servicio será revertido al del Light Wallet. Quieres continuar?", "Enter passcode to continue": "Passwort eingeben, um fortzufahren", "Invalid URL": "URL no válida", @@ -2180,7 +2208,17 @@ "Reset Service Provider": "Reset Service Provider", "Go back": "Go back", "GO BACK": "GO BACK", - "Reset": "Reset" + "Reset": "Reset", + "Save changes": "Guardar cambios", + "Custom Service Provider": "Custom Service Provider", + "Reset providers": "Reset providers", + "ENDPOINT URL (DVM)": "ENDPOINT URL (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "Used to get balance from Native DFC (MainNet and TestNet)", + "ENDPOINT URL (EVM)": "ENDPOINT URL (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "Used to get balance from EVM (MainNet and TestNet)", + "ENDPOINT URL (ETH-RPC)": "ENDPOINT URL (ETH-RPC)", + "Used to get Nonce and Chain ID": "Used to get Nonce and Chain ID", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk." }, "components/QuickBid": { "QUICK BID": "OFERTA RAPIDA", @@ -2227,7 +2265,9 @@ "Swap": "Cambiar", "Transactions": "Transacciones", "Future swap": "Cambio a futuros", - "Get DFI": "Obtener DFI" + "Get DFI": "Obtener DFI", + "Convert": "Convertir", + "Governance": "Governance" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "{{poolPair}} Pool", @@ -2258,6 +2298,10 @@ "Search with token name": "Buscar por nombre de token", "Search results for “{{searchTerm}}”": "Buscar resultados para “{{searchTerm}}”" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "Resultando UTXO", + "Resulting Tokens": "Resultando Tokens" + }, "screens/OCGProposalsScreen": { "Governance": "Governance", "Community Funding Proposal": "Community Funding Proposal", diff --git a/shared/translations/languages/fr.json b/shared/translations/languages/fr.json index 40bfe5b8d2..90977eab50 100644 --- a/shared/translations/languages/fr.json +++ b/shared/translations/languages/fr.json @@ -109,7 +109,8 @@ "AVAILABLE ASSETS": "ACTIFS DISPONIBLES", "Asset value": "Valeur des actifs", "Sort by": "Trier par", - "ASSETS": "ACTIFS" + "ASSETS": "ACTIFS", + "network": "réseau" }, "screens/GetDFIScreen": { "Get DFI": "Obtenir DFI", @@ -215,7 +216,8 @@ "Address deleted!": "Adresse supprimée !", "It may take a few seconds to delete": "La suppression peut prendre quelques secondes", "It may take a few seconds to update": "La mise à jour peut prendre quelques secondes", - "It may take a few seconds to save": "La sauvegarde peut prendre quelques secondes" + "It may take a few seconds to save": "La sauvegarde peut prendre quelques secondes", + "ADDRESS TYPE": "TYPE D’ADRESSE" }, "screens/AddressControlScreen": { "CREATE WALLET ADDRESS": "CRÉER UNE ADRESSE DE PORTEFEUILLE", @@ -233,7 +235,7 @@ "Copy": "Copier", "Share": "Partager", "WALLET ADDRESS": "ADRESSE DU PORTEFEUILLE", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Utiliser l'adresse QR ou Wallet pour recevoir des tokens (DST) ou des DFI", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "Scanner le code QR pour recevoir des dTokens (par exemple DUSD, dBTC..) ou des DFI", "Get DFI": "Obtenir DFI" }, "components/toaster": { @@ -336,6 +338,7 @@ "Available {{unit}}": "{{unit}} Disponible", "Resulting {{unit}}": "{{unit}} Restants", "TO RECEIVE": "A RECEVOIR", + "TO CONVERT": "CONVERTIR", "tokens": "tokens" }, "screens/ConvertConfirmScreen": { @@ -355,11 +358,13 @@ "CONFIRM TRANSACTION": "VALIDEZ LA TRANSACTION", "You are converting to {{unit}}": "Vous convertissez en {{unit}}", "Transaction fee": "Frais de transaction", + "Resulting Tokens (EVM)": "Tokens restants (EVM)", "Resulting Tokens": "Tokens restants", "Resulting UTXO": "UTXO restants", "Convert {{amount}} DFI to {{target}}": "Conversion de {{amount}} DFI en {{target}}", "Converting": "Conversion", - "Converted": "Converti" + "Converted": "Converti", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "Convertir {{montant}} de tokens {{symbolA}} en {{symbolB}}" }, "screens/SettingsNavigator": { "Settings": "Paramètres" @@ -429,7 +434,9 @@ "Cancel transaction": "Annuler la transaction", "By cancelling, you will lose any changes you made for your transaction.": "En annulant, vous perdrez toutes les modifications apportées à votre transaction.", "View on Scan": "Voir sur Scan", - "Go back": "Retour" + "Go back": "Retour", + "Service Providers": "Fournisseurs de services", + "Custom (3rd-party)": "Personnalisé (tierce partie)" }, "screens/AboutScreen": { "About": "A propos de l'appli", @@ -465,7 +472,7 @@ "Liquidity Mining": "Liquidity mining", "Liquidity mining": "Liquidity mining", "UTXO and Tokens": "UTXO et tokens", - "Governance": "Governance" + "Governance": "Gouvernance" }, "components/UtxoVsTokenFaq": { "About UTXO And Tokens": "UTXO et tokens", @@ -548,6 +555,19 @@ "Are there other ways to submit proposals?": "Existe-t-il d'autres façons de soumettre des propositions ?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "Si vous possédez un portefeuille de nœud complet, vous pouvez également choisir de soumettre en utilisant des commandes via ILC. Les commandes peuvent être générées sur DeFiScan, sous l'onglet Governance > Submit proposal." }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "FOIRE AUX QUESTIONS", + "About MetaChain (EVM)": "MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "La couche MetaChain fournit un environnement compatible avec l'EVM qui permet aux développeurs connaissant Ethereum de créer des applications au sein de l'écosystème DeFiChain.", + "What tokens are supported between DVM and EVM bidirectionally?": "Quels tokens sont pris en charge entre DVM et EVM de manière bidirectionnelle ?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "Tous les dTokens sont acceptés. Les dTokens se composent de :\ndStocks (dTSLA, dGOOG.) + DFI\n\nPour la liste complète, vous pouvez vous référer à https://defiscan.live/tokens sur tous les tokens de la catégorie DAT.", + "How can I access the MetaChain layer from the Light Wallet?": "Comment puis-je accéder à la couche MetaChain à partir du portefeuille léger ?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "Déplacez vos dTokens entre la couche native de DeFiChain (DVM) et la couche MetaChain (EVM) de manière bidirectionnelle.\n\nPar exemple, transférez DFI/DUSD/dBTC ou tout autre dToken de DVM à EVM et retour, le tout directement dans le portefeuille léger.", + "Why would I need to move dTokens from DVM to EVM?": "Pourquoi aurais-je besoin de déplacer des dTokens de DVM à EVM ?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "L'utilisation de la passerelle vous permet de déplacer vos dTokens du portefeuille léger vers n'importe quel portefeuille compatible EVM sur la couche MetaChain (ex : MetaMask). Cela vous permettra d'interagir avec l'écosystème EVM en croissance constante sur MetaChain et les différents projets qui s'y trouvent.", + "How can I move dTokens from DVM to EVM?": "Comment puis-je déplacer des dTokens de DVM à EVM?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "Vous pouvez le faire via les fonctions \"Convertir\" ou \"Envoyer\" sur le portefeuille léger. L'option \"Convertir\" vous permet de convertir tous les dTokens sur DVM en votre propre adresse EVM dans le portefeuille léger (et vice-versa).\n\nVotre phrase de récupération peut également être utilisée pour importer l'adresse EVM de votre portefeuille léger dans n'importe quel portefeuille externe qui supporte une phrase de récupération de 24 mots comme MetaMask.\n\nL'option \"Envoyer\" vous permet d'envoyer des dTokens depuis votre adresse DVM vers n'importe quelle adresse EVM sur la couche MetaChain et vice versa. Notez que vous n'avez pas besoin de convertir vos dTokens avant de les envoyer, ce processus le fait automatiquement pour vous." + }, "screens/NetworkSelectionScreen": { "NETWORK": "RÉSEAU", "Select network": "Sélectionnez un réseau", @@ -619,6 +639,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "Négociez sur le DEX et gagnez des récompenses de liquidity mining avec des cryptomonnaies et des dTokens.", "Decentralized loans": "Prêts décentralisés", "Access financial opportunities with dTokens minted through decentralized vaults.": "Accédez à des opportunités financières avec des dTokens mintés par des vaults décentralisés.", + "EVM compatible": "Compatible EVM", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "Transferts transparents entre DeFiChain et MetaChain via l'adresse EVM générée.", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "Le portefeuille DeFiChain est entièrement sans garde. Vous seul aurez accès à votre fonds." }, "screens/CreateMnemonicWallet": { @@ -651,6 +673,7 @@ "I understand it is my responsibility to keep my recovery words secure. Losing them will result in the irrecoverable loss of access to my wallet funds.": "Je comprends qu'il est de ma responsabilité de garder mes mots de récupération en sécurité. Leur perte entraînera la perte irrémédiable de l'accès aux fonds de mon portefeuille.", "Write the words on paper. Take note of their correct spelling and order.": "Prenez note des mots sur papier. Faites bien attention à l'orthographe et à respecter l'ordre.", "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Sécurisez-les dans un endroit sûr. Conservez-les hors ligne et dans un endroit sûr auquel vous êtes le seul à avoir accès. Gardez-les secrets et ne partagez pas avec qui que ce soit.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "Une adresse EVM mappée sera générée pour assurer des transferts transparents entre DeFiChain et MetaChain.", "Don’t share to anyone. Keep the recovery words only to yourself.": "Ne partagez pas avec qui que ce soit. Gardez les mots de récupération uniquement pour vous.", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "Vous verrez apparaître 24 mots de récupération sur l'écran suivant. Gardez en sécurité vos 24 mots de récupération car ils vous permettront de récupérer l'accès au porte-monnaie." }, @@ -747,7 +770,9 @@ "Display payback DUSD loan with DUSD collateral": "Afficher le remboursement du prêt DUSD avec garantie DUSD", "CFP/DFIP proposal(s)": "Proposition(s) CFP/DFIP", "Allows the submission of CFP/DFIP proposals": "Permet la soumission de propositions CFP/DFIP", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Dès l'activation, vous pourrez soumettre des propositions CFP/DFIP directement en utilisant votre compte actif du portefeuille léger mobile. Continuer ?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Dès l'activation, vous pourrez soumettre des propositions CFP/DFIP directement en utilisant votre compte actif du portefeuille léger mobile. Continuer ?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Les fonctions bêta du portefeuille léger sont en phase de test final avant leur lancement officiel. L'utilisation des fonctionnalités bêta est encouragée, mais la prudence est de mise lors de l'utilisation de vos actifs.", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "Permet de personnaliser les fournisseurs de services pour DVM et EVM. Procéder avec prudence." }, "BottomTabNavigator": { "Balances": "Soldes", @@ -840,7 +865,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Emprunt de {{amount}} {{symbol}} avec le vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "{{amount}} {{symbol}} empruntés", "Requested amount is higher than available amount.": "Le montant demandé est supérieur au montant disponible.", - "tokens": "tokens" + "tokens": "tokens", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "Conversion de {{amount}} de tokens {{symbolA}} en {{symbolB}}", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} de tokens {{symbolA}} converti en {{symbolB}}" }, "components/BarCodeScanner": { "Requesting for camera permission": "Demande d'accès à votre caméra", @@ -2151,6 +2178,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "L'ajout de fournisseurs de services malveillants peut entraîner des fonds irrécupérables. Procédez à vos propres risques.", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "N'ajouter que des URL qui sont entièrement fiables et sécurisées. Les modifications ne prennent pas effet tant que vous n'avez pas redémarré manuellement l'application.", "Adding custom service provider": "Ajouter un fournisseur de service personnalisé.", + "Adding custom service providers": "Ajouter un fournisseur de service personnalisé.", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "En faisant cela, vous serez renvoyé au point de terminaison par défaut du portefeuille léger. Continuer ?", "Enter passcode to continue": "Entrez le code d'accès pour continuer", "Invalid URL": "URL non valide", @@ -2161,7 +2189,17 @@ "Reset Service Provider": "Réinitialiser le fournisseur de services", "Go back": "Retour", "GO BACK": "RETOUR", - "Reset": "Réinitialiser" + "Reset": "Réinitialiser", + "Save changes": "Sauvegarder les modifications", + "Custom Service Provider": "Fournisseur de service personnalisé", + "Reset providers": "Réinitialiser les fournisseurs", + "ENDPOINT URL (DVM)": "URL DU POINT DE TERMINAISON (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "Utilisé pour obtenir le solde de DFC natif (MainNet et TestNet)", + "ENDPOINT URL (EVM)": "URL DU POINT DE TERMINAISON (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "Utilisé pour obtenir le solde de l'EVM (MainNet et TestNet)", + "ENDPOINT URL (ETH-RPC)": "URL DU POINT DE TERMINAISON (ETH-RPC)", + "Used to get Nonce and Chain ID": "Utilisé pour obtenir le Nonce et le Chain ID", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "N'ajoutez que des URL entièrement fiables et sécurisées. L'ajout de fournisseurs de services malveillants peut entraîner la perte de fonds. Procédez à vos risques et périls." }, "components/QuickBid": { "QUICK BID": "ENCHÈRE RAPIDE", @@ -2208,7 +2246,9 @@ "Swap": "Échanger", "Transactions": "Transactions", "Future swap": "Échange à terme", - "Get DFI": "Obtenir DFI" + "Get DFI": "Obtenir DFI", + "Convert": "Convertir", + "Governance": "Gouvernance" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "Pool {{poolPair}}", @@ -2239,8 +2279,12 @@ "Search with token name": "Recherche avec le nom du token", "Search results for “{{searchTerm}}”": "Résultats de la recherche pour “{{searchTerm}}”" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "UTXO restants", + "Resulting Tokens": "Tokens restants" + }, "screens/OCGProposalsScreen": { - "Governance": "Governance", + "Governance": "Gouvernance", "Community Funding Proposal": "Community Funding Proposal", "Proposal to build on top of the DeFiChain blockchain, and funded by the Community Development Fund.": "Proposition de construire sur la blockchain DeFiChain, et financée par le fonds de développement communautaire, le Community Development Fund.", "DeFiChain Improvement Proposal": "DeFiChain Improvement Proposal", diff --git a/shared/translations/languages/it.json b/shared/translations/languages/it.json index 2576868be6..832593507f 100644 --- a/shared/translations/languages/it.json +++ b/shared/translations/languages/it.json @@ -114,7 +114,8 @@ "AVAILABLE ASSETS": "ASSET DISPONIBILI", "Asset value": "Valore degli asset", "Sort by": "Sort by", - "ASSETS": "ASSETS" + "ASSETS": "ASSETS", + "network": "rete" }, "screens/GetDFIScreen": { "Get DFI": "Get DFI", @@ -223,7 +224,8 @@ "Address deleted!": "Address deleted!", "It may take a few seconds to delete": "It may take a few seconds to delete", "It may take a few seconds to update": "It may take a few seconds to update", - "It may take a few seconds to save": "It may take a few seconds to save" + "It may take a few seconds to save": "It may take a few seconds to save", + "ADDRESS TYPE": "ADDRESS TYPE" }, "screens/ReceiveScreen": { "Receive": "Ricevi", @@ -234,7 +236,7 @@ "Copy": "Copia", "Share": "Condividi", "WALLET ADDRESS": "INDIRIZZO WALLET", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Use QR or Wallet address to receive any tokens (DST) or DFI", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "扫描二维码以接收任何 dToken(例如 DUSD、dBTC..)或 DFI", "Get DFI": "Get DFI" }, "components/toaster": { @@ -283,7 +285,7 @@ "You are sending": "Stai inviando", "TRANSACTION DETAILS": "DETTAGLI TRANSAZIONE", "Recipient address": "Indirizzo del destinatario", - "Network": "Network", + "Network": "Rete", "Amount": "Importo", "Estimated fee": "Commissione stimata", "Remaining balance": "Saldo rimanente", @@ -337,6 +339,7 @@ "Available {{unit}}": "Disponibile {{unit}}", "Resulting {{unit}}": "Risultato {{unit}}", "TO RECEIVE": "TO RECEIVE", + "TO CONVERT": "TO CONVERT", "tokens": "tokens" }, "screens/ConvertConfirmScreen": { @@ -356,11 +359,13 @@ "CONFIRM TRANSACTION": "CONFERMA LA TRANSAZIONE", "You are converting to {{unit}}": "You are converting to {{unit}}", "Transaction fee": "Transaction fee", + "Resulting Tokens (EVM)": "Risultato Tokens (EVM)", "Resulting Tokens": "Risultato Tokens", "Resulting UTXO": "Risultato UTXO", "Convert {{amount}} DFI to {{target}}": "Conversione {{amount}} DFI in {{target}}", "Converting": "Conversione", - "Converted": "Converted" + "Converted": "Converted", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens" }, "screens/SettingsNavigator": { "Settings": "Impostazioni" @@ -433,7 +438,9 @@ "Cancel transaction": "Cancel transaction", "By cancelling, you will lose any changes you made for your transaction.": "By cancelling, you will lose any changes you made for your transaction.", "View on Scan": "View on Scan", - "Go back": "Torna indietro" + "Go back": "Torna indietro", + "Service Providers": "Service Providers", + "Custom (3rd-party)": "Custom (3rd-party)" }, "screens/AboutScreen": { "About": "Informazioni su", @@ -553,6 +560,19 @@ "Are there other ways to submit proposals?": "Are there other ways to submit proposals?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal." }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "DOMANDE FREQUENTI", + "About MetaChain (EVM)": "About MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.", + "What tokens are supported between DVM and EVM bidirectionally?": "What tokens are supported between DVM and EVM bidirectionally?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.", + "How can I access the MetaChain layer from the Light Wallet?": "How can I access the MetaChain layer from the Light Wallet?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.", + "Why would I need to move dTokens from DVM to EVM?": "Why would I need to move dTokens from DVM to EVM?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.", + "How can I move dTokens from DVM to EVM?": "How can I move dTokens from DVM to EVM?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you." + }, "screens/NetworkSelectionScreen": { "NETWORK": "RETE", "Select network": "Selezionare la rete", @@ -624,6 +644,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "Scambia i token per ottenere rendimenti elevati e guadagna i premi di liquidity mining con i token decentralizzati.", "Decentralized loans": "Prestiti decentralizzati", "Access financial opportunities with dTokens minted through decentralized vaults.": "Conia e accedi a nuovi dToken utilizzando caveau sovra-collateralizzati.", + "EVM compatible": "EVM compatible", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "Seamless transfers between DeFiChain and MetaChain via generated EVM address.", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund." }, "screens/CreateMnemonicWallet": { @@ -659,7 +681,8 @@ "Create wallet": "Create wallet", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.", "Write the words on paper. Take note of their correct spelling and order.": "Write the words on paper. Take note of their correct spelling and order.", - "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone." + "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain." }, "screens/GuidelinesRecoveryWords": { "What are recovery words?": "Cosa sono le parole di recupero (Seed Phrase)?", @@ -753,7 +776,9 @@ "Display payback DUSD loan with DUSD collateral": "Display payback DUSD loan with DUSD collateral", "CFP/DFIP proposal(s)": "CFP/DFIP proposal(s)", "Allows the submission of CFP/DFIP proposals": "Allows the submission of CFP/DFIP proposals", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "Allows to customize the service providers for both DVM and EVM. Proceed with caution." }, "BottomTabNavigator": { "Balances": "Saldi", @@ -846,7 +871,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "Borrowed {{amount}} {{symbol}}", "Requested amount is higher than available amount.": "Requested amount is higher than available amount.", - "tokens": "tokens" + "tokens": "tokens", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} {{symbolA}} converted to {{symbolB}} tokens" }, "components/BarCodeScanner": { "Requesting for camera permission": "Richiesta di accesso alla fotocamera", @@ -2165,6 +2192,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.", "Adding custom service provider": "Adding custom service provider", + "Adding custom service providers": "Adding custom service providers", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?", "Enter passcode to continue": "Inserisci il codice di accesso per continuare", "Invalid URL": "Invalid URL", @@ -2175,7 +2203,17 @@ "Reset Service Provider": "Reset Service Provider", "Go back": "Go back", "GO BACK": "GO BACK", - "Reset": "Reset" + "Reset": "Reset", + "Save changes": "Salva modifiche", + "Custom Service Provider": "Custom Service Provider", + "Reset providers": "Reset providers", + "ENDPOINT URL (DVM)": "ENDPOINT URL (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "Used to get balance from Native DFC (MainNet and TestNet)", + "ENDPOINT URL (EVM)": "ENDPOINT URL (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "Used to get balance from EVM (MainNet and TestNet)", + "ENDPOINT URL (ETH-RPC)": "ENDPOINT URL (ETH-RPC)", + "Used to get Nonce and Chain ID": "Used to get Nonce and Chain ID", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk." }, "components/QuickBid": { "QUICK BID": "OFFERTA RAPIDA", @@ -2222,7 +2260,9 @@ "Swap": "Scambia", "Transactions": "Transazioni", "Future swap": "Future swap", - "Get DFI": "Get DFI" + "Get DFI": "Get DFI", + "Convert": "Converti", + "Governance": "Governance" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "{{poolPair}} Pool", @@ -2253,6 +2293,10 @@ "Search with token name": "Search with token name", "Search results for “{{searchTerm}}”": "Search results for “{{searchTerm}}”" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "Risultato UTXO", + "Resulting Tokens": "Risultato Tokens" + }, "screens/OCGProposalsScreen": { "Governance": "Governance", "Community Funding Proposal": "Community Funding Proposal", diff --git a/shared/translations/languages/zh-Hans.json b/shared/translations/languages/zh-Hans.json index 75b5ac3cdb..0a4508e981 100644 --- a/shared/translations/languages/zh-Hans.json +++ b/shared/translations/languages/zh-Hans.json @@ -109,7 +109,8 @@ "AVAILABLE ASSETS": "可用资产", "Asset value": "资产价值", "Sort by": "Sort by", - "ASSETS": "ASSETS" + "ASSETS": "ASSETS", + "network": "网络" }, "screens/GetDFIScreen": { "Get DFI": "获取 DFI", @@ -210,9 +211,10 @@ "Address saved!": "Address saved!", "Address label updated!": "Address label updated!", "Address deleted!": "Address deleted!", - "It may take a few seconds to delete": "It may take a few seconds to delete", - "It may take a few seconds to update": "It may take a few seconds to update", - "It may take a few seconds to save": "It may take a few seconds to save" + "It may take a few seconds to delete": "可能需要几秒钟进行删除", + "It may take a few seconds to update": "可能需要几秒钟进行更新", + "It may take a few seconds to save": "可能需要几秒钟进行保存", + "ADDRESS TYPE": "地址类型" }, "screens/ReceiveScreen": { "Receive": "接收", @@ -223,7 +225,7 @@ "Copy": "复制地址", "Share": "转发地址", "WALLET ADDRESS": "钱包地址", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Use QR or Wallet address to receive any tokens (DST) or DFI", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "扫描二维码以接收任何 dToken(例如 DUSD、dBTC..)或 DFI", "Get DFI": "获得 DFI" }, "components/toaster": { @@ -258,7 +260,7 @@ "SEND TO": "SEND TO", "Paste address": "Paste address", "I WANT TO SEND": "I WANT TO SEND", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Verified": "Verified", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "Max available {{unit}} entered": "Max available {{unit}} entered", @@ -319,13 +321,14 @@ "I WANT TO CONVERT": "I WANT TO CONVERT", "Insufficient balance": "Insufficient balance", "Available: ": "可转换资金: ", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Max available {{unit}} entered": "Max available {{unit}} entered", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "A small amount of UTXO is reserved for fees": "保留少量 UTXO 用于交易费用", "Available {{unit}}": "可转换资金 {{unit}}", "Resulting {{unit}}": "转换后 {{unit}}", "TO RECEIVE": "TO RECEIVE", + "TO CONVERT": "转换", "tokens": "代币" }, "screens/ConvertConfirmScreen": { @@ -343,13 +346,15 @@ "Convert": "转换", "{{token}} to receive": "{{token}} 将会收到", "CONFIRM TRANSACTION": "确认发出", - "You are converting to {{unit}}": "You are converting to {{unit}}", + "You are converting to {{unit}}": "您正在转换为 {{unit}}", "Transaction fee": "交易費用", + "Resulting Tokens (EVM)": "转换后 Tokens (EVM)", "Resulting Tokens": "转换后 Tokens", "Resulting UTXO": "转换后 UTXO", "Convert {{amount}} DFI to {{target}}": "转换 {{amount}} DFI 至 {{target}}", "Converting": "转换中", - "Converted": "Converted" + "Converted": "Converted", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "转换 {{amount}} {{symbolA}} 到 {{symbolB}} 代币" }, "screens/SettingsNavigator": { "Settings": "设置" @@ -413,14 +418,16 @@ "This will unlink your wallet from the app.": "这将取消您的钱包与应用程式的绑定。", "DISPLAY & LANGUAGE": "显示和语言", "Provide your passcode to\nview recovery words.": "Provide your passcode to\nview recovery words.", - "Passcode verified!": "Passcode verified!", + "Passcode verified!": "密码已验证!", "Provider": "Provider", "Custom": "Custom", "Default": "Default", "Cancel transaction": "Cancel transaction", "By cancelling, you will lose any changes you made for your transaction.": "By cancelling, you will lose any changes you made for your transaction.", "View on Scan": "往 DeFi Scan 查看", - "Go back": "回到上一页" + "Go back": "回到上一页", + "Service Providers": "服务提供商", + "Custom (3rd-party)": "自定义(第三方" }, "screens/AboutScreen": { "About": "关于", @@ -539,6 +546,19 @@ "Are there other ways to submit proposals?": "还有其他的方式提交提案吗?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "如果您拥有全节点钱包,你可以选择通过CLI界面使用命令进行提交。该命令可以在DeFiScan上生成,在\"Governance\" > \"Submit proposal\" 选项里。" }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "常见问题", + "About MetaChain (EVM)": "MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "MetaChain 层提供了一个与 EVM 兼容的环境,允许熟悉以太坊的开发人员在 DeFiChain 生态系统内构建应用程序。", + "What tokens are supported between DVM and EVM bidirectionally?": "DVM 和 EVM 这两个之间支持哪些双向代币?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "所有 dToken 均被接受。 dToken 包括:\ndStocks (dTSLA, dGOOG.) + DFI\n\n有关完整列表,您可以参考 https://defiscan.live/tokens 了解 DAT 类别下的任何代币。", + "How can I access the MetaChain layer from the Light Wallet?": "如何从轻钱包访问MetaChain层?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "在原生 DeFiChain 的原链层 (DVM) 和 MetaChain 层 (EVM) 之间双向移动您的 dToken。\n\n例如,将 DFI/DUSD/dBTC 或任何其他 dToken 从 DVM 转移到 EVM 并返回,所有这些操作都直接在轻钱包内进行。", + "Why would I need to move dTokens from DVM to EVM?": "为什么我需要将 dToken 从 DVM 转移到 EVM?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "使用这路线可以让您将 dToken 从 Light Wallet 移动到 MetaChain 层上的任何 EVM 兼容钱包(例如:MetaMask)。 这将使您能够与 MetaChain 上不断发展的 EVM 生态系统及其上的各种项目进行交互。", + "How can I move dTokens from DVM to EVM?": "如何将 dToken 从 DVM 转移到 EVM?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "您可以通过 Light Wallet 上的\"转换\"或\"发送\"功能来完成此操作。 \"转换\"选项允许您将 DVM 上的任何 dToken 转换为您自己的轻钱包中的 EVM 地址(反之亦然)。\n\n您的助记词还可用于将您的轻钱包 EVM 地址导入任何支持 24 个单词恢复短语(如 MetaMask)的外部钱包。\n\n\"发送\"选项允许您将 dToken 从您的 DVM 地址发送到 MetaChain 层上的任何 EVM 地址,反之亦然。 请注意,您无需在发送前转换 dToken,此过程会自动为您完成。" + }, "screens/NetworkSelectionScreen": { "NETWORK": "网络", "Select network": "切换网络", @@ -610,6 +630,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "在 DEX 上进行交易并使用加密货币和 dToken 从流动性挖矿中获得奖励 ", "Decentralized loans": "去中心化资产贷款", "Access financial opportunities with dTokens minted through decentralized vaults.": "透过去中心化金库铸造的 dToken 获得交易机会", + "EVM compatible": "EVM 兼容", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "通过生成的 EVM 地址在 DeFiChain 和 MetaChain 之间无缝传输。", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "DeFiChain 钱包是完全非托管的。个人资金只供您私人操作。" }, "screens/CreateMnemonicWallet": { @@ -643,7 +665,8 @@ "Create wallet": "Create wallet", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.", "Write the words on paper. Take note of their correct spelling and order.": "Write the words on paper. Take note of their correct spelling and order.", - "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone." + "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "将生成映射的 EVM 地址,以确保 DeFiChain 和 MetaChain 之间的无缝传输。" }, "screens/GuidelinesRecoveryWords": { "What are recovery words?": "「恢复字组」是什么?", @@ -737,7 +760,9 @@ "Display payback DUSD loan with DUSD collateral": "Display payback DUSD loan with DUSD collateral", "CFP/DFIP proposal(s)": "CFP/DFIP 提案", "Allows the submission of CFP/DFIP proposals": "允许提交 CFP/DFIP 提案", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "激活后,您将能够使用您活跃的移动端Light Wallet账户直接提交 CFP/DFIP 提案。 你要继续吗?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "激活后,您将能够使用您活跃的移动端Light Wallet账户直接提交 CFP/DFIP 提案。 你要继续吗?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Light Wallet beta 功能目前在正式发布前进行最终测试。 我们鼓励使用测试版功能,但建议您在使用资产时务必小心。", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "允许为 DVM 和 EVM 自定义服务提供者。 谨慎行事。" }, "BottomTabNavigator": { "Balances": "总资金", @@ -831,7 +856,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "Borrowed {{amount}} {{symbol}}", "Requested amount is higher than available amount.": "您请求的金额高于可用金额。", - "tokens": "代币" + "tokens": "代币", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "正在转换 {{amount}} {{symbolA}} 到 {{symbolB}} 代币 ", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} {{symbolA}} 已经成功转换成 {{symbolB}}代币" }, "components/BarCodeScanner": { "Requesting for camera permission": "请许可程序使用相机", @@ -880,7 +907,7 @@ "Pooled {{symbol}}": "池中总 {{symbol}}", "View pool share": "View pool share", "View pool info": "View pool info", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Insufficient balance": "Insufficient balance", "APR": "APR", "Shares to add": "Shares to add", @@ -1064,9 +1091,9 @@ "You are buying dTokens at 5% more than the oracle price at settlement block.": "You are buying dTokens at 5% more than the oracle price at settlement block.", "You are buying {{displaySymbol}} at 5% more than the oracle price at settlement block.": "You are buying {{displaySymbol}} at 5% more than the oracle price at settlement block.", "You are selling your {{displaySymbol}} at 5% less than the oracle price at settlement block.": "You are selling your {{displaySymbol}} at 5% less than the oracle price at settlement block.", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "By continuing, the required amount of DFI will be converted": "By continuing, the required amount of DFI will be converted", - "I HAVE {{totalAmount}} {{token}}": "I HAVE {{totalAmount}} {{token}}", + "I HAVE {{totalAmount}} {{token}}": "我有 {{totalAmount}} {{token}}", "I WANT {{token}}": "I WANT {{token}}", "incl. stabilization fee ({{dexStabilizationFee}}%)": "incl. stabilization fee ({{dexStabilizationFee}}%)", "Total fees": "Total fees", @@ -1152,7 +1179,7 @@ "Sign to verify access": "签下以确认使用", "Success!": "成功!", "It may take a few seconds to verify": "It may take a few seconds to verify", - "Passcode verified!": "Passcode verified!", + "Passcode verified!": "密码已验证!", "Provide your passcode to view recovery words.": "Provide your passcode to view recovery words.", "Provide existing passcode to change passcode.": "Provide existing passcode to change passcode." }, @@ -1748,7 +1775,7 @@ "Insufficient DFI and/or DUSD in vault to maintain active loans": "Insufficient DFI and/or DUSD in vault to maintain active loans", "Active DUSD loans require 50% DFI collaterals": "Active DUSD loans require 50% DFI collaterals", "By continuing, the required amount of DFI will be converted": "By continuing, the required amount of DFI will be converted", - "Review full details in the next screen": "Review full details in the next screen" + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息" }, "screens/ConfirmEditCollateralScreen": { "You are adding collateral to": "向金库增加抵押品", @@ -1791,7 +1818,7 @@ "I WANT TO PAY": "I WANT TO PAY", "I WANT TO PAY WITH DUSD COLLATERAL": "I WANT TO PAY WITH DUSD COLLATERAL", "Available: ": "现有可使用: ", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Use your DUSD collaterals to fully pay off your DUSD loan.": "Use your DUSD collaterals to fully pay off your DUSD loan.", "Continue": "继续", "Max available {{unit}} entered": "Max available {{unit}} entered", @@ -1880,7 +1907,7 @@ "Amount entered may liquidate the vault. Proceed at your own risk.": "Amount entered may liquidate the vault. Proceed at your own risk.", "Insufficient DFI and/or DUSD in vault. Add more to start minting dTokens.": "Insufficient DFI and/or DUSD in vault. Add more to start minting dTokens.", "Insufficient DFI in vault. Add more to borrow DUSD.": "Insufficient DFI in vault. Add more to borrow DUSD.", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Max loan amount entered": "已输入最高贷款金额", "{{percent}} of max loan amount entered": "已输入最高贷款金额的 {{percent}}%", "SELECT VAULT FOR COLLATERAL": "选择金库抵押", @@ -1951,7 +1978,7 @@ "Continue": "继续", "Confirm your vault details in next screen": "在下一页确认金库的细行", "AVAILABLE SCHEMES": "AVAILABLE SCHEMES", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "VAULT DETAILS": "VAULT DETAILS", "{{interestRate}}% Interest": "{{interestRate}}% Interest", "min. ": "min. ", @@ -2048,7 +2075,7 @@ "The value of the tokens you are placing is considerably higher than the total auction value.": "您正要出的价钱比拍卖价值还高,请检查和确认", "Collateral for auction": "待拍賣的抵押品", "I HAVE {{ownedAmount}} {{symbol}}": "I HAVE {{ownedAmount}} {{symbol}}", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Transaction fee": "Transaction fee", "The minimum next bid is {{amount}} {{symbol}} (100%)": "The minimum next bid is {{amount}} {{symbol}} (100%)", "{{percent}} min bid entered": "{{percent}} 最低竞投出价输入", @@ -2077,7 +2104,7 @@ "Preparing placing {{amount}} {{token}} bid": "Preparing placing {{amount}} {{token}} bid", "Placed {{amount}} {{token}} bid": "Placed {{amount}} {{token}} bid", "It may take a few seconds to verify": "It may take a few seconds to verify", - "Passcode verified!": "Passcode verified!" + "Passcode verified!": "密码已验证!" }, "screens/WithdrawFutureSwapScreen": { "Withdraw": "Withdraw", @@ -2095,7 +2122,7 @@ "Withdraw from": "Withdraw from", "Insufficient Balance": "Insufficient Balance", "Transaction fee": "交易費用", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一个屏幕中查看完整详细信息", "Max available {{unit}} entered": "Max available {{unit}} entered", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "Amount to swap": "Amount to swap", @@ -2147,6 +2174,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "添加恶意服务供应商 可能会导致可收回资金。风险自负", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.", "Adding custom service provider": "添加自定义服务提供者", + "Adding custom service providers": "添加自定义服务提供者", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "这样做,您将恢复到手机轻钱包的预设终端点。你想继续吗?", "Enter passcode to continue": "输入密码后可继续", "Invalid URL": "无效的网址", @@ -2157,7 +2185,17 @@ "Reset Service Provider": "Reset Service Provider", "Go back": "Go back", "GO BACK": "GO BACK", - "Reset": "Reset" + "Reset": "Reset", + "Save changes": "储存修改", + "Custom Service Provider": "自定义服务提供商", + "Reset providers": "Reset 提供商", + "ENDPOINT URL (DVM)": "端点 URL (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "用于从原生DFC(主网和测试网)获取余额", + "ENDPOINT URL (EVM)": "端点 URL (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "用于从EVM(主网和测试网)获取余额", + "ENDPOINT URL (ETH-RPC)": "端点 URL (ETH-RPC)", + "Used to get Nonce and Chain ID": "用于获取Nonce和Chain ID", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "仅添加完全受信任且安全的 URL。 添加恶意服务提供商可能会导致资金无法收回。 继续行动则需要您自担风险。" }, "components/QuickBid": { "QUICK BID": "快速标价", @@ -2204,7 +2242,9 @@ "Swap": "兑换", "Transactions": "交易纪录", "Future swap": "Future swap", - "Get DFI": "获取 DFI" + "Get DFI": "获取 DFI", + "Convert": "转换", + "Governance": "治理" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "Pool {{poolPair}}", @@ -2235,8 +2275,12 @@ "Search with token name": "使用代币名称搜索", "Search results for “{{searchTerm}}”": "Search results for “{{searchTerm}}”" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "转换后 UTXO", + "Resulting Tokens": "转换后 Tokens" + }, "screens/OCGProposalsScreen": { - "Governance": "Governance", + "Governance": "治理", "Community Funding Proposal": "社区资助提案 (CFP)", "Proposal to build on top of the DeFiChain blockchain, and funded by the Community Development Fund.": "该选项是用于搭建在DeFiChain区块链之上且由社区发展基金资助", "DeFiChain Improvement Proposal": "DeFiChain 改进提案 (DFIP)", diff --git a/shared/translations/languages/zh-Hant.json b/shared/translations/languages/zh-Hant.json index 07e6677ccf..bcb6cec15c 100644 --- a/shared/translations/languages/zh-Hant.json +++ b/shared/translations/languages/zh-Hant.json @@ -109,7 +109,8 @@ "AVAILABLE ASSETS": "可用資產", "Asset value": "資產價值", "Sort by": "Sort by", - "ASSETS": "ASSETS" + "ASSETS": "ASSETS", + "network": "網絡" }, "screens/GetDFIScreen": { "Get DFI": "獲取 DFI", @@ -210,9 +211,10 @@ "Address saved!": "Address saved!", "Address label updated!": "Address label updated!", "Address deleted!": "Address deleted!", - "It may take a few seconds to delete": "It may take a few seconds to delete", - "It may take a few seconds to update": "It may take a few seconds to update", - "It may take a few seconds to save": "It may take a few seconds to save" + "It may take a few seconds to delete": "可能需要幾秒鐘進行刪除", + "It may take a few seconds to update": "可能需要幾秒鐘進行更新", + "It may take a few seconds to save": "可能需要幾秒鐘進行保存", + "ADDRESS TYPE": "地址類型" }, "screens/ReceiveScreen": { "Receive": "接收", @@ -223,7 +225,7 @@ "Copy": "複製地址", "Share": "轉發地址", "WALLET ADDRESS": "錢包地址", - "Use QR or Wallet address to receive any tokens (DST) or DFI": "Use QR or Wallet address to receive any tokens (DST) or DFI", + "Scan QR code to receive any dTokens (eg. DUSD,dBTC..) or DFI": "掃描二維碼以接收任何 dToken(例如 DUSD、dBTC..)或 DFI", "Get DFI": "獲得 DFI" }, "components/toaster": { @@ -258,7 +260,7 @@ "SEND TO": "SEND TO", "Paste address": "Paste address", "I WANT TO SEND": "I WANT TO SEND", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Verified": "Verified", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "Max available {{unit}} entered": "Max available {{unit}} entered", @@ -319,13 +321,14 @@ "I WANT TO CONVERT": "I WANT TO CONVERT", "Insufficient balance": "Insufficient balance", "Available: ": "可轉換資金: ", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Max available {{unit}} entered": "Max available {{unit}} entered", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "A small amount of UTXO is reserved for fees": "保留少量 UTXO 用於交易費用", "Available {{unit}}": "可轉換資金 {{unit}}", "Resulting {{unit}}": "轉換後 {{unit}}", "TO RECEIVE": "TO RECEIVE", + "TO CONVERT": "轉換", "tokens": "代幣" }, "screens/ConvertConfirmScreen": { @@ -343,13 +346,15 @@ "Convert": "轉換", "{{token}} to receive": "{{token}} 將會收到", "CONFIRM TRANSACTION": "確認交易", - "You are converting to {{unit}}": "You are converting to {{unit}}", + "You are converting to {{unit}}": "您正在轉換為 {{unit}}", "Transaction fee": "交易費用", + "Resulting Tokens (EVM)": "轉換後 Tokens (EVM)", "Resulting Tokens": "轉換後 Tokens", "Resulting UTXO": "轉換後 UTXO", "Convert {{amount}} DFI to {{target}}": "轉換 {{amount}} DFI 至 {{target}}", "Converting": "轉換中", - "Converted": "Converted" + "Converted": "Converted", + "Convert {{amount}} {{symbolA}} to {{symbolB}} tokens": "轉換 {{amount}} {{symbolA}} 到 {{symbolB}} 代幣" }, "screens/SettingsNavigator": { "Settings": "設定" @@ -420,7 +425,9 @@ "Cancel transaction": "Cancel transaction", "By cancelling, you will lose any changes you made for your transaction.": "By cancelling, you will lose any changes you made for your transaction.", "View on Scan": "往 DeFi Scan 查看", - "Go back": "回到上一頁" + "Go back": "回到上一頁", + "Service Providers": "服務提供者", + "Custom (3rd-party)": "自定義(第三方)" }, "screens/AboutScreen": { "About": "關於", @@ -539,6 +546,19 @@ "Are there other ways to submit proposals?": "還有其他的方式提交提案嗎?", "If you own a full node wallet, you may also choose to submit using commands via CLI. Commands can be generated on DeFiScan, under Governance tab > Submit proposal.": "如果您擁有全節點錢包,你可以選擇通過CLI界面使用命令進行提交。該命令可以在DeFiScan上生成,在\"Governance\" > \"Submit proposal\" 選項裡。" }, + "components/EvmFeatureFaq": { + "FREQUENTLY ASKED QUESTIONS": "常見問題", + "About MetaChain (EVM)": "MetaChain (EVM)", + "The MetaChain layer provides an EVM-compatible environment that allows developers familiar with Ethereum to build applications inside the DeFiChain ecosystem.": "MetaChain 層提供了一個與EVM 兼容的環境,允許熟悉以太坊的開發人員在DeFiChain 生態系統內構建應用程序。", + "What tokens are supported between DVM and EVM bidirectionally?": "DVM 和 EVM 這兩個之間支持哪些雙向代幣?", + "All dTokens are accepted. dTokens consist of:\ndStocks (dTSLA, dGOOG.) + DFI\n\nFor the full list, you may refer to https://defiscan.live/tokens on any tokens under DAT category.": "所有 dToken 均被接受。 dToken 包括:\ndStocks (dTSLA, dGOOG.) + DFI\n\n有關完整列表,您可以參考https://defiscan.live/tokens 了解DAT 類別下的任何代幣。", + "How can I access the MetaChain layer from the Light Wallet?": "如何從輕錢包訪問MetaChain層?", + "Move your dTokens between native DeFiChain's native layer (DVM) and the MetaChain layer (EVM) bidirectionally.\n\nFor instance, transfer DFI/DUSD/dBTC or any other dToken from DVM to EVM and back, all directly within the Light Wallet.": "在原生 DeFiChain 的原鏈層 (DVM) 和 MetaChain 層 (EVM) 之間雙向移動您的 dToken。\n\n例如,將DFI/DUSD/dBTC 或任何其他dToken 從DVM 轉移到EVM 並返回,所有這些操作都直接在輕錢包內進行。", + "Why would I need to move dTokens from DVM to EVM?": "為什麼我需要將 dToken 從 DVM 轉移到 EVM?", + "Using the gateway allows you to move your dTokens from the Light Wallet to any EVM compatible wallet on the MetaChain layer (ex: MetaMask). This would allow you to interact with the constantly growing EVM ecosystem on MetaChain and the various projects on it.": "使用這路線可以讓您將dToken 從Light Wallet 移動到MetaChain 層上的任何EVM 兼容錢包(例如:MetaMask)。這將使您能夠與 MetaChain 上不斷發展的 EVM 生態系統及其上的各種項目進行交互。", + "How can I move dTokens from DVM to EVM?": "如何將 dToken 從 DVM 轉移到 EVM?", + "You can do it through either the \"Convert\" or \"Send\" functions on Light Wallet. The \"Convert\" option allows you to convert any dTokens on DVM to your own EVM address within the Light Wallet (and vice versa).\n\nYour seed phrase can also be used to import your Light Wallet EVM address into any external wallets which support a 24 words recovery phrase like MetaMask.\n\nThe \"Send\" option allows you to send dTokens from your DVM address to any EVM address on the MetaChain layer and vice versa. Note that you do not need to convert your dTokens before sending, this process does it automatically for you.": "您可以通過Light Wallet 上的\"轉換\"或\"發送\"功能來完成此操作。 \"轉換\"選項允許您將 DVM 上的任何 dToken 轉換為您自己的輕錢包中的 EVM 地址(反之亦然)。\n\n您的助記詞還可用於將您的輕錢包EVM 地址導入任何支持24 個單詞恢復短語(如MetaMask)的外部錢包。\n\n\"發送\"選項允許您將dToken 從您的DVM 地址發送到MetaChain 層上的任何EVM 地址,反之亦然。請注意,您無需在發送前轉換 dToken,此過程會自動為您完成。" + }, "screens/NetworkSelectionScreen": { "NETWORK": "網絡", "Select network": "切換網絡", @@ -610,6 +630,8 @@ "Trade on the DEX and earn rewards from liquidity mining with crypto and dTokens.": "在 DEX 上進行交易並使用加密貨幣和 dToken 從流動性挖礦中獲得獎勵 ", "Decentralized loans": "去中心化資產貸款", "Access financial opportunities with dTokens minted through decentralized vaults.": "透過去中心化金庫鑄造的 dToken 獲得交易機會", + "EVM compatible": "EVM 兼容", + "Seamless transfers between DeFiChain and MetaChain via generated EVM address.": "通過生成的 EVM 地址在 DeFiChain 和 MetaChain 之間無縫傳輸。", "DeFiChain Wallet is fully non-custodial. Only you will have access to your fund.": "DeFiChain 錢包是完全非託管的。 個人資金只供您私人操作。" }, "screens/CreateMnemonicWallet": { @@ -643,7 +665,8 @@ "Create wallet": "Create wallet", "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.": "You will be shown 24 recovery words on the next screen. Keep your 24-word recovery safe as it will allow you to recover access to the wallet.", "Write the words on paper. Take note of their correct spelling and order.": "Write the words on paper. Take note of their correct spelling and order.", - "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone." + "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.": "Secure them in a safe place. Store them offline at a place only you have access. Keep them private and do not share it with anyone.", + "A mapped EVM address will be generated to ensure seamless transfers between DeFiChain and MetaChain.": "將生成映射的 EVM 地址,以確保 DeFiChain 和 MetaChain 之間的無縫傳輸。" }, "screens/GuidelinesRecoveryWords": { "What are recovery words?": "「恢復字組」是什麼?", @@ -737,7 +760,9 @@ "Display payback DUSD loan with DUSD collateral": "Display payback DUSD loan with DUSD collateral", "CFP/DFIP proposal(s)": "CFP/DFIP 提案", "Allows the submission of CFP/DFIP proposals": "允許提交 CFP/DFIP 提案", - "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "激活後,您將能夠使用您活躍的移動端Light Wallet賬戶直接提交 CFP/DFIP 提案。你要繼續嗎?" + "Upon activation, you will be able to submit CFP/DFIP proposals directly using your active mobile Light Wallet account. Do you want to continue?": "激活後,您將能夠使用您活躍的移動端Light Wallet賬戶直接提交 CFP/DFIP 提案。你要繼續嗎?", + "Light Wallet beta features are in final testing before their official release. Using beta features are encouraged, but caution is advised when using your assets.": "Light Wallet beta 功能目前在正式發布前進行最終測試。 我們鼓勵使用測試版功能,但建議您在使用資產時務必小心。", + "Allows to customize the service providers for both DVM and EVM. Proceed with caution.": "允許為 DVM 和 EVM 自訂服務提供者。 謹慎行事。" }, "BottomTabNavigator": { "Balances": "總資金", @@ -831,7 +856,9 @@ "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}": "Borrowing {{amount}} {{symbol}} with vault {{vaultId}}", "Borrowed {{amount}} {{symbol}}": "Borrowed {{amount}} {{symbol}}", "Requested amount is higher than available amount.": "您請求的金額高於可用金額。", - "tokens": "代幣" + "tokens": "代幣", + "Converting {{amount}} {{symbolA}} to {{symbolB}} tokens": "正在轉換 {{amount}} {{symbolA}} 到 {{symbolB}} 代幣", + "{{amount}} {{symbolA}} converted to {{symbolB}} tokens": "{{amount}} {{symbolA}} 已經成功轉換成 {{symbolB}}代幣" }, "components/BarCodeScanner": { "Requesting for camera permission": "請許可程序使用相機", @@ -880,7 +907,7 @@ "Pooled {{symbol}}": "池中總 {{symbol}}", "View pool share": "View pool share", "View pool info": " 查看流動池資料", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Insufficient balance": "Insufficient balance", "APR": "APR", "Shares to add": "要添加的股份", @@ -1064,9 +1091,9 @@ "You are buying dTokens at 5% more than the oracle price at settlement block.": "You are buying dTokens at 5% more than the oracle price at settlement block.", "You are buying {{displaySymbol}} at 5% more than the oracle price at settlement block.": "You are buying {{displaySymbol}} at 5% more than the oracle price at settlement block.", "You are selling your {{displaySymbol}} at 5% less than the oracle price at settlement block.": "You are selling your {{displaySymbol}} at 5% less than the oracle price at settlement block.", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "By continuing, the required amount of DFI will be converted": "By continuing, the required amount of DFI will be converted", - "I HAVE {{totalAmount}} {{token}}": "I HAVE {{totalAmount}} {{token}}", + "I HAVE {{totalAmount}} {{token}}": "我有 {{totalAmount}} {{token}}", "I WANT {{token}}": "I WANT {{token}}", "incl. stabilization fee ({{dexStabilizationFee}}%)": "incl. stabilization fee ({{dexStabilizationFee}}%)", "Total fees": "Total fees", @@ -1750,7 +1777,7 @@ "Insufficient DFI and/or DUSD in vault to maintain active loans": "Insufficient DFI and/or DUSD in vault to maintain active loans", "Active DUSD loans require 50% DFI collaterals": "Active DUSD loans require 50% DFI collaterals", "By continuing, the required amount of DFI will be converted": "By continuing, the required amount of DFI will be converted", - "Review full details in the next screen": "Review full details in the next screen" + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息" }, "screens/ConfirmEditCollateralScreen": { "You are adding collateral to": "您正在加入抵押到", @@ -1793,7 +1820,7 @@ "I WANT TO PAY": "I WANT TO PAY", "I WANT TO PAY WITH DUSD COLLATERAL": "I WANT TO PAY WITH DUSD COLLATERAL", "Available: ": "現有可使用: ", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Use your DUSD collaterals to fully pay off your DUSD loan.": "Use your DUSD collaterals to fully pay off your DUSD loan.", "Continue": "繼續", "Max available {{unit}} entered": "Max available {{unit}} entered", @@ -1882,7 +1909,7 @@ "Amount entered may liquidate the vault. Proceed at your own risk.": "Amount entered may liquidate the vault. Proceed at your own risk.", "Insufficient DFI and/or DUSD in vault. Add more to start minting dTokens.": "Insufficient DFI and/or DUSD in vault. Add more to start minting dTokens.", "Insufficient DFI in vault. Add more to borrow DUSD.": "Insufficient DFI in vault. Add more to borrow DUSD.", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Max loan amount entered": "已輸入最高貸款金額的", "{{percent}} of max loan amount entered": "已輸入最高貸款金額的 {{percent}}%", "SELECT VAULT FOR COLLATERAL": "選擇金庫抵押", @@ -1953,7 +1980,7 @@ "Continue": "繼續", "Confirm your vault details in next screen": "請在下一頁確認金庫細項", "AVAILABLE SCHEMES": "AVAILABLE SCHEMES", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "VAULT DETAILS": "VAULT DETAILS", "{{interestRate}}% Interest": "{{interestRate}}% Interest", "min. ": "min. ", @@ -2049,7 +2076,7 @@ "The value of the tokens you are placing is considerably higher than the total auction value.": "您正要出的價錢比拍賣價值還高,請檢查和確認", "Collateral for auction": "待拍賣的抵押品", "I HAVE {{ownedAmount}} {{symbol}}": "I HAVE {{ownedAmount}} {{symbol}}", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Transaction fee": "Transaction fee", "The minimum next bid is {{amount}} {{symbol}} (100%)": "The minimum next bid is {{amount}} {{symbol}} (100%)", "{{percent}} min bid entered": "{{percent}} 最低競投出價輸入", @@ -2096,7 +2123,7 @@ "Withdraw from": "Withdraw from", "Insufficient Balance": "Insufficient Balance", "Transaction fee": "交易費用", - "Review full details in the next screen": "Review full details in the next screen", + "Review full details in the next screen": "在下一個屏幕中查看完整詳細信息", "Max available {{unit}} entered": "Max available {{unit}} entered", "{{percent}} of available {{unit}} entered": "{{percent}} of available {{unit}} entered", "Amount to swap": "Amount to swap", @@ -2148,6 +2175,7 @@ "Adding malicious service providers may result in irrecoverable funds. Please proceed at your own risk.": "添加惡意服務供應商 可能會導致可收回資金。 風險自負", "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.": "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Changes do not take effect until you manually restart the app.", "Adding custom service provider": "添加自定義服務提供者", + "Adding custom service providers": "添加自定義服務提供者", "In doing so, you will be reverted back to Light wallet's default endpoint. Would you like to continue?": "這樣做,您將恢復到手機輕錢包的預設終端點。 你想繼續嗎?", "Enter passcode to continue": "輸入密碼後可繼續", "Invalid URL": "無效的網址", @@ -2158,7 +2186,17 @@ "Reset Service Provider": "Reset Service Provider", "Go back": "Go back", "GO BACK": "GO BACK", - "Reset": "Reset" + "Reset": "Reset", + "Save changes": "儲存修改", + "Custom Service Provider": "自定義服務供應商", + "Reset providers": "Reset 供應商", + "ENDPOINT URL (DVM)": "端點 URL (DVM)", + "Used to get balance from Native DFC (MainNet and TestNet)": "用於從原生DFC(主網和測試網)取得餘額", + "ENDPOINT URL (EVM)": "端點 URL (EVM)", + "Used to get balance from EVM (MainNet and TestNet)": "用於從EVM(主網和測試網)取得餘額", + "ENDPOINT URL (ETH-RPC)": "端點 URL (ETH-RPC)", + "Used to get Nonce and Chain ID": "用於取得Nonce和Chain ID", + "Only add URLs that are fully trusted and secured. Adding malicious service providers may result in irrecoverable funds. Proceed at your own risk.": "僅添加完全受信任且安全的 URL。 新增惡意服務提供者可能會導致資金無法收回。 繼續行動則需要您自擔風險。" }, "components/QuickBid": { "QUICK BID": "快速標價", @@ -2205,7 +2243,9 @@ "Swap": "兌換", "Transactions": "交易紀錄", "Future swap": "Future swap", - "Get DFI": "獲取 DFI" + "Get DFI": "獲取 DFI", + "Convert": "轉換", + "Governance": "治理" }, "screens/PoolPairDetailsScreen": { "{{poolPair}} Pool": "Pool {{poolPair}}", @@ -2236,8 +2276,12 @@ "Search with token name": "使用代幣名稱搜索", "Search results for “{{searchTerm}}”": "Search results for “{{searchTerm}}”" }, + "components/ConversionDetailsRow": { + "Resulting UTXO": "轉換後 UTXO", + "Resulting Tokens": "轉換後 Tokens" + }, "screens/OCGProposalsScreen": { - "Governance": "Governance", + "Governance": "治理", "Community Funding Proposal": "社區資助提案 (CFP)", "Proposal to build on top of the DeFiChain blockchain, and funded by the Community Development Fund.": "該選項是用於搭建在DeFiChain區塊鏈之上且由社區發展基金資助", "DeFiChain Improvement Proposal": "DeFiChain 改進提案 (DFIP)", diff --git a/tsconfig.json b/tsconfig.json index 959ca614a1..4cbbc4faf1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,6 +25,8 @@ "@shared-api/*": ["../../shared/api/*"], "@shared-contexts": ["../../shared/contexts"], "@shared-contexts/*": ["../../shared/contexts/*"], + "@shared-contracts": ["../../shared/contracts"], + "@shared-contracts/*": ["../../shared/contracts/*"], "@shared-types": ["../../shared/types"], "@shared-types/*": ["../../shared/types/*"], "@screens/*": ["screens/*"],