From 855c405ba5cda81b3c32f700a7f578a22cab2322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Mon, 6 Mar 2023 14:46:39 +0000 Subject: [PATCH 01/69] feat: add fund wallet component with banxa integration --- src/assets/img/banxa-kintsugi.png | Bin 0 -> 3668 bytes src/assets/locales/en/translation.json | 8 ++ .../FundWallet/FundWallet.style.tsx | 55 ++++++++++++ src/components/FundWallet/FundWallet.tsx | 85 ++++++++++++++++++ src/components/FundWallet/entities.tsx | 74 +++++++++++++++ src/components/FundWallet/index.tsx | 2 + src/components/index.tsx | 2 + src/parts/Topbar/index.tsx | 5 +- 8 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/assets/img/banxa-kintsugi.png create mode 100644 src/components/FundWallet/FundWallet.style.tsx create mode 100644 src/components/FundWallet/FundWallet.tsx create mode 100644 src/components/FundWallet/entities.tsx create mode 100644 src/components/FundWallet/index.tsx diff --git a/src/assets/img/banxa-kintsugi.png b/src/assets/img/banxa-kintsugi.png new file mode 100644 index 0000000000000000000000000000000000000000..8a1767467ec06bbe4f3b69ceaf4307d69c8eea88 GIT binary patch literal 3668 zcmV-a4y*BrP)bNXqL_k`FqJSvAEh$9JfqV=zbMNW<&e?b7&b@oz=Q+1;t$)s$v-jC&pS}O{@Bg*0 z=llL}00R*XJ|?|M+T?lOR#XA(|E@e-O*)IzkF=gNi}VQl(1wU$p7R}2pRA$}NlW;w z|Dpo0{eyWpf#hXeevR!m6u7UO>DOLaMJdt?q*ZLgM`?Z8gNHLnU9yT=NRP6;cMvri z8oFV>?la(de6D{0d~ZE!FdGNg{T`KoFVo~lixg=K=~mKSh!JexBi-ZZ!#Ri$Z0~eZ zi{qUak-C)GboxD(S=!x6>Q&(0!RCE!_=I#KN&xHcPI}CD<7z|=-%nsu;{v?c==0b? zFEuvf<>jZM0whSgAzDZRNs?YnTEhW39`Ru)>HDzvVU{Kf(V+*a)=@T=bU7+RSI4#P z`ESE!((8^g^?3ouVQ&6zG*Bn;!NAPun;?`foTG41?}hihS9)%5;9WLpnd?)w}Mt08G=#~RWI z-un@v#Ja}aX-K|7Chv{39h}+oPH*9@BBPJQfVz_U;4+NfCVh+aZAQ3FLGWGwh3evF($NULD%p_za2@-#j{SNiebEoS zFu#VIx!)&U9656fo_7f)b#L>Jz$Jb#uEQQxB*YpumAjj zBTeI&rVuq&uI!B@-M2pHQLU#kh9#N08v~zi49>gtx{H6G&tY;E^^dH+8LSrno zs-lQo8GTBU?&j%C0HuWL72ZEvHWlJPjejYb`ru%s(vn+D?o*}uc*kY%>ccTS;K=R# z5T*q+GF^z_`T5v1^c%%I&ZROOLQ<&xZ4?i+btuB+&-QW1)$}sT0Q;d_nR6Y*b2u3v zWM1I^5Az=7aE!^St9+6h`az@%EoBlI^ZDF&`P?f$x*Qy!i|g z4JqU{%%>Aanad#`>|7393rd7p+U3TwEvE`_EOOkcoQac>t79HTI+OHULlR1~LBn6*MaSC!qwe&Pv|lY)9{PeZEIl%lJ{iXdTMKk4b|q*JVIW5@R{;ldJ4k zjI`=#zM1|^g?AW zR8wSFPR5`?pIYx5IBWx%duAZIJGm5fKXvhqE5DHMvDISm{-lMay3AO=Cqloj4G)u6 zx$ZS7qVlMGHk^!GAIhNO$}&gTFg ziXvc^@k<@Wv&cm6qc|wz(55md%WigDl9c_^l0T8;GG-NExfn6RteATLDs<%^`}uS@!BPL$MFsf9=y4zb`BeIH@R{}d&INDtD=1&w(k~ktBB>_ZQ5qg2-DSD1<$I3N z^&^KF3)um3A=)JQXAs&6qYyo$-p$KXuIIYK`O?Q1b6m=eg@icpVD1j} zWGaRX`9~?u;VZ-BeOk~dcO^XM>X4X&b$`m);1Z_}zSMDD8HY~Y(=fljY@6!vXHwoh ziZ;kqhS12eMN*}|jYqtYs&&7kOp;Qr&I1q;IEGr4Tw^FKLAY~AZZ=n>Q-1U5Wk+Bi ze5MCdZPUrry9N?FnW>&69>c*8i1EH;8gKQ>^%V{M^^7=*HDY0)Rb9(_(rzw!&iG?`z=(VT>eY?#i zlfROaYMa8|^r~NrXP#--5L^@56BT6s8BdAp%ioyCy(eR^ujRS|MbZgBgUTQ|at-WB z^D+iC(W?;?6bLdqgC0Q`){hKqSDVMR*~GOqP=T=t?8D})K7DE;o$^}Q@;k)X+O8(A z)zc^jyB&5Z+LUvij;;IYb$c89MleB*QzChYN~RiW67d3VB4>n&B^j40Y`^F^er!=KU45#V*~cDYj!cXnvTQp zl61`33}JlH^18Ub+djzs!JRlDZ$=&INyG>;$qK%+Qdz}x6{$rg*Ze04S4@{tDaQVJ zz7JQyDL?!z85y9q-B0qY+{Zen7^B^e?X6d!*6T<`@Y8<+>AGvsPM1W;&`BfR#jJXZ zWbi`hw0%vlm&n-4mhdx*GwOAE861Nh(Ei`W)r@2+s&|pYNYqB}7*nkxKU z_D?aGh@*DNyY`#@ha`zx%C95H=vPI_)8Z_O|~bNu9a zm^}NuBcD8*!u>yRhmxa!3>!^gUA~R0EPEH>ME$=Z50A?~>ym0^f0!nHSbGfb&-2V= zo+cFTcl|P%0(FzjZ>E&eC-H-VY%Y(LcxIN#ap{cu0WD#1k#R}#bigOgMt@F@tpSRGKoCz + ({ + buy: { + title: t('fund_wallet_modal.buy'), + description: ( + +

{t('fund_wallet_modal.buy_via_banxa')}

+

{t('fund_wallet_modal.banxa_leading_solution')}

+
+ ), + entities: payments + }, + exchange: { + title: t('fund_wallet_modal.exchange'), + description: ( +

{t('fund_wallet_modal.please_check_terms', { token: GOVERNANCE_TOKEN.ticker })}

+ ), + entities: exchanges + } + }[method]); + +type FundWalletProps = CTAProps; + +// TODO: create theme card +const FundWallet = forwardRef( + (props, ref): JSX.Element => { + const { t } = useTranslation(); + const [isOpen, setOpen] = useState(false); + + return ( + <> + setOpen(true)} {...props}> + {t('fund_wallet')} + + setOpen(false)}> + {t('fund_wallet')} + + + {TABS.map((tab) => { + const { title, description, entities } = getData(tab, t); + return ( + + + {description} + + {entities.map((entity) => ( + + {entity.icon} + + ))} + + + + ); + })} + + + + + ); + } +); + +FundWallet.displayName = 'FundWallet'; + +export { FundWallet }; +export type { FundWalletProps }; diff --git a/src/components/FundWallet/entities.tsx b/src/components/FundWallet/entities.tsx new file mode 100644 index 0000000000..803ffed023 --- /dev/null +++ b/src/components/FundWallet/entities.tsx @@ -0,0 +1,74 @@ +import { ReactNode } from 'react'; + +import BANXA_KITNSUGI from '@/assets/img/banxa-kintsugi.png'; +import { ReactComponent as AcalaLogoIcon } from '@/assets/img/exchanges/acala-logo.svg'; +import { ReactComponent as GateLogoIcon } from '@/assets/img/exchanges/gate-logo.svg'; +import { ReactComponent as KrakenLogoIcon } from '@/assets/img/exchanges/kraken-logo.svg'; +import { ReactComponent as LbankLogoIcon } from '@/assets/img/exchanges/lbank-logo.svg'; +import { ReactComponent as MexcLogoForInterlayIcon } from '@/assets/img/exchanges/mexc-logo-for-interlay.svg'; +import { ReactComponent as MexcLogoForKintsugiIcon } from '@/assets/img/exchanges/mexc-logo-for-kintsugi.svg'; +import { ReactComponent as StellaSwapLogoIcon } from '@/assets/img/exchanges/stellaswap-logo.svg'; +import { ReactComponent as ZenlinkLogoIcon } from '@/assets/img/exchanges/zenlink-logo.svg'; +import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; + +type FundWalletEntities = { link: string; icon: ReactNode }; + +let exchanges: FundWalletEntities[] = []; +let payments: FundWalletEntities[] = []; + +if (process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT) { + exchanges = [ + { + link: 'https://acala.network/', + icon: + }, + { + link: 'https://stellaswap.com/', + icon: + }, + { + link: 'https://trade.kraken.com/charts/KRAKEN:INTR-USD', + icon: + }, + { + link: 'https://www.gate.io/trade/INTR_USDT', + icon: + }, + { + link: 'https://www.mexc.com/exchange/INTR_USDT', + icon: + }, + { + link: 'https://www.lbank.info/exchange/intr/usdt', + icon: + } + ]; + + // TODO: add banxa for light theme + payments = [{ link: '#', icon: banxa }]; +} else if (process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA) { + exchanges = [ + { + link: 'https://www.kraken.com/en-gb/prices/kint-kintsugi-price-chart/usd-us-dollar?interval=1m', + icon: + }, + { + link: 'https://www.gate.io/de/trade/kint_usdt', + icon: + }, + { + link: 'https://dex.zenlink.pro/#/swap', + icon: + }, + { + link: 'https://www.mexc.com/de-DE/exchange/KINT_USDT', + icon: + } + ]; + + payments = [{ link: '#', icon: banxa }]; +} else { + throw new Error(`Error: REACT_APP_RELAY_CHAIN_NAME=${process.env.REACT_APP_RELAY_CHAIN_NAME} is not valid`); +} + +export { exchanges, payments }; diff --git a/src/components/FundWallet/index.tsx b/src/components/FundWallet/index.tsx new file mode 100644 index 0000000000..74fe4a0a8c --- /dev/null +++ b/src/components/FundWallet/index.tsx @@ -0,0 +1,2 @@ +export type { FundWalletProps } from './FundWallet'; +export { FundWallet } from './FundWallet'; diff --git a/src/components/index.tsx b/src/components/index.tsx index 0e4dfa7549..28d3c50a3b 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -1,2 +1,4 @@ export type { AuthCTAProps } from './AuthCTA'; export { AuthCTA } from './AuthCTA'; +export type { FundWalletProps } from './FundWallet'; +export { FundWallet } from './FundWallet'; diff --git a/src/parts/Topbar/index.tsx b/src/parts/Topbar/index.tsx index 2685625283..a4340c2ddd 100644 --- a/src/parts/Topbar/index.tsx +++ b/src/parts/Topbar/index.tsx @@ -7,6 +7,7 @@ import { toast } from 'react-toastify'; import { showAccountModalAction } from '@/common/actions/general.actions'; import { StoreType } from '@/common/types/util.types'; +import { FundWallet } from '@/components'; import { ACCOUNT_ID_TYPE_NAME } from '@/config/general'; import { GOVERNANCE_TOKEN } from '@/config/relay-chains'; import InterlayCaliforniaOutlinedButton from '@/legacy-components/buttons/InterlayCaliforniaOutlinedButton'; @@ -18,7 +19,6 @@ import { useSubstrateSecureState } from '@/lib/substrate'; import AccountModal from '@/parts/AccountModal'; import { BitcoinNetwork } from '@/types/bitcoin'; -import GetGovernanceTokenUI from './GetGovernanceTokenUI'; import ManualIssueExecutionActionsBadge from './ManualIssueExecutionActionsBadge'; const SMALL_SIZE_BUTTON_CLASSES = clsx('leading-7', '!px-3'); @@ -76,7 +76,8 @@ const Topbar = (): JSX.Element => { <>
- + {/* */} + {selectedAccount !== undefined && ( <> {process.env.REACT_APP_BITCOIN_NETWORK !== BitcoinNetwork.Mainnet && ( From c5a69d661c8903e59fd57ae5243ae2a21900144c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Thu, 9 Mar 2023 17:22:19 +0000 Subject: [PATCH 02/69] feat: Card and clean up --- jest.config.ts | 6 +- src/assets/img/banxa-dark.png | Bin 0 -> 4353 bytes src/assets/img/banxa-kintsugi.png | Bin 3668 -> 0 bytes src/assets/img/banxa-white.png | Bin 0 -> 3277 bytes src/component-library/Card/Card.style.tsx | 42 +++++++++--- src/component-library/Card/Card.tsx | 63 +++++++++++++++--- src/component-library/Input/Input.style.tsx | 6 +- .../theme/theme.interlay.css | 5 +- .../theme/theme.kintsugi.css | 5 +- src/component-library/theme/theme.ts | 16 +++-- src/component-library/utils/prop-types.ts | 2 + .../FundWallet/FundWallet.style.tsx | 9 +-- src/components/FundWallet/FundWallet.tsx | 1 + src/components/FundWallet/entities.tsx | 5 +- .../DepositForm/DepositForm.styles.tsx | 2 +- .../WithdrawForm/WithdrawForm.styles.tsx | 2 +- .../components/SwapInfo/SwapInfo.style.tsx | 2 +- .../LoanActionInfo/LoanActionInfo.style.tsx | 2 +- .../CreateVaultWizard.styles.tsx | 2 +- .../components/InfoBox/InfoBox.style.tsx | 2 +- .../components/VaultCard/VaultCard.style.tsx | 4 +- src/test/mocks/file.js | 1 + 22 files changed, 129 insertions(+), 48 deletions(-) create mode 100644 src/assets/img/banxa-dark.png delete mode 100644 src/assets/img/banxa-kintsugi.png create mode 100644 src/assets/img/banxa-white.png create mode 100644 src/test/mocks/file.js diff --git a/jest.config.ts b/jest.config.ts index 42e4b8e36c..6b9a7b38ce 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -75,8 +75,10 @@ const config = { // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module moduleNameMapper: { - '^@/(.+)': '/src/$1', - '\\.css$': 'identity-obj-proxy' + '\\.css$': 'identity-obj-proxy', + '\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/src/test/mocks/file.js', + '^@/(.+)': '/src/$1' }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader diff --git a/src/assets/img/banxa-dark.png b/src/assets/img/banxa-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..0ef1f75a4401f9d4f06c2d12113dafdbc040e503 GIT binary patch literal 4353 zcmV+c5&rIpP)mj&z#*&$ZK~)HX9Nm5hHjBCYuEPEcI5YwHL)J#R^`ie)itm3R0j5wUkyNY8A!W z*3Y(9trfLeO+^J1t+s{Q$46U%5Qyd7l%|nQLUuPHuRUjG`k#|*vU|?SW;faG@B2>9 z$;_F@nfcBCHM7L&^?ga9BoD>`4nz>a2Q)!i>?%9Z+1c2tC#M)?Wo4PcUe^X7a3=xc z6d-=d6x)XG)(?-t1mP<3m4P5PQVO<68siWO`2#NjH1|W2@Omq=!-6a#3N4JJ3C>Og z{EfRtD>Hd&RS8q+=cD_;v6N8x2ceF}1CSs*o|%9_1Fl&Q=AJ5;{s9u|0?*G+i9E2>-#y98cmMeuOaMf{QmpeK9<^L>OoY48H51h74+a9K zLrGKzVSoz-AwNdiWRKKGKgQdr#A9K&1v~N>H!N9VqsN`z%K0IG#|t6AVUdiY9M*y(?<)jt8*UHKsg5I`HqCkOIv3&FfW!h%aM@DTx|( zr1>YDjNYC^RVgDKMD?OtQ|N1`atdL>sBi$~Qqs9CG8Hb!nmmuM9MS_j3ZTvT-l|(5 z&5#lerSAXXV~;75z-OGwq{m?Nxl&xcp_N$vHj6w#1z#0tJNQSKAS(9M=b%L1f~0ej z;jWDU&8`g>?%Uyo1Tosj^kM^{F)tt?Wcz?c`PnL=TVaB57um1Hp}Q{5D=xH)WIGd* zdZPg=b>M(L?JBCi3et>F+oAVy_Ev$}Mkd&g+ucRAE3C>ni+nes>f3_vWW?qOj_I2^ z{fA!F4T=e3AgtViLS?=jXjvN-vPuF`lCP9>Ynvg#xiAqAD{ZBOTqZ!P8S@fa4HEDM z>`;TT9xmXf+>*;D!+7EKX5$n*fCD&bj5imcgOE;Qznh*#~Wr92lxtGj??xPcOX5wS7mZj8wvzN0<{HA$^PPnapMiE=TF12VjTD|QPQ#5R81 z^FruGY`3AvC!K})Ng22CAuK{d;!;=Eq*rotYYQNaXl>o!OQ|Nm#kBZw-Y=#kR4yI-Ig7bhaM(2QacyMv_dKM0|>BeXpY#Vp?b@i~1R`yUr)4 zu||hLoim`Wqk_0_JO)M5Ao={XzwcpN2YVOi>75vx4+l@$mhSp`XS}LYGJrWnCud?O zD~##bjiiE#67H!xXJgk_nlc1`sJr9PanOfD_jCh>#x7Q}1%`93w!s8}Hf|%v!q8KM zc4HPce`lVz>YL@|u6fCB#hGLdpINQF*ctdW%>DJO}x6z#3OJ)HU=ZXJ>8kel~+`C zxedgVSaOn~p0HhLzlLOhlPNT|Neo8BqaaRGt>-6^|Mc*KAWs{6jvxNz{GvcgVu)RB z4KL#mOE1l6df0JiU}I+}=SD~`MCdoi zK2AS8Ur_pF{3mSX zQx^67yshnsACkc2?wtAfkqcuI1*o8q^_`t3V^%)5_dSZY6NV}Z(KbYBxLARSLxkE6 zK8XXm#Ud|DQ1XJi$hQE}6w1-Dcdr)oH>}4c^&-Tvz0uD49SJLUN#_Jogo;@;UlNRb zQnpH@5yhqR04mYggROJs^bWsRSI3D>*?>_DzZ?ijPCeuTBtJ7V{Fo%LRsHc)ElKdQ zD%i^ie-@HJcHwL4!CCAqJoY(A5hf{$lp-?B z!D8A$sf=y?z+LE@3+V+Pp!6OjU&|=@9VlH^2Lk((+S-eU3t!&h)d<-jh6pE#r`vH{ z>}Ix>ca85KpLe6&9oZ@!-sm_V-WHY5t^7}`Hqv4wV}n@=rw=4!?Axib64mD=hGahz z;&H#fvB#=Rz;SLn4$JQh$!O{*n_VuS3sL~-Wr_@j_KJANBD)N~^@n-5IS*+>24jmb zmN>;K59Lq}Zci*vk(Ad}EP4lD=M1Jx-$I77g!E?OQ&~sl`Thn2NF<4t|`^iaILI0Wf1ZUue0YbqZVvw>BE?&^fC<| zwU`YK^8b(`gw7leP@A|D<74L2Fa)X;%D3f~Tr&P(c^o)B)i>kqA#BIeX+qN?6OH*h z+(pOkfE1|x>C>xgP-rYgS4Ey|kuHlqx`dNwPAph(bhL6U^OtmDU}F<%A$6F1x}z(u zyr{tT1>^g~<@E`}m#8@5Pa*9CkRX_VLhR-e8RRr%VSrJ5E_n9Po>2=|R5+X+_HEeF zrG}iphgsj;-i~9fFb3S-svqM7EQgrS0Kc%)E4x|_oQzl2Rp{G{qf{52hFjnd2R=Ty z(fDq*_tH!4VB3kcmzgRO@P;cZxGdP4JyQ_JJ`&>~k#j-+!KCAVlfBi~Fc2@{0?(e9G**?#RoLtAgzWZk?*b9#(}+z6U#>I-O?a@R?C!sL$Jx!t4<7bve(y%r!RoU0d%F5O@H>YMtqsM>v2$Fm?PRDcj zZ!D1rEDH7JKOngJ3Zy{kN%gG>{zG)t&7>2!dqco!NOPcad(!Q#Jst4xKMdnQXimv> zz?8-M?gSD}+IJYEVYp+msb%RHq>~_o^Y>r7k1(YM=d@I+AxSRDj1*kwXZ*SKok%E%VpXLiHI)5FH(j$FSe>{TS(u z1i7_Kbyq{`AOikFZ=rgZF)EYYiSfmCM6ultgEscKk()cC0O$J&B;5>CCLtZ1@cEc$ zQu|1kDFWDw*`CXaAX(Hsmr0pYhicU(oeIK+#FZv~Ra$hz_C%{WdF{;&*pC+@I~-E& zQvJxLSW~`d*R05UDYfyC@W(BZv(fOiY-fPj7vkbFc!jvaD7m+(sVNLeKo#L5d! z@>O=Ken*~!h9ppyKV=2u#7Cv?E<-1SC=T8216Fo zppFMlYME+fE=%{RMZkCT_nUExS zKYNE}Du2SpVx%bH;vNjI{5lwH2tw+>nPR(N(X?V5(J?p06M@ScT!0g9d6Wq~*S8&n zJsuq-?rd+^?)3V$A|by4vC>iM$vd2$%0r>{#`y8n#r2BX&o-b#H7$CQkg+{fqxY4; zRSu{_6Mb4Fry0gX8ER;z?6#|HA8LjxBBxr=M6u&?y03iq?hnkw6Hw(UtbTzKp14;l zkG%^`M)8eDw1Yyhw~X)S7FW&`Osuxhe>R1ZS6p8AxPLGt^rKlOp8LQdWO(Jf0Lh=e z84ca7`#W-TYgZ^)Ogc4}!vx?gsFcUnkyvJ7fD)sjUt?blcADauJjB(9T-08P&kGEB z8HCa&+{M15f!2mUjMi>Rh4U(*!haLnU_)|nn9gA#V{m(wl75}WMCPEwA>?nEsBTt) zg6yP2Kc0|2gHUukSGRuUhAx^+S#l>spUlXSDgsv!NB?pwiHB+8HlBo8M27#w0-Jd? z)PC3y;9aaJ?Dz(J@K{zQMm*D$0weJr&t)&QxBulVq!8WR`#bV7eYYwU-V~Om#@Hw* ztuEHW^4y}BX39icN!7>~`Z^n}cP`qS&a>j$FDi`5-5ulk#Yw=(YdJ+#pE-Z_P?ND} z`Rd&n{hY4BcvvAPk=WbdxzRM%ek?pm}xjhm49Cf5h64jdy;;Goc z3#>0=Q7ClStghRedU0Jez`q&zxvh*3G((zzo~Ar3@f88dg`>DVrw%9P8dC<*>$xY? zcIdrC>It+RXvA;4Tl%6Fbya0J=>5gTwOP^0O3vi-1DZGzRD=Wr(>9KLwmdt^3f6Uos-fqVOuT^#SuR>k?fD@Q~2K^f@> zNzy?RAgvdE>nZHwiXqQ81}OdI376<_fr=%@6@U%4HN1&au~FasiD^Upb+j@#DH&is z@hlbFPe@pK4w68?UtW)MAP+T|$cNf6!{Im=(@tyMoL`Nor!E=gT+c6HbJrv>b~S{{lq+ vGrsH$?>Ybg01jnXNoGw=04e|g00;m8000000Mb*F00000NkvXXu0mjfZ>nDr literal 0 HcmV?d00001 diff --git a/src/assets/img/banxa-kintsugi.png b/src/assets/img/banxa-kintsugi.png deleted file mode 100644 index 8a1767467ec06bbe4f3b69ceaf4307d69c8eea88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3668 zcmV-a4y*BrP)bNXqL_k`FqJSvAEh$9JfqV=zbMNW<&e?b7&b@oz=Q+1;t$)s$v-jC&pS}O{@Bg*0 z=llL}00R*XJ|?|M+T?lOR#XA(|E@e-O*)IzkF=gNi}VQl(1wU$p7R}2pRA$}NlW;w z|Dpo0{eyWpf#hXeevR!m6u7UO>DOLaMJdt?q*ZLgM`?Z8gNHLnU9yT=NRP6;cMvri z8oFV>?la(de6D{0d~ZE!FdGNg{T`KoFVo~lixg=K=~mKSh!JexBi-ZZ!#Ri$Z0~eZ zi{qUak-C)GboxD(S=!x6>Q&(0!RCE!_=I#KN&xHcPI}CD<7z|=-%nsu;{v?c==0b? zFEuvf<>jZM0whSgAzDZRNs?YnTEhW39`Ru)>HDzvVU{Kf(V+*a)=@T=bU7+RSI4#P z`ESE!((8^g^?3ouVQ&6zG*Bn;!NAPun;?`foTG41?}hihS9)%5;9WLpnd?)w}Mt08G=#~RWI z-un@v#Ja}aX-K|7Chv{39h}+oPH*9@BBPJQfVz_U;4+NfCVh+aZAQ3FLGWGwh3evF($NULD%p_za2@-#j{SNiebEoS zFu#VIx!)&U9656fo_7f)b#L>Jz$Jb#uEQQxB*YpumAjj zBTeI&rVuq&uI!B@-M2pHQLU#kh9#N08v~zi49>gtx{H6G&tY;E^^dH+8LSrno zs-lQo8GTBU?&j%C0HuWL72ZEvHWlJPjejYb`ru%s(vn+D?o*}uc*kY%>ccTS;K=R# z5T*q+GF^z_`T5v1^c%%I&ZROOLQ<&xZ4?i+btuB+&-QW1)$}sT0Q;d_nR6Y*b2u3v zWM1I^5Az=7aE!^St9+6h`az@%EoBlI^ZDF&`P?f$x*Qy!i|g z4JqU{%%>Aanad#`>|7393rd7p+U3TwEvE`_EOOkcoQac>t79HTI+OHULlR1~LBn6*MaSC!qwe&Pv|lY)9{PeZEIl%lJ{iXdTMKk4b|q*JVIW5@R{;ldJ4k zjI`=#zM1|^g?AW zR8wSFPR5`?pIYx5IBWx%duAZIJGm5fKXvhqE5DHMvDISm{-lMay3AO=Cqloj4G)u6 zx$ZS7qVlMGHk^!GAIhNO$}&gTFg ziXvc^@k<@Wv&cm6qc|wz(55md%WigDl9c_^l0T8;GG-NExfn6RteATLDs<%^`}uS@!BPL$MFsf9=y4zb`BeIH@R{}d&INDtD=1&w(k~ktBB>_ZQ5qg2-DSD1<$I3N z^&^KF3)um3A=)JQXAs&6qYyo$-p$KXuIIYK`O?Q1b6m=eg@icpVD1j} zWGaRX`9~?u;VZ-BeOk~dcO^XM>X4X&b$`m);1Z_}zSMDD8HY~Y(=fljY@6!vXHwoh ziZ;kqhS12eMN*}|jYqtYs&&7kOp;Qr&I1q;IEGr4Tw^FKLAY~AZZ=n>Q-1U5Wk+Bi ze5MCdZPUrry9N?FnW>&69>c*8i1EH;8gKQ>^%V{M^^7=*HDY0)Rb9(_(rzw!&iG?`z=(VT>eY?#i zlfROaYMa8|^r~NrXP#--5L^@56BT6s8BdAp%ioyCy(eR^ujRS|MbZgBgUTQ|at-WB z^D+iC(W?;?6bLdqgC0Q`){hKqSDVMR*~GOqP=T=t?8D})K7DE;o$^}Q@;k)X+O8(A z)zc^jyB&5Z+LUvij;;IYb$c89MleB*QzChYN~RiW67d3VB4>n&B^j40Y`^F^er!=KU45#V*~cDYj!cXnvTQp zl61`33}JlH^18Ub+djzs!JRlDZ$=&INyG>;$qK%+Qdz}x6{$rg*Ze04S4@{tDaQVJ zz7JQyDL?!z85y9q-B0qY+{Zen7^B^e?X6d!*6T<`@Y8<+>AGvsPM1W;&`BfR#jJXZ zWbi`hw0%vlm&n-4mhdx*GwOAE861Nh(Ei`W)r@2+s&|pYNYqB}7*nkxKU z_D?aGh@*DNyY`#@ha`zx%C95H=vPI_)8Z_O|~bNu9a zm^}NuBcD8*!u>yRhmxa!3>!^gUA~R0EPEH>ME$=Z50A?~>ym0^f0!nHSbGfb&-2V= zo+cFTcl|P%0(FzjZ>E&eC-H-VY%Y(LcxIN#ap{cu0WD#1k#R}#bigOgMt@F@tpSRGKoCzd zi8mFEva$j}MFC~8)D$VB1`v!IF4;L=zORpE=I!g*o}C`Qs&9Mt9sld&@Av-WwP%d^ z4SJ6}`5$sA`L5@A8_@vp90%}l2Kfte5cx8B565dm2B7@@Je)}GrGLw+p5qvcP$MXB z3m%Rm_le|r5o<{jst>mHGE+#Sh#j2nMOR(PlFSLm3%mNX$>F7o*IT15D$AA0!v zl9!R~yuj}xLr~rhJlsYOw5nRj8(7~L^`j}GjibrOIL0ohU0xrnOfO}%bNvM2Om0Kh zJ%i_PWRCqg5#>_6bqMXYG+gWGucb-Kww#khX-FbsC=*Ua2C1JQ9X+Mz3T;Fne55C$Y!f*6L}})-cEjnda>2UvpJbx5Dx07 z_q-ACo323$Lz_c+`mQKyQ zPmq5@1HtQ9#_Q2D&;uM`RZA(Ck<;S>w$TlRjA)5>w~L1QtQ)PtLDm20-UgXge7&xl8vAUBhTIb{5k zJeTc0M;2Jzel|?;;NW+lY=QDg_IiX9PzXb>+}}7EE0A^WXQ5@#>9IdoUXs^Eov z3AcjngkB=Lp%*!-<{%6?*pT6UJQ@#O({((*-Oxbro)&p{h-`OMYxcc9I)@)ew4oPp zYGz9J+ML}`ES(qpHs$nbH+qx0X1ut(}q6S0;_jesttI-Qk zp5ADM1h%lM=9HNLe8}eSC zMpjtJU~$Pm0}6YKCQ`l zY&BafK#ib0#lC)xN*hjiA7Q8=03XO~gm1fzt0?0bWCO+AWG87U`@pKx%k~3~bz5W> zGz^|*6X0UbKv%M?yi(_C~Gr*^gL`_-e-*p=RH0TZ!! z_Ar-ddpR6JUPoStbWm{fn~w6=$Tv_sG?TbyEiEextukF~E4f2inU=xx;a;A413p9V zV=9+CL(OnQta^Ff3M)-TW1;Kc1EKet1kFBEc)lx<75el!0;S>!fwFnn?7=qS0gO0i z^UJvB*iBgU;=O3fUBNcFGH>?)F2`~ZC)%PtByS{dKuwAlE!ncE##mLFb%s%1 zr=yPyUPbHeu)}d|pE~RjrKDyc4AjPujWv*R@==?U5YFzdwBY&VBW$}VYC9~Fcd*rN zN4EJCy#(dTzCFTGC1tyymTT@2&n(;${Wrb=-?SiS!nINKFdK&)>0VXdZsTgj+`kva z69eTlMQYi;7(RMgdDE;j7x8df^7ck;(8ITF0y!S@H!(`8ee*ku9DhA3(S< z!iGW`$Dx7X^~k2%BcWOj#t)Gt`fNCfGhIu#w0aTEN_w|c+ z%Te&c-A)zCXU;;dxgwosKWK?p+GZirLz=8*Xs}hT9I9-#*HXyPjXlIselH*R|EhIl z{c_%HIUD6mv>bzrW&FoWWfq_;?Zo*5!kFQqR<%-ulURQ_Hd{n>!-U(VWM8JqfnG{} zh|ufrJqk@Hp{X<+z8s3kU~4j+RGt|){q*Wlk1tE}G00oSel0=2Aj9Deox6>j$mSINN0@M%RXNrs&Dbp8 zoqWQ$q5IH6zUrvk0X2Z_w}tIczj+SPtG%VcCNwmx;0`ioHLd@Qw`<{-%bTt${cFwB0u+pctKH^r-GiCE$&(~`GE zQU~6gQ3!*yHh#y4`w~(jT28eby>C@19(V&9044KzI2&Qi(uTqwy;gYMmmDeO)y|v# zjwV0n_){%62(DYu?-u`nGAHV@< z3>3a-#I`JDf?5;m=97Qbk4X8|&b6IhGoI|+#24R2Dc>{>1%Erua$f9E6tNT=2Gz8? zIKX#CN$DP~%h5-IT4s@|9%W8(=9*v$U4AA&%-75zcmt`}V&x5#LQd-sVHU*6A|=p8hc zYv+jUF4;=c&=_d{oI)xSPzQKl6fV&+?NU0;=o6#-tqpw)q)^TUR=HGRJmo&ge)Exl zzPBvgtJCw&?OOi=gDdbzx8~Ek)Odvnf#uj~qWw!IoDFkqlP`rItx(KwXV*?#lOl7G29%?Kwn8mQc5-6o z!i3(x68x@jR+Oi`hJEix^4Rj;wT;U4DS)y+SF-;zuD<@nH>Yv*pP-qKtq<88D_E&Z z(SofTs%tXn%4EdHChHhvIIQ0uHXC++;{wR?GHM!x6e3B>q>X~TbjYf_h{QQx9XRorBQ$4ttpaix+bqMJc4i;EymkcqD)1p z%+iRnAAy*lo_3$<_&)_hBiW=e%!mL001jnXNoGw=04e|g00;m8000000Mb*F00000 LNkvXXu0mjf0uoG_ literal 0 HcmV?d00001 diff --git a/src/component-library/Card/Card.style.tsx b/src/component-library/Card/Card.style.tsx index 47fbb7bbd3..84379aa430 100644 --- a/src/component-library/Card/Card.style.tsx +++ b/src/component-library/Card/Card.style.tsx @@ -1,20 +1,42 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { Flex } from '../Flex'; import { theme } from '../theme'; +import { CardVariants, Variants } from '../utils/prop-types'; -type CardVariants = 'default' | 'bordered'; +type StyledCardProps = { + $variant: CardVariants; + $background: Variants; + $isHoverable?: boolean; + $isPressable?: boolean; +}; -type WrapperProps = { variant: CardVariants }; - -const Wrapper = styled(Flex)` +const StyledCard = styled(Flex)` box-shadow: ${theme.boxShadow.default}; - color: ${theme.colors.textSecondary}; - background-color: ${theme.card.bg}; - border: ${(props) => props.variant === 'bordered' && theme.border.default}; + color: ${theme.colors.textPrimary}; + background-color: ${({ $background }) => theme.card.bg[$background]}; + border: ${({ $variant }) => ($variant === 'bordered' ? theme.border.default : theme.card.outlined.border)}; border-radius: ${theme.rounded.xl}; padding: ${theme.spacing.spacing6}; + cursor: ${({ $isPressable }) => $isPressable && 'pointer'}; + outline: none; + + ${({ $isHoverable }) => + $isHoverable && + css` + &:hover { + border: ${theme.border.hover}; + } + `} + + ${({ $isPressable }) => + $isPressable && + css` + &:focus { + border: ${theme.border.focus}; + box-shadow: ${theme.boxShadow.focus}; + } + `} `; -export { Wrapper }; -export type { CardVariants, WrapperProps }; +export { StyledCard }; diff --git a/src/component-library/Card/Card.tsx b/src/component-library/Card/Card.tsx index a525d5e287..e5671390c5 100644 --- a/src/component-library/Card/Card.tsx +++ b/src/component-library/Card/Card.tsx @@ -1,25 +1,66 @@ +import { useButton } from '@react-aria/button'; +import { mergeProps } from '@react-aria/utils'; +import { PressEvent } from '@react-types/shared'; +import { forwardRef } from 'react'; + import { FlexProps } from '../Flex'; -import { CardVariants, Wrapper } from './Card.style'; +import { useDOMRef } from '../utils/dom'; +import { CardVariants, Variants } from '../utils/prop-types'; +import { StyledCard } from './Card.style'; type Props = { variant?: CardVariants; + background?: Variants; + isHoverable?: boolean; + isPressable?: boolean; + isDisabled?: boolean; + onPress?: (e: PressEvent) => void; }; type InheritAttrs = Omit; type CardProps = Props & InheritAttrs; -const Card = ({ - variant = 'default', - role = 'section', - direction = 'column', - children, - ...props -}: CardProps): JSX.Element => ( - - {children} - +const Card = forwardRef( + ( + { + variant = 'default', + role = 'section', + direction = 'column', + background = 'primary', + isHoverable, + isPressable, + children, + elementType, + isDisabled, + ...props + }, + ref + ): JSX.Element => { + const cardRef = useDOMRef(ref); + const { buttonProps } = useButton( + { elementType: elementType || 'div', isDisabled: !isPressable || isDisabled, ...props }, + cardRef + ); + + return ( + + {children} + + ); + } ); +Card.displayName = 'Card'; + export { Card }; export type { CardProps }; diff --git a/src/component-library/Input/Input.style.tsx b/src/component-library/Input/Input.style.tsx index a21ef02826..e65ed6be50 100644 --- a/src/component-library/Input/Input.style.tsx +++ b/src/component-library/Input/Input.style.tsx @@ -59,12 +59,12 @@ const StyledBaseInput = styled.input` padding-bottom: ${({ $adornments }) => ($adornments.bottom ? theme.spacing.spacing6 : theme.spacing.spacing2)}; &:hover:not(:disabled):not(:focus) { - border: ${(props) => !props.$isDisabled && !props.$hasError && theme.input.hover.border}; + border: ${(props) => !props.$isDisabled && !props.$hasError && theme.border.focus}; } &:focus { - border: ${(props) => !props.$isDisabled && theme.input.focus.border}; - box-shadow: ${(props) => !props.$isDisabled && theme.input.focus.boxShadow}; + border: ${(props) => !props.$isDisabled && theme.border.focus}; + box-shadow: ${(props) => !props.$isDisabled && theme.boxShadow.focus}; } &::placeholder { diff --git a/src/component-library/theme/theme.interlay.css b/src/component-library/theme/theme.interlay.css index fef6d86da4..05ca316875 100644 --- a/src/component-library/theme/theme.interlay.css +++ b/src/component-library/theme/theme.interlay.css @@ -12,8 +12,9 @@ .theme-interlay { --colors-border: var(--colors-neutral-black-25); --colors-bg-primary: var(--colors-neutral-white); - --colors-card-bg: var(--colors-neutral-white); - --colors-card-secondary-bg: var(--colors-light-blue-10); + /* Card */ + --color-card-primary-bg: var(--colors-neutral-white); + --color-card-secondary-bg: var(--colors-light-blue-10); /* CTA */ --colors-cta-primary: var(--colors-light-blue); --colors-cta-primary-hover: var(--colors-light-blue-90); diff --git a/src/component-library/theme/theme.kintsugi.css b/src/component-library/theme/theme.kintsugi.css index 386ac48a09..5b3df686b3 100644 --- a/src/component-library/theme/theme.kintsugi.css +++ b/src/component-library/theme/theme.kintsugi.css @@ -15,8 +15,9 @@ .theme-kintsugi { --colors-border: var(--colors-mid-blue); --colors-bg-primary: var(--colors-dark-blue); - --colors-card-bg: var(--colors-dark-blue); - --colors-card-secondary-bg: var(--colors-neutral-white-06); + /* Card */ + --color-card-primary-bg: var(--colors-dark-blue); + --color-card-secondary-bg: var(--colors-neutral-white-06); /* CTA */ --colors-cta-primary: var(--colors-yellow); --colors-cta-primary-hover: var(--colors-dark-yellow); diff --git a/src/component-library/theme/theme.ts b/src/component-library/theme/theme.ts index 824e710b93..a038147b24 100644 --- a/src/component-library/theme/theme.ts +++ b/src/component-library/theme/theme.ts @@ -67,14 +67,20 @@ const theme = { xl: 'var(--rounded-xl)', full: 'var(--rounded-full)' }, + // TODO: clean this in each theme border: { - default: '1px solid var(--colors-border)' + default: '1px solid var(--colors-border)', + hover: '1px solid var(--colors-input-hover-border)', + focus: '1px solid var(--colors-input-focus-border)', + disabled: '1px solid var(--colors-input-disabled-border)', + error: '1px solid var(--colors-error-dark)' }, outline: { default: '2px solid var(--colors-border)' }, boxShadow: { - default: 'var(--box-shadow-default)' + default: 'var(--box-shadow-default)', + focus: '0 0 0 1px var(--colors-input-focus-border)' }, // Components input: { @@ -142,8 +148,10 @@ const theme = { } }, card: { - bg: 'var(--colors-card-bg)', - secondaryBg: 'var(--colors-card-secondary-bg)' + outlined: { + border: '1px solid transparent' + }, + bg: { primary: 'var(--color-card-primary-bg)', secondary: 'var(--color-card-secondary-bg)' } }, cta: { primary: { diff --git a/src/component-library/utils/prop-types.ts b/src/component-library/utils/prop-types.ts index b0265ec68a..dbf0c52740 100644 --- a/src/component-library/utils/prop-types.ts +++ b/src/component-library/utils/prop-types.ts @@ -48,6 +48,8 @@ export type Variants = typeof variant[number]; export type CTAVariants = typeof ctaVariant[number]; +export type CardVariants = 'default' | 'bordered'; + export type CTASizes = 'x-small' | 'small' | 'medium' | 'large'; export type Status = typeof status[number]; diff --git a/src/components/FundWallet/FundWallet.style.tsx b/src/components/FundWallet/FundWallet.style.tsx index 022a059442..2ad0876f73 100644 --- a/src/components/FundWallet/FundWallet.style.tsx +++ b/src/components/FundWallet/FundWallet.style.tsx @@ -24,8 +24,8 @@ const StyledEntitiesItem = styled.a` align-items: center; padding: ${theme.spacing.spacing8}; width: 100%; - background-color: ${theme.card.secondaryBg}; - border: ${theme.input.default.border}; + border: ${theme.border.default}; + background-color: ${theme.card.bg.secondary}; border-radius: 12px; max-height: 120px; @@ -40,11 +40,12 @@ const StyledEntitiesItem = styled.a` } &:hover { - border: ${theme.input.hover.border}; + border: ${theme.border.hover}; } &:focus { - box-shadow: ${theme.input.focus.boxShadow}; + border: ${theme.border.focus}; + box-shadow: ${theme.boxShadow.focus}; } `; diff --git a/src/components/FundWallet/FundWallet.tsx b/src/components/FundWallet/FundWallet.tsx index 3ef5321167..92db1a0724 100644 --- a/src/components/FundWallet/FundWallet.tsx +++ b/src/components/FundWallet/FundWallet.tsx @@ -51,6 +51,7 @@ const FundWallet = forwardRef( {TABS.map((tab) => { const { title, description, entities } = getData(tab, t); + return ( diff --git a/src/components/FundWallet/entities.tsx b/src/components/FundWallet/entities.tsx index 803ffed023..848405db78 100644 --- a/src/components/FundWallet/entities.tsx +++ b/src/components/FundWallet/entities.tsx @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; -import BANXA_KITNSUGI from '@/assets/img/banxa-kintsugi.png'; +import BANXA_INTERLAY from '@/assets/img/banxa-dark.png'; +import BANXA_KITNSUGI from '@/assets/img/banxa-white.png'; import { ReactComponent as AcalaLogoIcon } from '@/assets/img/exchanges/acala-logo.svg'; import { ReactComponent as GateLogoIcon } from '@/assets/img/exchanges/gate-logo.svg'; import { ReactComponent as KrakenLogoIcon } from '@/assets/img/exchanges/kraken-logo.svg'; @@ -45,7 +46,7 @@ if (process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT) { ]; // TODO: add banxa for light theme - payments = [{ link: '#', icon: banxa }]; + payments = [{ link: '#', icon: banxa }]; } else if (process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA) { exchanges = [ { diff --git a/src/pages/AMM/Pools/components/DepositForm/DepositForm.styles.tsx b/src/pages/AMM/Pools/components/DepositForm/DepositForm.styles.tsx index eb266ea036..6baa738902 100644 --- a/src/pages/AMM/Pools/components/DepositForm/DepositForm.styles.tsx +++ b/src/pages/AMM/Pools/components/DepositForm/DepositForm.styles.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { Divider, Dl, DlGroup, theme } from '@/component-library'; const StyledDl = styled(Dl)` - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; padding: ${theme.spacing.spacing4}; font-size: ${theme.text.xs}; border-radius: ${theme.rounded.rg}; diff --git a/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.styles.tsx b/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.styles.tsx index 1d764b7675..f4a56eb18a 100644 --- a/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.styles.tsx +++ b/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.styles.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { Dl, theme } from '@/component-library'; const StyledDl = styled(Dl)` - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; padding: ${theme.spacing.spacing4}; font-size: ${theme.text.xs}; border-radius: ${theme.rounded.rg}; diff --git a/src/pages/AMM/Swap/components/SwapInfo/SwapInfo.style.tsx b/src/pages/AMM/Swap/components/SwapInfo/SwapInfo.style.tsx index 18491cf623..2fc50a87cd 100644 --- a/src/pages/AMM/Swap/components/SwapInfo/SwapInfo.style.tsx +++ b/src/pages/AMM/Swap/components/SwapInfo/SwapInfo.style.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { theme } from '@/component-library'; const StyledCard = styled.div` - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; padding: ${theme.spacing.spacing2}; border-radius: ${theme.rounded.md}; `; diff --git a/src/pages/Loans/LoansOverview/components/LoanActionInfo/LoanActionInfo.style.tsx b/src/pages/Loans/LoansOverview/components/LoanActionInfo/LoanActionInfo.style.tsx index 1d764b7675..f4a56eb18a 100644 --- a/src/pages/Loans/LoansOverview/components/LoanActionInfo/LoanActionInfo.style.tsx +++ b/src/pages/Loans/LoansOverview/components/LoanActionInfo/LoanActionInfo.style.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { Dl, theme } from '@/component-library'; const StyledDl = styled(Dl)` - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; padding: ${theme.spacing.spacing4}; font-size: ${theme.text.xs}; border-radius: ${theme.rounded.rg}; diff --git a/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/CreateVaultWizard.styles.tsx b/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/CreateVaultWizard.styles.tsx index ac115d1adf..8e0c6454df 100644 --- a/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/CreateVaultWizard.styles.tsx +++ b/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/CreateVaultWizard.styles.tsx @@ -26,7 +26,7 @@ const StyledDisclaimerCard = styled.div` line-height: ${theme.lineHeight.base}; padding: ${theme.spacing.spacing3}; border-radius: ${theme.rounded.rg}; - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; `; const StyledDisclaimerList = styled.ol` diff --git a/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.style.tsx b/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.style.tsx index 133df64e8d..82322eab73 100644 --- a/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.style.tsx +++ b/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.style.tsx @@ -5,7 +5,7 @@ import { theme } from '@/component-library'; const InfoBoxWrapper = styled.div` align-items: center; box-shadow: ${theme.boxShadow.default}; - background: ${theme.card.bg}; + background: ${theme.card.bg.primary}; border: ${theme.border.default}; border-radius: ${theme.rounded.xl}; display: flex; diff --git a/src/pages/Vaults/VaultsOverview/components/VaultCard/VaultCard.style.tsx b/src/pages/Vaults/VaultsOverview/components/VaultCard/VaultCard.style.tsx index e0f83f0a57..04706c8af1 100644 --- a/src/pages/Vaults/VaultsOverview/components/VaultCard/VaultCard.style.tsx +++ b/src/pages/Vaults/VaultsOverview/components/VaultCard/VaultCard.style.tsx @@ -10,7 +10,7 @@ export const Card = styled.div` box-shadow: ${theme.boxShadow.default}; color: ${theme.colors.textSecondary}; display: flex; - background-color: ${theme.card.bg}; + background-color: ${theme.card.bg.primary}; border: ${theme.border.default}; border-radius: ${theme.rounded.xl}; flex-direction: column; @@ -39,7 +39,7 @@ export const CardBody = styled.div` `; export const StyledDl = styled.dl` - background-color: ${theme.card.secondaryBg}; + background-color: ${theme.card.bg.secondary}; border-radius: ${theme.rounded.md}; font-size: ${theme.text.s}; font-weight: ${theme.fontWeight.medium}; diff --git a/src/test/mocks/file.js b/src/test/mocks/file.js new file mode 100644 index 0000000000..86059f3629 --- /dev/null +++ b/src/test/mocks/file.js @@ -0,0 +1 @@ +module.exports = 'test-file-stub'; From 66e7a90baf8b67d57e164ba3991c0cdd3c104986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Wed, 15 Mar 2023 12:09:30 +0000 Subject: [PATCH 03/69] feat: add link --- .../FundWallet/FundWallet.style.tsx | 3 +- src/components/FundWallet/FundWallet.tsx | 21 ++-- src/components/FundWallet/entities.tsx | 75 ------------- src/components/FundWallet/use-entities.tsx | 106 ++++++++++++++++++ src/config/links.ts | 14 ++- src/config/relay-chains.tsx | 5 + src/parts/Topbar/index.tsx | 1 - src/utils/hooks/use-wallet.ts | 24 +++- 8 files changed, 155 insertions(+), 94 deletions(-) delete mode 100644 src/components/FundWallet/entities.tsx create mode 100644 src/components/FundWallet/use-entities.tsx diff --git a/src/components/FundWallet/FundWallet.style.tsx b/src/components/FundWallet/FundWallet.style.tsx index 2ad0876f73..13252606c8 100644 --- a/src/components/FundWallet/FundWallet.style.tsx +++ b/src/components/FundWallet/FundWallet.style.tsx @@ -1,3 +1,4 @@ +import { Link } from 'react-router-dom'; import styled from 'styled-components'; import { CTA, Flex, Tabs, theme } from '@/component-library'; @@ -18,7 +19,7 @@ const StyledEntities = styled.div` grid-gap: ${theme.spacing.spacing1}; `; -const StyledEntitiesItem = styled.a` +const StyledEntitiesItem = styled(Link)` display: flex; justify-content: center; align-items: center; diff --git a/src/components/FundWallet/FundWallet.tsx b/src/components/FundWallet/FundWallet.tsx index 92db1a0724..08be16e11e 100644 --- a/src/components/FundWallet/FundWallet.tsx +++ b/src/components/FundWallet/FundWallet.tsx @@ -4,14 +4,14 @@ import { TFunction, useTranslation } from 'react-i18next'; import { CTAProps, Flex, Modal, ModalBody, ModalHeader, P, TabsItem } from '@/component-library'; import { GOVERNANCE_TOKEN } from '@/config/relay-chains'; -import { exchanges, payments } from './entities'; import { StyledCTA, StyledEntities, StyledEntitiesItem, StyledTabs, StyledWrapper } from './FundWallet.style'; +import { useEntities, UseEntitiesResult } from './use-entities'; const TABS = ['buy', 'exchange'] as const; type FundWalletMethod = typeof TABS[number]; -const getData = (method: FundWalletMethod, t: TFunction) => +const getData = (method: FundWalletMethod, entities: UseEntitiesResult, t: TFunction) => ({ buy: { title: t('fund_wallet_modal.buy'), @@ -21,24 +21,24 @@ const getData = (method: FundWalletMethod, t: TFunction) =>

{t('fund_wallet_modal.banxa_leading_solution')}

), - entities: payments + entities: entities.payments }, exchange: { title: t('fund_wallet_modal.exchange'), description: (

{t('fund_wallet_modal.please_check_terms', { token: GOVERNANCE_TOKEN.ticker })}

), - entities: exchanges + entities: entities.exchanges } }[method]); type FundWalletProps = CTAProps; -// TODO: create theme card const FundWallet = forwardRef( (props, ref): JSX.Element => { const { t } = useTranslation(); const [isOpen, setOpen] = useState(false); + const entitiesData = useEntities(); return ( <> @@ -50,20 +50,15 @@ const FundWallet = forwardRef( {TABS.map((tab) => { - const { title, description, entities } = getData(tab, t); + const { title, description, entities } = getData(tab, entitiesData, t); return ( {description} - {entities.map((entity) => ( - + {entities.map((entity, key) => ( + {entity.icon} ))} diff --git a/src/components/FundWallet/entities.tsx b/src/components/FundWallet/entities.tsx deleted file mode 100644 index 848405db78..0000000000 --- a/src/components/FundWallet/entities.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { ReactNode } from 'react'; - -import BANXA_INTERLAY from '@/assets/img/banxa-dark.png'; -import BANXA_KITNSUGI from '@/assets/img/banxa-white.png'; -import { ReactComponent as AcalaLogoIcon } from '@/assets/img/exchanges/acala-logo.svg'; -import { ReactComponent as GateLogoIcon } from '@/assets/img/exchanges/gate-logo.svg'; -import { ReactComponent as KrakenLogoIcon } from '@/assets/img/exchanges/kraken-logo.svg'; -import { ReactComponent as LbankLogoIcon } from '@/assets/img/exchanges/lbank-logo.svg'; -import { ReactComponent as MexcLogoForInterlayIcon } from '@/assets/img/exchanges/mexc-logo-for-interlay.svg'; -import { ReactComponent as MexcLogoForKintsugiIcon } from '@/assets/img/exchanges/mexc-logo-for-kintsugi.svg'; -import { ReactComponent as StellaSwapLogoIcon } from '@/assets/img/exchanges/stellaswap-logo.svg'; -import { ReactComponent as ZenlinkLogoIcon } from '@/assets/img/exchanges/zenlink-logo.svg'; -import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; - -type FundWalletEntities = { link: string; icon: ReactNode }; - -let exchanges: FundWalletEntities[] = []; -let payments: FundWalletEntities[] = []; - -if (process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT) { - exchanges = [ - { - link: 'https://acala.network/', - icon: - }, - { - link: 'https://stellaswap.com/', - icon: - }, - { - link: 'https://trade.kraken.com/charts/KRAKEN:INTR-USD', - icon: - }, - { - link: 'https://www.gate.io/trade/INTR_USDT', - icon: - }, - { - link: 'https://www.mexc.com/exchange/INTR_USDT', - icon: - }, - { - link: 'https://www.lbank.info/exchange/intr/usdt', - icon: - } - ]; - - // TODO: add banxa for light theme - payments = [{ link: '#', icon: banxa }]; -} else if (process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA) { - exchanges = [ - { - link: 'https://www.kraken.com/en-gb/prices/kint-kintsugi-price-chart/usd-us-dollar?interval=1m', - icon: - }, - { - link: 'https://www.gate.io/de/trade/kint_usdt', - icon: - }, - { - link: 'https://dex.zenlink.pro/#/swap', - icon: - }, - { - link: 'https://www.mexc.com/de-DE/exchange/KINT_USDT', - icon: - } - ]; - - payments = [{ link: '#', icon: banxa }]; -} else { - throw new Error(`Error: REACT_APP_RELAY_CHAIN_NAME=${process.env.REACT_APP_RELAY_CHAIN_NAME} is not valid`); -} - -export { exchanges, payments }; diff --git a/src/components/FundWallet/use-entities.tsx b/src/components/FundWallet/use-entities.tsx new file mode 100644 index 0000000000..38915363d7 --- /dev/null +++ b/src/components/FundWallet/use-entities.tsx @@ -0,0 +1,106 @@ +import { ReactNode } from 'react'; +import { LinkProps } from 'react-router-dom'; + +import BANXA_INTERLAY from '@/assets/img/banxa-dark.png'; +import BANXA_KITNSUGI from '@/assets/img/banxa-white.png'; +import { ReactComponent as AcalaLogoIcon } from '@/assets/img/exchanges/acala-logo.svg'; +import { ReactComponent as GateLogoIcon } from '@/assets/img/exchanges/gate-logo.svg'; +import { ReactComponent as KrakenLogoIcon } from '@/assets/img/exchanges/kraken-logo.svg'; +import { ReactComponent as LbankLogoIcon } from '@/assets/img/exchanges/lbank-logo.svg'; +import { ReactComponent as MexcLogoForInterlayIcon } from '@/assets/img/exchanges/mexc-logo-for-interlay.svg'; +import { ReactComponent as MexcLogoForKintsugiIcon } from '@/assets/img/exchanges/mexc-logo-for-kintsugi.svg'; +import { ReactComponent as StellaSwapLogoIcon } from '@/assets/img/exchanges/stellaswap-logo.svg'; +import { ReactComponent as ZenlinkLogoIcon } from '@/assets/img/exchanges/zenlink-logo.svg'; +import { BANXA_LINK, LINK_QUERY_PARAMETERS } from '@/config/links'; +import { GOVERNANCE_TOKEN } from '@/config/relay-chains'; +import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; +import { useWallet } from '@/utils/hooks/use-wallet'; + +const queryString = require('query-string'); + +type FundWalletEntities = { link: LinkProps['to']; icon: ReactNode }; + +type UseEntitiesResult = { + exchanges: FundWalletEntities[]; + payments: FundWalletEntities[]; +}; + +const useEntities = (): UseEntitiesResult => { + const wallet = useWallet(); + + const banxaLink = { + pathname: BANXA_LINK, + search: queryString.stringify({ + [LINK_QUERY_PARAMETERS.BANXA.WALLET_ADDRESS]: wallet.getRelayChainAddress(), + [LINK_QUERY_PARAMETERS.BANXA.FIAT_TYPE]: 'EUR', + [LINK_QUERY_PARAMETERS.BANXA.COIN_TYPE]: GOVERNANCE_TOKEN.ticker + }) + }; + + if (process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT) { + const exchanges = [ + { + link: 'https://acala.network/', + icon: + }, + { + link: 'https://stellaswap.com/', + icon: + }, + { + link: 'https://trade.kraken.com/charts/KRAKEN:INTR-USD', + icon: + }, + { + link: 'https://www.gate.io/trade/INTR_USDT', + icon: + }, + { + link: 'https://www.mexc.com/exchange/INTR_USDT', + icon: + }, + { + link: 'https://www.lbank.info/exchange/intr/usdt', + icon: + } + ]; + + const payments = [{ link: banxaLink, icon: banxa }]; + + return { + exchanges, + payments + }; + } else if (process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA) { + const exchanges = [ + { + link: 'https://www.kraken.com/en-gb/prices/kint-kintsugi-price-chart/usd-us-dollar?interval=1m', + icon: + }, + { + link: 'https://www.gate.io/de/trade/kint_usdt', + icon: + }, + { + link: 'https://dex.zenlink.pro/#/swap', + icon: + }, + { + link: 'https://www.mexc.com/de-DE/exchange/KINT_USDT', + icon: + } + ]; + + const payments = [{ link: banxaLink, icon: banxa }]; + + return { + exchanges, + payments + }; + } else { + throw new Error(`Error: REACT_APP_RELAY_CHAIN_NAME=${process.env.REACT_APP_RELAY_CHAIN_NAME} is not valid`); + } +}; + +export { useEntities }; +export type { UseEntitiesResult }; diff --git a/src/config/links.ts b/src/config/links.ts index ec3ca6e1ab..e07131f0a2 100644 --- a/src/config/links.ts +++ b/src/config/links.ts @@ -19,7 +19,18 @@ const KINTSUGI_SUBSCAN_LINK = 'https://kintsugi.subscan.io'; const INTERLAY_VAULT_DOCS_LINK = 'https://docs.interlay.io/#/vault/overview'; const INTERLAY_DOS_AND_DONTS_DOCS_LINK = 'https://docs.interlay.io/#/vault/installation?id=dos-and-donts'; +const LINK_QUERY_PARAMETERS = { + BANXA: { + WALLET_ADDRESS: 'walletAddress', + FIAT_TYPE: 'fiatType', + COIN_TYPE: 'coinType' + } +}; + +const BANXA_LINK = `https://talisman.banxa.com`; + export { + BANXA_LINK, INTERLAY_COMPANY_LINK, INTERLAY_CROWDLOAN_LINK, INTERLAY_DISCORD_LINK, @@ -37,5 +48,6 @@ export { KINTSUGI_GOVERNANCE_LINK, KINTSUGI_SUBSCAN_LINK, KINTSUGI_TERMS_AND_CONDITIONS_LINK, - KINTSUGI_USE_WRAPPED_CURRENCY_LINK + KINTSUGI_USE_WRAPPED_CURRENCY_LINK, + LINK_QUERY_PARAMETERS }; diff --git a/src/config/relay-chains.tsx b/src/config/relay-chains.tsx index 7f5ae39d16..d358c50be6 100644 --- a/src/config/relay-chains.tsx +++ b/src/config/relay-chains.tsx @@ -116,6 +116,8 @@ let XCM_ADAPTERS: Record; let TRANSACTION_FEE_AMOUNT: MonetaryAmount; +let SS58_PREFIX: number; + type WrappedTokenAmount = InterBtcAmount | KBtcAmount; switch (process.env.REACT_APP_RELAY_CHAIN_NAME) { @@ -157,6 +159,7 @@ switch (process.env.REACT_APP_RELAY_CHAIN_NAME) { polkadot: new PolkadotAdapter(), statemint: new StatemintAdapter() }; + SS58_PREFIX = 0; break; } @@ -198,6 +201,7 @@ switch (process.env.REACT_APP_RELAY_CHAIN_NAME) { kusama: new KusamaAdapter(), statemine: new StatemineAdapter() }; + SS58_PREFIX = 2; break; } default: { @@ -230,6 +234,7 @@ export { RELAY_CHAIN_NATIVE_TOKEN_SYMBOL, RelayChainLogoIcon, RelayChainNativeTokenLogoIcon, + SS58_PREFIX, STAKE_LOCK_TIME, SUBSCAN_LINK, TERMS_AND_CONDITIONS_LINK, diff --git a/src/parts/Topbar/index.tsx b/src/parts/Topbar/index.tsx index a4340c2ddd..5047855796 100644 --- a/src/parts/Topbar/index.tsx +++ b/src/parts/Topbar/index.tsx @@ -76,7 +76,6 @@ const Topbar = (): JSX.Element => { <>
- {/* */} {selectedAccount !== undefined && ( <> diff --git a/src/utils/hooks/use-wallet.ts b/src/utils/hooks/use-wallet.ts index 3dbbb9e282..60609b60b9 100644 --- a/src/utils/hooks/use-wallet.ts +++ b/src/utils/hooks/use-wallet.ts @@ -1,16 +1,18 @@ import { newAccountId } from '@interlay/interbtc-api'; import { InjectedAccountWithMeta } from '@polkadot/extension-inject/types'; import { AccountId } from '@polkadot/types/interfaces'; -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { StoreType } from '@/common/types/util.types'; +import { SS58_PREFIX } from '@/config/relay-chains'; import { useSubstrateSecureState } from '@/lib/substrate'; type UseWalletResult = { isAuth: boolean; account?: AccountId; accounts: InjectedAccountWithMeta[]; + getRelayChainAddress: (address?: string) => string | undefined; }; const useWallet = (): UseWalletResult => { @@ -23,20 +25,36 @@ const useWallet = (): UseWalletResult => { [bridgeLoaded, selectedAccount] ); + const getRelayChainAddress = useCallback( + (address?: string) => { + const currentAddress = address || selectedAccount?.address; + + if (!currentAddress) { + return undefined; + } + + const decodedAddress = substrate.keyring.decodeAddress(currentAddress); + return substrate.keyring.encodeAddress(decodedAddress, SS58_PREFIX); + }, + [selectedAccount?.address, substrate.keyring] + ); + const isAuth = !!substrate.selectedAccount; if (!bridgeLoaded || !selectedAccount) { return { isAuth: false, account: undefined, - accounts: [] + accounts: [], + getRelayChainAddress }; } return { isAuth, account, - accounts: isAuth ? accounts : [] + accounts: isAuth ? accounts : [], + getRelayChainAddress }; }; From ecc433f46dab73992769972c64e947e4e4049020 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 29 Mar 2023 10:42:52 +0100 Subject: [PATCH 04/69] chore: add env variables to config --- .env.dev | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.env.dev b/.env.dev index 6e63056257..fd40ea1079 100644 --- a/.env.dev +++ b/.env.dev @@ -14,6 +14,7 @@ REACT_APP_PARACHAIN_URL="ws://127.0.0.1:9944" REACT_APP_FAUCET_URL="http://localhost:3035" REACT_APP_RELAY_CHAIN_NAME="kusama" DOCKER_RELAY_CHAIN_CURRENCY="KSM" +REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" // Kintsugi testnet @@ -26,6 +27,7 @@ REACT_APP_RELAY_CHAIN_URL="wss://api-dev-kintsugi.interlay.io/relaychain" REACT_APP_PARACHAIN_ID="2121" DOCKER_RELAY_CHAIN_CURRENCY="KSM" REACT_APP_SQUID_URL="https://api-dev-kintsugi.interlay.io/graphql/graphql" +REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" // Interlay testnet @@ -38,6 +40,7 @@ REACT_APP_PARACHAIN_ID="2032" REACT_APP_RELAY_CHAIN_NAME="polkadot" DOCKER_RELAY_CHAIN_CURRENCY="DOT" REACT_APP_SQUID_URL="https://api-testnet.interlay.io/graphql/graphql" +REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" /* PRODUCTION */ @@ -52,6 +55,7 @@ REACT_APP_RELAY_CHAIN_URL="wss://kusama-rpc.polkadot.io" REACT_APP_PARACHAIN_ID="2092" DOCKER_RELAY_CHAIN_CURRENCY="KSM" REACT_APP_SQUID_URL="https://api-kusama.interlay.io/graphql/graphql" +REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" // Interlay mainnet @@ -64,3 +68,4 @@ REACT_APP_RELAY_CHAIN_URL="wss://rpc.polkadot.io" REACT_APP_PARACHAIN_ID="2032" DOCKER_RELAY_CHAIN_CURRENCY="DOT" REACT_APP_SQUID_URL="https://api.interlay.io/graphql/graphql" +REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" From e31fc5af2f48814ef856ef6a74b9404e201128c1 Mon Sep 17 00:00:00 2001 From: ns212 <73105077+ns212@users.noreply.github.com> Date: Tue, 4 Apr 2023 13:39:30 +0100 Subject: [PATCH 05/69] chore: add cors to market data api (#1091) --- api/market_data.py | 2 ++ api/requirements.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/market_data.py b/api/market_data.py index 0f41c6de0a..bbcf4d232f 100644 --- a/api/market_data.py +++ b/api/market_data.py @@ -1,8 +1,10 @@ from flask import Flask, request, jsonify +from flask_cors import CORS import requests import os app = Flask(__name__) +CORS(app) api_key = os.environ.get("CG_API_KEY") diff --git a/api/requirements.txt b/api/requirements.txt index cbd2f6a824..62fb9584d9 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -1,3 +1,4 @@ Flask +flask-cors requests -python-dateutil \ No newline at end of file +python-dateutil From 25c5b3dc009902437ebe332df129051bd0a3f5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Mon, 27 Mar 2023 17:23:49 +0100 Subject: [PATCH 06/69] feat: add T&C signature --- .env.dev | 2 + src/assets/locales/en/translation.json | 1 + src/components/AuthCTA/AuthCTA.tsx | 71 +++++++++++------ src/constants.ts | 3 + src/pages/Bridge/BurnForm/index.tsx | 30 +++---- src/pages/Bridge/IssueForm/index.tsx | 23 +++--- src/pages/Bridge/RedeemForm/index.tsx | 26 ++---- src/pages/Staking/index.tsx | 34 +++----- .../Transactions/IssueRequestsTable/index.tsx | 5 -- .../Transfer/CrossChainTransferForm/index.tsx | 28 +++---- src/pages/Transfer/TransferForm/index.tsx | 32 +++----- src/parts/AccountModal/index.tsx | 18 +++-- src/parts/Topbar/index.tsx | 11 ++- src/utils/helpers/wallet.ts | 21 +++++ src/utils/hooks/use-sign-message.ts | 79 +++++++++++++++++++ 15 files changed, 232 insertions(+), 152 deletions(-) create mode 100644 src/utils/helpers/wallet.ts create mode 100644 src/utils/hooks/use-sign-message.ts diff --git a/.env.dev b/.env.dev index ac580353f8..f59ea2acca 100644 --- a/.env.dev +++ b/.env.dev @@ -56,6 +56,7 @@ REACT_APP_PARACHAIN_ID="2092" DOCKER_RELAY_CHAIN_CURRENCY="KSM" REACT_APP_SQUID_URL="https://api-kusama.interlay.io/graphql/graphql" REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" +SIGNER_API_URL="https://api.interlay.io/signer" // Interlay mainnet @@ -69,3 +70,4 @@ REACT_APP_PARACHAIN_ID="2032" DOCKER_RELAY_CHAIN_CURRENCY="DOT" REACT_APP_SQUID_URL="https://api.interlay.io/graphql/graphql" REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" +SIGNER_API_URL="https://api.interlay.io/signer" diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index bb3258f7f3..34a8bef274 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -152,6 +152,7 @@ "fund_wallet": "Fund Wallet", "unlocks": "Unlocks", "staked": "Staked", + "sign_t&cs": "Sign T&C's", "redeem_page": { "maximum_in_single_request": "Max redeemable in single request", "redeem": "Redeem", diff --git a/src/components/AuthCTA/AuthCTA.tsx b/src/components/AuthCTA/AuthCTA.tsx index b853b064c4..aa7ab7a565 100644 --- a/src/components/AuthCTA/AuthCTA.tsx +++ b/src/components/AuthCTA/AuthCTA.tsx @@ -1,4 +1,3 @@ -import { mergeProps } from '@react-aria/utils'; import { forwardRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; @@ -6,31 +5,59 @@ import { useDispatch } from 'react-redux'; import { showAccountModalAction } from '@/common/actions/general.actions'; import { CTA, CTAProps } from '@/component-library'; import { useSubstrateSecureState } from '@/lib/substrate'; +import { useSignMessage } from '@/utils/hooks/use-sign-message'; + +enum AuthStatus { + UNAUTH, + AUTH, + UNSIGNED +} + +const useAuthCTAProps = (props: AuthCTAProps): AuthCTAProps => { + const { t } = useTranslation(); + const { hasSignature, buttonProps } = useSignMessage(); + + const { selectedAccount } = useSubstrateSecureState(); + + const status = selectedAccount ? (hasSignature ? AuthStatus.AUTH : AuthStatus.UNSIGNED) : AuthStatus.UNAUTH; + + const dispatch = useDispatch(); + + const { onPress, children, type: typeProp, disabled } = props; + + switch (status) { + case AuthStatus.AUTH: + return { + type: typeProp, + disabled, + onPress, + children + }; + case AuthStatus.UNSIGNED: + return { + ...buttonProps, + type: 'button', + disabled: false, + children: t('sign_t&cs') + }; + case AuthStatus.UNAUTH: + default: + return { + type: 'button', + disabled: false, + onPress: () => dispatch(showAccountModalAction(true)), + children: t('connect_wallet') + }; + } +}; type AuthCTAProps = CTAProps; const AuthCTA = forwardRef( - ({ onPress, children, type: typeProp, disabled, ...props }, ref): JSX.Element => { - const { t } = useTranslation(); - - const { selectedAccount } = useSubstrateSecureState(); - const dispatch = useDispatch(); - - const otherProps = selectedAccount - ? { - type: typeProp, - disabled, - onPress, - children - } - : { - type: 'button', - disabled: false, - onPress: () => dispatch(showAccountModalAction(true)), - children: t('connect_wallet') - }; - - return ; + (props, ref): JSX.Element => { + const authProps = useAuthCTAProps(props); + + return ; } ); diff --git a/src/constants.ts b/src/constants.ts index 1da781d828..e123a56f62 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,6 +36,8 @@ const SQUID_URL = process.env.REACT_APP_SQUID_URL || 'http://localhost:4000/grap const FEEDBACK_URL = 'https://forms.gle/2eKFnq4j1fkBgejW7'; +const SIGNER_API_URL = process.env.REACT_APP_SIGNER_API_URL || 'https://api.interlay.io/signer'; + // FIXME: hacky workaround to get the right ss58 prefix. Should be fetched at runtime instead // Possible example below: // // Load the basic bridge data without depending on interbtc-api @@ -90,6 +92,7 @@ export { FEEDBACK_URL, PARACHAIN_URL, RELAY_CHAIN_URL, + SIGNER_API_URL, SQUID_URL, SS58_FORMAT, STORE_NAME, diff --git a/src/pages/Bridge/BurnForm/index.tsx b/src/pages/Bridge/BurnForm/index.tsx index 96a218ed50..911cbff307 100644 --- a/src/pages/Bridge/BurnForm/index.tsx +++ b/src/pages/Bridge/BurnForm/index.tsx @@ -5,13 +5,13 @@ import * as React from 'react'; import { useErrorHandler, withErrorBoundary } from 'react-error-boundary'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { toast } from 'react-toastify'; -import { showAccountModalAction } from '@/common/actions/general.actions'; import { ParachainStatus, StoreType } from '@/common/types/util.types'; import { displayMonetaryAmountInUSDFormat } from '@/common/utils/utils'; import { CoinIcon } from '@/component-library'; +import { AuthCTA } from '@/components'; import { WRAPPED_TOKEN, WRAPPED_TOKEN_SYMBOL, WrappedTokenLogoIcon } from '@/config/relay-chains'; import { BALANCE_MAX_INTEGER_LENGTH } from '@/constants'; import ErrorFallback from '@/legacy-components/ErrorFallback'; @@ -20,10 +20,8 @@ import FormTitle from '@/legacy-components/FormTitle'; import Hr2 from '@/legacy-components/hrs/Hr2'; import PriceInfo from '@/legacy-components/PriceInfo'; import PrimaryColorEllipsisLoader from '@/legacy-components/PrimaryColorEllipsisLoader'; -import SubmitButton from '@/legacy-components/SubmitButton'; import TokenField from '@/legacy-components/TokenField'; import Tokens, { TokenOption } from '@/legacy-components/Tokens'; -import { useSubstrateSecureState } from '@/lib/substrate'; import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; @@ -45,14 +43,12 @@ type BurnableCollateral = { }; const BurnForm = (): JSX.Element | null => { - const dispatch = useDispatch(); const { t } = useTranslation(); const prices = useGetPrices(); const [status, setStatus] = React.useState(STATUSES.IDLE); const handleError = useErrorHandler(); - const { selectedAccount } = useSubstrateSecureState(); const { bridgeLoaded, parachainStatus } = useSelector((state: StoreType) => state.general); const { data: balances } = useGetBalances(); const { data: collateralCurrencies } = useGetCollateralCurrencies(bridgeLoaded); @@ -150,13 +146,6 @@ const BurnForm = (): JSX.Element | null => { throw new Error('Something went wrong!'); } - const handleConfirmClick = (event: React.MouseEvent) => { - if (!accountSet) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const onSubmit = async (data: BurnFormData) => { try { setSubmitStatus(STATUSES.PENDING); @@ -210,7 +199,6 @@ const BurnForm = (): JSX.Element | null => { const earnedCollateralTokenAmount = selectedCollateral.burnRate.rate.eq(0) ? newMonetaryAmount(0, selectedCollateral.currency) : selectedCollateral.burnRate.toCounter(parsedInterBTCAmount || BitcoinAmount.zero()); - const accountSet = !!selectedAccount; return ( <> @@ -308,14 +296,16 @@ const BurnForm = (): JSX.Element | null => { getTokenPrice(prices, selectedCollateral.currency.ticker)?.usd )} /> - - {accountSet ? t('burn') : t('connect_wallet')} - + {t('burn')} + {submitStatus === STATUSES.REJECTED && submitError && ( { setSubmittedRequest(undefined); }; - const handleConfirmClick = (event: React.MouseEvent) => { - if (!accountSet) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const handleSelectVaultCheckboxChange = () => { if (!isSelectVaultCheckboxDisabled) { setSelectVaultManually((prev) => !prev); @@ -529,13 +521,16 @@ const IssueForm = (): JSX.Element | null => { /> } /> - - {accountSet ? t('confirm') : t('connect_wallet')} - + {t('confirm')} + {submitStatus === STATUSES.REJECTED && submitError && ( { const handleError = useErrorHandler(); const usdPrice = getTokenPrice(prices, ForeignAssetIdLiteral.BTC)?.usd; - const { selectedAccount } = useSubstrateSecureState(); const { bridgeLoaded, bitcoinHeight, btcRelayHeight, parachainStatus } = useSelector( (state: StoreType) => state.general ); @@ -226,13 +223,6 @@ const RedeemForm = (): JSX.Element | null => { setSubmittedRequest(undefined); }; - const handleConfirmClick = (event: React.MouseEvent) => { - if (!accountSet) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const handleSelectVaultCheckboxChange = () => { if (!isSelectVaultCheckboxDisabled) { setSelectVaultManually((prev) => !prev); @@ -385,8 +375,6 @@ const RedeemForm = (): JSX.Element | null => { getTokenPrice(prices, ForeignAssetIdLiteral.BTC)?.usd ); - const accountSet = !!selectedAccount; - // `btcToDotRate` has 0 value only if oracle call fails const isOracleOffline = btcToRelayChainNativeTokenRate.toBig().eq(0); @@ -523,13 +511,15 @@ const RedeemForm = (): JSX.Element | null => { approxUSD={totalRelayChainNativeTokenInUSD} /> )} - - {accountSet ? t('confirm') : t('connect_wallet')} - + {t('confirm')} + {submitStatus === STATUSES.REJECTED && submitError && ( { const [blockLockTimeExtension, setBlockLockTimeExtension] = React.useState(0); - const dispatch = useDispatch(); const { t } = useTranslation(); const prices = useGetPrices(); @@ -668,14 +666,6 @@ const Staking = (): JSX.Element => { return displayMonetaryAmount(claimableRewardAmount); }; - const handleConfirmClick = (event: React.MouseEvent) => { - // TODO: should be handled based on https://kentcdodds.com/blog/application-state-management-with-react - if (!accountSet) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const valueInUSDOfLockingAmount = displayMonetaryAmountInUSDFormat( monetaryLockingAmount, getTokenPrice(prices, GOVERNANCE_TOKEN_SYMBOL)?.usd @@ -858,18 +848,18 @@ const Staking = (): JSX.Element => { voteGovernanceTokenSymbol: VOTE_GOVERNANCE_TOKEN_SYMBOL })} /> - - ) : null - } + loading={initialStakeMutation.isLoading || moreStakeMutation.isLoading} > - {submitButtonLabel} - + {submitButtonLabel}{' '} + {unlockFirst ? ( + + ) : null} + diff --git a/src/pages/Transactions/IssueRequestsTable/index.tsx b/src/pages/Transactions/IssueRequestsTable/index.tsx index e6f1fd586f..fdb72c9aa5 100644 --- a/src/pages/Transactions/IssueRequestsTable/index.tsx +++ b/src/pages/Transactions/IssueRequestsTable/index.tsx @@ -5,10 +5,8 @@ import { useErrorHandler, withErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; import { FaCheck, FaRegClock, FaRegTimesCircle } from 'react-icons/fa'; import { useQuery } from 'react-query'; -import { useDispatch } from 'react-redux'; import { useTable } from 'react-table'; -import { showAccountModalAction } from '@/common/actions/general.actions'; import { formatDateTimePrecise, formatNumber, shortTxId } from '@/common/utils/utils'; import { BTC_EXPLORER_TRANSACTION_API } from '@/config/blockstream-explorer-links'; import { ISSUE_REDEEM_REQUEST_REFETCH_INTERVAL } from '@/config/parachain'; @@ -39,7 +37,6 @@ import useUpdateQueryParameters from '@/utils/hooks/use-update-query-parameters' import IssueRequestModal from './IssueRequestModal'; const IssueRequestsTable = (): JSX.Element => { - const dispatch = useDispatch(); const { t } = useTranslation(); const queryParams = useQueryParams(); @@ -216,8 +213,6 @@ const IssueRequestsTable = (): JSX.Element => { updateQueryParameters({ [QUERY_PARAMETERS.ISSUE_REQUEST_ID]: requestId }); - } else { - dispatch(showAccountModalAction(true)); } }; diff --git a/src/pages/Transfer/CrossChainTransferForm/index.tsx b/src/pages/Transfer/CrossChainTransferForm/index.tsx index c5f88a6cda..a6e11509b7 100644 --- a/src/pages/Transfer/CrossChainTransferForm/index.tsx +++ b/src/pages/Transfer/CrossChainTransferForm/index.tsx @@ -1,7 +1,6 @@ import { FixedPointNumber } from '@acala-network/sdk-core'; import { BasicToken, CrossChainTransferParams } from '@interlay/bridge'; -import { CurrencyExt, DefaultTransactionAPI } from '@interlay/interbtc-api'; -import { newMonetaryAmount } from '@interlay/interbtc-api'; +import { CurrencyExt, DefaultTransactionAPI, newMonetaryAmount } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; import { ApiPromise } from '@polkadot/api'; import { web3FromAddress } from '@polkadot/extension-dapp'; @@ -11,13 +10,13 @@ import { useEffect } from 'react'; import { withErrorBoundary } from 'react-error-boundary'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { toast } from 'react-toastify'; import { firstValueFrom } from 'rxjs'; -import { showAccountModalAction } from '@/common/actions/general.actions'; import { ParachainStatus, StoreType } from '@/common/types/util.types'; import { displayMonetaryAmountInUSDFormat } from '@/common/utils/utils'; +import { AuthCTA } from '@/components'; import Accounts from '@/legacy-components/Accounts'; import AvailableBalanceUI from '@/legacy-components/AvailableBalanceUI'; import Chains, { ChainOption } from '@/legacy-components/Chains'; @@ -25,7 +24,6 @@ import ErrorFallback from '@/legacy-components/ErrorFallback'; import ErrorModal from '@/legacy-components/ErrorModal'; import FormTitle from '@/legacy-components/FormTitle'; import PrimaryColorEllipsisLoader from '@/legacy-components/PrimaryColorEllipsisLoader'; -import SubmitButton from '@/legacy-components/SubmitButton'; import TokenField from '@/legacy-components/TokenField'; import { KeyringPair, useSubstrateSecureState } from '@/lib/substrate'; import STATUSES from '@/utils/constants/statuses'; @@ -55,7 +53,6 @@ const CrossChainTransferForm = (): JSX.Element => { // TODO: this will need to be refactored when we support multiple currencies // per channel, but so will the UI so better to handle this then. - const dispatch = useDispatch(); const { t } = useTranslation(); const prices = useGetPrices(); @@ -203,13 +200,6 @@ const CrossChainTransferForm = (): JSX.Element => { } }; - const handleConfirmClick = (event: React.MouseEvent) => { - if (!selectedAccount) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const handleUpdateUsdAmount = (value: string) => { if (!value) return; @@ -351,13 +341,15 @@ const CrossChainTransferForm = (): JSX.Element => { label={t('transfer_page.cross_chain_transfer_form.target_account')} callbackFunction={setDestination} /> - - {selectedAccount ? t('transfer') : t('connect_wallet')} - + {t('transfer')} + {submitStatus === STATUSES.REJECTED && submitError && ( { - const dispatch = useDispatch(); const { t } = useTranslation(); - const { selectedAccount } = useSubstrateSecureState(); const { parachainStatus } = useSelector((state: StoreType) => state.general); const { @@ -50,7 +46,6 @@ const TransferForm = (): JSX.Element => { }); const [activeToken, setActiveToken] = React.useState(undefined); - const [accountSet, setAccountSet] = React.useState(undefined); const [submitStatus, setSubmitStatus] = React.useState(STATUSES.IDLE); const [submitError, setSubmitError] = React.useState(null); @@ -92,23 +87,12 @@ const TransferForm = (): JSX.Element => { [t] ); - const handleConfirmClick = (event: React.MouseEvent) => { - if (!accountSet) { - dispatch(showAccountModalAction(true)); - event.preventDefault(); - } - }; - const handleTokenChange = (token: any) => { setActiveToken(token); }; const handleClickBalance = () => setValue(TRANSFER_AMOUNT, activeToken?.transferableBalance || ''); - React.useEffect(() => { - setAccountSet(!!selectedAccount); - }, [selectedAccount]); - // This ensures that triggering the notification and clearing // the form happen at the same time. React.useEffect(() => { @@ -179,13 +163,15 @@ const TransferForm = (): JSX.Element => { helperText={errors[RECIPIENT_ADDRESS]?.message} />
- - {accountSet ? t('transfer') : t('connect_wallet')} - + {t('transfer')} + {submitStatus === STATUSES.REJECTED && submitError && ( void; + onAccountSelect?: (account: KeyringPair) => void; } const ACCOUNT_MODAL_BUTTON_CLASSES = clsx( @@ -42,7 +43,7 @@ const ACCOUNT_MODAL_BUTTON_SELECTED_CLASSES = clsx( { 'dark:hover:bg-opacity-100': process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA } ); -const AccountModal = ({ open, onClose }: Props): JSX.Element => { +const AccountModal = ({ open, onAccountSelect, onClose }: Props): JSX.Element => { const { extensions, selectedAccount, accounts } = useSubstrateSecureState(); const { t } = useTranslation(); @@ -84,7 +85,7 @@ const AccountModal = ({ open, onClose }: Props): JSX.Element => { const keyring = new Keyring({ type: 'sr25519', ss58Format: SS58_FORMAT }); const theSelectedAccount = keyring.addFromAddress(newAccount.address, newAccount.meta); setSelectedAccount(theSelectedAccount); - + onAccountSelect?.(theSelectedAccount as KeyringPair); onClose(); }; @@ -130,15 +131,16 @@ const AccountModal = ({ open, onClose }: Props): JSX.Element => { ); } }, [ - accounts, - accountsFromSelectedWallet, - selectedAccount, + setSelectedAccount, + removeSelectedAccount, supportedExtensions, + onAccountSelect, onClose, selectedWallet, t, - setSelectedAccount, - removeSelectedAccount + accounts, + accountsFromSelectedWallet, + selectedAccount ]); return ( diff --git a/src/parts/Topbar/index.tsx b/src/parts/Topbar/index.tsx index 2e11eca46a..88fce06efb 100644 --- a/src/parts/Topbar/index.tsx +++ b/src/parts/Topbar/index.tsx @@ -18,6 +18,7 @@ import { useSubstrateSecureState } from '@/lib/substrate'; import AccountModal from '@/parts/AccountModal'; import { BitcoinNetwork } from '@/types/bitcoin'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; +import { useSignMessage } from '@/utils/hooks/use-sign-message'; import GetGovernanceTokenUI from './GetGovernanceTokenUI'; import ManualIssueExecutionActionsBadge from './ManualIssueExecutionActionsBadge'; @@ -29,7 +30,9 @@ const Topbar = (): JSX.Element => { const dispatch = useDispatch(); const { t } = useTranslation(); const { getAvailableBalance } = useGetBalances(); - const kintBalanceIsZero = getAvailableBalance("KINT")?.isZero(); + const { selectProp } = useSignMessage(); + + const kintBalanceIsZero = getAvailableBalance('KINT')?.isZero(); const handleRequestFromFaucet = async (): Promise => { if (!selectedAccount) return; @@ -117,7 +120,11 @@ const Topbar = (): JSX.Element => { {accountLabel}
- + ); }; diff --git a/src/utils/helpers/wallet.ts b/src/utils/helpers/wallet.ts new file mode 100644 index 0000000000..7bce5f09dd --- /dev/null +++ b/src/utils/helpers/wallet.ts @@ -0,0 +1,21 @@ +import { web3FromSource } from '@polkadot/extension-dapp'; +import { SignerResult } from '@polkadot/types/types'; +import { stringToHex } from '@polkadot/util'; + +import { KeyringPair } from '@/lib/substrate'; + +const signMessage = async (account: KeyringPair, message: string): Promise => { + const injector = await web3FromSource(account.meta.source as any); + const signRaw = injector?.signer?.signRaw; + + if (!signRaw) return; + // after making sure that signRaw is defined + // we can use it to sign our message + return signRaw({ + address: account.address, + data: stringToHex(message), + type: 'bytes' + }); +}; + +export { signMessage }; diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts new file mode 100644 index 0000000000..95a429102c --- /dev/null +++ b/src/utils/hooks/use-sign-message.ts @@ -0,0 +1,79 @@ +import { PressEvent } from '@react-types/shared'; +import { useEffect, useState } from 'react'; +import { useMutation } from 'react-query'; +import { useLocalStorage } from 'react-use'; + +import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; +import { SIGNER_API_URL } from '@/constants'; +import { KeyringPair, useSubstrateSecureState } from '@/lib/substrate'; +import { BitcoinNetwork } from '@/types/bitcoin'; + +import { signMessage } from '../helpers/wallet'; + +const postSignature = async (account: KeyringPair) => { + const signerResult = await signMessage(account, TERMS_AND_CONDITIONS_LINK); + + if (!signerResult?.signature) { + throw new Error('Failed to sign message'); + } + + return fetch(`${SIGNER_API_URL}/accept`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accountid: account.address, + signature: signerResult?.signature + }) + }); +}; + +type UseSignMessageResult = { + hasSignature?: boolean; + selectProp: { onSelectionChange: (account: KeyringPair) => void }; + buttonProps: { + onPress: (e: PressEvent) => void; + }; +}; + +const useSignMessage = (): UseSignMessageResult => { + const [account, setAccount] = useState(); + // TODO: replace this with new get endpoint + const [signature, setSignature] = useLocalStorage(`$tc-${account?.address}`); + const { selectedAccount } = useSubstrateSecureState(); + + // TODO: this function might be removed + const handleSuccess = (account?: KeyringPair) => { + if (!account) return; + setSignature(`$tc-${account.address}`); + }; + + const handleError = (error: Error) => console.log(error); + + const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { + onSuccess: () => handleSuccess(account), + onError: handleError + }); + + useEffect(() => { + if (!selectedAccount) return; + setAccount(selectedAccount); + }, [selectedAccount]); + + const handleSignMessage = (account?: KeyringPair) => { + // should not sign message if there is already a stored signature + if (!account || signature) return; + + signMessageMutation.mutate(account); + }; + + return { + hasSignature: process.env.REACT_APP_BITCOIN_NETWORK === BitcoinNetwork.Testnet || !!signature, + selectProp: { onSelectionChange: handleSignMessage }, + buttonProps: { onPress: () => handleSignMessage(selectedAccount) } + }; +}; + +export { useSignMessage }; +export type { UseSignMessageResult }; From 2846873cadfd072e6b71d7bc51f327e75bbee2df Mon Sep 17 00:00:00 2001 From: tomjeatt <40243778+tomjeatt@users.noreply.github.com> Date: Tue, 4 Apr 2023 16:04:29 +0100 Subject: [PATCH 07/69] hotifx: make kintsugi the only valid originating XCM chain (#1099) --- .../Transfer/CrossChainTransferForm/index.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pages/Transfer/CrossChainTransferForm/index.tsx b/src/pages/Transfer/CrossChainTransferForm/index.tsx index c5f88a6cda..06b64723ca 100644 --- a/src/pages/Transfer/CrossChainTransferForm/index.tsx +++ b/src/pages/Transfer/CrossChainTransferForm/index.tsx @@ -128,13 +128,17 @@ const CrossChainTransferForm = (): JSX.Element => { if (!XCMBridge) return; if (!XCMProvider) return; - const availableFromChains: Array = XCMBridge.adapters.map((adapter: any) => { - return { - type: adapter.chain.id, - name: adapter.chain.id, - icon: - }; - }); + const availableFromChains: Array = XCMBridge.adapters + // TODO: This is a kintsugi-only hotfix to temporarily disable + // originating chains other than kintsugi. + .filter((adapter) => adapter.chain.id === 'kintsugi') + .map((adapter: any) => { + return { + type: adapter.chain.id, + name: adapter.chain.id, + icon: + }; + }); setFromChains(availableFromChains); setFromChain(availableFromChains[0]); From 043a5cfb9025d0c5639564a629870464668b52fe Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 5 Apr 2023 09:04:01 +0100 Subject: [PATCH 08/69] chore: update Banxa link --- src/config/links.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/links.ts b/src/config/links.ts index e07131f0a2..437092b497 100644 --- a/src/config/links.ts +++ b/src/config/links.ts @@ -27,7 +27,7 @@ const LINK_QUERY_PARAMETERS = { } }; -const BANXA_LINK = `https://talisman.banxa.com`; +const BANXA_LINK = 'http://kintsugi.banxa.com/'; export { BANXA_LINK, From b7f4cd79cd9440972e96a1d441119721d16779a0 Mon Sep 17 00:00:00 2001 From: tomjeatt <40243778+tomjeatt@users.noreply.github.com> Date: Wed, 5 Apr 2023 10:11:34 +0100 Subject: [PATCH 09/69] Release/kintsugi/2.28.9 (#1098) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: add resolutions for various polkadot packages (#1089) * Fix input field width issue (#1090) * fix: input field width * fix: rename max weeks to total weeks * chore: bump ui version * chore: bump XCM bridge (#1093) * feat(Wallet): add page (#1001) * feat(Wallet): add page * feat: add WalletIcon * feat: copy address * wip * feat: staking table * feat: refactor and add lending * refactor: clean up code * wip * feat: add List card * continue * fix: continue * feat: continue * feat(CTALink): improve * feat: add responsiveness and swap handling * feat: final * feat: add responsive prop * fix: clean up List and Divider * feat: add tests * feat: add final tests * fix: code review * feat: add vesting and tests * fix: code review * Tom/bug/burn form collateral tokens (#1042) * refactor: loop collateral to get burnable tokens * refactor: revert previous change and simplify * refactor: add function to filter tokens * refactor: fetch collateral currencies and render token values * wip: form layout and translation * wip: set data and selected collateral * chore: remove console log * refactor: remove single collateral code * chore: comment * fix: incorrect USD value * chore: remove testing code * refactor: remove native token import * refactor: add BurnableCollateral type * refactor: add fullWidth prop and label to token selector * refactor: collateral icon * chore: add dictionary item * chore: remove unnecessary conditional operators * refactor: handle callback * refactor: fix failing test * chore: remove unused code * refactor: add success notification to burn form * Add CORS to market data (#1096) * chore: add env variables to config * chore: add cors to market data api --------- Co-authored-by: ns212 * fix: revert to using 0.2.x version of the bridge (#1095) * chore: improve price impact warning copy * chore: release v2.29.0 --------- Co-authored-by: Brendon Votteler Co-authored-by: Chanakya888 Co-authored-by: Daniel Simão Co-authored-by: ns212 Co-authored-by: Dominik Harz --- .env.dev | 6 +- .github/workflows/test.yml | 1 + package.json | 24 +- src/App.tsx | 7 + src/assets/icons/ArrowTopRightOnSquare.tsx | 25 + src/assets/icons/DocumentDuplicate.tsx | 25 + src/assets/icons/PencilSquare.tsx | 25 + src/assets/icons/index.ts | 3 + src/assets/locales/en/translation.json | 31 +- src/common/actions/general.actions.ts | 7 + src/common/reducers/general.reducer.ts | 4 + src/common/types/actions.types.ts | 9 +- src/common/types/util.types.ts | 1 + src/component-library/CTA/CTA.style.tsx | 1 + src/component-library/CTA/CTALink.tsx | 46 +- src/component-library/CTA/index.tsx | 2 + .../Divider/Divider.style.tsx | 12 +- src/component-library/Divider/Divider.tsx | 11 +- src/component-library/Flex/Flex.style.tsx | 4 +- src/component-library/Flex/Flex.tsx | 54 +- src/component-library/List/List.stories.tsx | 44 +- src/component-library/List/List.style.tsx | 48 +- src/component-library/List/List.tsx | 25 +- src/component-library/List/ListItem.tsx | 4 +- src/component-library/Switch/Switch.tsx | 11 +- src/component-library/Table/Table.stories.tsx | 5 +- src/component-library/TextLink/TextLink.tsx | 1 + .../WalletIcon/FallbackIcon.tsx | 17 + .../WalletIcon/WalletIcon.stories.tsx | 34 + .../WalletIcon/WalletIcon.style.tsx | 11 + .../WalletIcon/WalletIcon.tsx | 38 + .../WalletIcon/icons/PolkadotJS.tsx | 45 + .../WalletIcon/icons/SubWallet.tsx | 101 ++ .../WalletIcon/icons/Talisman.tsx | 39 + .../WalletIcon/icons/index.ts | 3 + src/component-library/WalletIcon/index.tsx | 2 + src/component-library/css/margin.ts | 21 + src/component-library/css/responsive.ts | 26 + src/component-library/index.tsx | 5 +- src/component-library/theme/theme.ts | 55 +- src/component-library/utils/breakpoints.ts | 17 + src/component-library/utils/prop-types.ts | 18 + .../utils/use-media-query.tsx | 44 + .../utils/use-style-props.tsx | 30 + src/components/DataGrid/AssetCell.tsx | 24 + src/components/DataGrid/BalanceCell.tsx | 20 + src/components/DataGrid/Cell.tsx | 33 + src/components/DataGrid/DataGrid.style.tsx | 21 + src/components/DataGrid/DataGrid.tsx | 35 + src/components/DataGrid/List.tsx | 44 + src/components/DataGrid/ListItem.tsx | 33 + src/components/DataGrid/Table.tsx | 38 + src/components/DataGrid/TableWrapper.tsx | 32 + src/components/DataGrid/index.tsx | 10 + .../LoanApyTooltip}/AssetGroup.tsx | 2 +- .../LoanApyTooltip}/BreakdownGroup.tsx | 4 +- .../LoanApyTooltip/LoanApyTooltip.style.tsx} | 0 .../LoanApyTooltip/LoanApyTooltip.tsx} | 12 +- .../LoanApyTooltip}/RewardsGroup.tsx | 2 +- src/components/LoanApyTooltip/index.tsx | 2 + .../LoanPositionsTable}/ApyCell.tsx | 15 +- .../LoanPositionsTable/LoanPositionsTable.tsx | 153 ++ .../LoanTablePlaceholder.tsx | 22 + src/components/LoanPositionsTable/index.tsx | 4 + .../PoolsTable}/PoolsTable.tsx | 52 +- src/components/PoolsTable/index.tsx | 2 + src/components/index.tsx | 6 + .../Tokens/TokenSelector/index.tsx | 12 +- src/legacy-components/Tokens/index.tsx | 33 +- .../components/PoolsTables/PoolsTables.tsx | 2 +- src/pages/AMM/Swap/Swap.tsx | 42 +- .../PriceImpactModal/PriceImpactModal.tsx | 2 +- .../AMM/Swap/components/SwapForm/SwapForm.tsx | 21 +- src/pages/Bridge/BurnForm/index.tsx | 159 ++- src/pages/Bridge/index.tsx | 19 +- .../components/ApyTooltip/index.tsx | 2 - .../BorrowAssetsTable.style.tsx | 9 +- .../BorrowAssetsTable/BorrowAssetsTable.tsx | 34 +- .../BorrowPositionsTable.style.tsx | 9 - .../BorrowPositionsTable.tsx | 93 -- .../components/BorrowPositionsTable/index.tsx | 2 - .../LendAssetsTable/LendAssetsTable.style.tsx | 9 - .../LendAssetsTable/LendAssetsTable.tsx | 34 +- .../LendPositionsTable.style.tsx | 9 - .../LendPositionsTable/LendPositionsTable.tsx | 106 -- .../components/LendPositionsTable/index.tsx | 2 - .../components/LoanActionInfo/LoanGroup.tsx | 2 +- .../LoanActionInfo/RewardsGroup.tsx | 4 +- .../components/LoansBaseTable/AssetCell.tsx | 18 - .../components/LoansBaseTable/BalanceCell.tsx | 26 - .../LoansBaseTable/LoanStatusTag.tsx | 22 - .../LoansBaseTable/LoansBaseTable.style.tsx | 49 - .../LoansBaseTable/LoansBaseTable.tsx | 51 - .../LoansBaseTable/MonetaryCell.tsx | 30 - .../components/LoansBaseTable/index.tsx | 8 - .../components/LoansTables/BorrowTables.tsx | 8 +- .../components/LoansTables/LendTables.tsx | 8 +- .../LoansTables/LoansTables.style.tsx | 28 +- src/pages/Staking/LockTimeField/index.tsx | 4 +- .../DespositCollateralStep.tsx | 2 +- .../components/InfoBox/InfoBox.stories.tsx | 28 - .../Wallet/WalletOverview/WalletOverview.tsx | 57 + .../AvailableAssetsTable/ActionsCell.tsx | 131 ++ .../AvailableAssetsTable.tsx | 130 ++ .../components/AvailableAssetsTable/index.tsx | 2 + .../components/StakingTable/StakingTable.tsx | 94 ++ .../components/StakingTable/index.tsx | 2 + .../WalletInsights/WalletInsights.style.tsx | 14 + .../WalletInsights/WalletInsights.tsx | 85 ++ .../components/WalletInsights/WalletMeta.tsx | 85 ++ .../components/WalletInsights/index.tsx | 2 + .../components/WalletInsights/utils.ts | 24 + .../WalletOverview/components/index.tsx | 6 + src/pages/Wallet/WalletOverview/index.tsx | 3 + src/pages/Wallet/index.tsx | 3 + .../SidebarContent/Navigation/index.tsx | 12 +- .../Topbar/GetGovernanceTokenUI/index.tsx | 12 +- .../mocks/@interlay/interbtc-api/index.ts | 22 +- .../@interlay/interbtc-api/parachain/amm.ts | 5 +- .../interbtc-api/parachain/escrow.ts | 25 + .../@interlay/interbtc-api/parachain/loans.ts | 2 +- .../interbtc-api/parachain/redeem.ts | 1 + .../interbtc-api/parachain/system.ts | 6 + .../interbtc-api/parachain/vesting.ts | 9 + src/test/pages/Burn.test.tsx | 24 +- src/test/pages/Loans/index.test.tsx | 6 +- src/test/pages/Swap.test.tsx | 24 + src/test/pages/Wallet.test.tsx | 250 ++++ src/test/pages/utils/common.ts | 6 + src/test/pages/utils/list.ts | 17 + src/test/pages/utils/table.ts | 9 +- src/test/test-utils.tsx | 7 +- src/utils/constants/links.ts | 9 +- src/utils/helpers/coin-icon.ts | 2 +- .../helpers/loans.ts} | 25 +- src/utils/helpers/pools.ts | 32 + .../escrow/use-get-account-staking-data.tsx | 71 + .../escrow/use-get-account-voting-balance.tsx | 37 + .../use-get-account-lending-statistics.tsx | 2 +- src/utils/hooks/api/use-get-currencies.tsx | 12 - src/utils/hooks/api/use-get-vesting-data.tsx | 50 + src/utils/hooks/api/xcm/use-xcm-bridge.ts | 6 +- src/utils/hooks/use-copy-tooltip.tsx | 63 + src/utils/hooks/use-feature-flag.ts | 6 +- yarn.lock | 1231 +++-------------- 145 files changed, 3147 insertions(+), 1869 deletions(-) create mode 100644 src/assets/icons/ArrowTopRightOnSquare.tsx create mode 100644 src/assets/icons/DocumentDuplicate.tsx create mode 100644 src/assets/icons/PencilSquare.tsx create mode 100644 src/component-library/WalletIcon/FallbackIcon.tsx create mode 100644 src/component-library/WalletIcon/WalletIcon.stories.tsx create mode 100644 src/component-library/WalletIcon/WalletIcon.style.tsx create mode 100644 src/component-library/WalletIcon/WalletIcon.tsx create mode 100644 src/component-library/WalletIcon/icons/PolkadotJS.tsx create mode 100644 src/component-library/WalletIcon/icons/SubWallet.tsx create mode 100644 src/component-library/WalletIcon/icons/Talisman.tsx create mode 100644 src/component-library/WalletIcon/icons/index.ts create mode 100644 src/component-library/WalletIcon/index.tsx create mode 100644 src/component-library/css/margin.ts create mode 100644 src/component-library/css/responsive.ts create mode 100644 src/component-library/utils/breakpoints.ts create mode 100644 src/component-library/utils/use-media-query.tsx create mode 100644 src/component-library/utils/use-style-props.tsx create mode 100644 src/components/DataGrid/AssetCell.tsx create mode 100644 src/components/DataGrid/BalanceCell.tsx create mode 100644 src/components/DataGrid/Cell.tsx create mode 100644 src/components/DataGrid/DataGrid.style.tsx create mode 100644 src/components/DataGrid/DataGrid.tsx create mode 100644 src/components/DataGrid/List.tsx create mode 100644 src/components/DataGrid/ListItem.tsx create mode 100644 src/components/DataGrid/Table.tsx create mode 100644 src/components/DataGrid/TableWrapper.tsx create mode 100644 src/components/DataGrid/index.tsx rename src/{pages/Loans/LoansOverview/components/ApyTooltip => components/LoanApyTooltip}/AssetGroup.tsx (93%) rename src/{pages/Loans/LoansOverview/components/ApyTooltip => components/LoanApyTooltip}/BreakdownGroup.tsx (94%) rename src/{pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.style.tsx => components/LoanApyTooltip/LoanApyTooltip.style.tsx} (100%) rename src/{pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.tsx => components/LoanApyTooltip/LoanApyTooltip.tsx} (89%) rename src/{pages/Loans/LoansOverview/components/ApyTooltip => components/LoanApyTooltip}/RewardsGroup.tsx (94%) create mode 100644 src/components/LoanApyTooltip/index.tsx rename src/{pages/Loans/LoansOverview/components/LoansBaseTable => components/LoanPositionsTable}/ApyCell.tsx (79%) create mode 100644 src/components/LoanPositionsTable/LoanPositionsTable.tsx create mode 100644 src/components/LoanPositionsTable/LoanTablePlaceholder.tsx create mode 100644 src/components/LoanPositionsTable/index.tsx rename src/{pages/AMM/Pools/components/PoolsTables => components/PoolsTable}/PoolsTable.tsx (65%) create mode 100644 src/components/PoolsTable/index.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/ApyTooltip/index.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/BorrowPositionsTable/BorrowPositionsTable.style.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/BorrowPositionsTable/BorrowPositionsTable.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/BorrowPositionsTable/index.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LendAssetsTable/LendAssetsTable.style.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LendPositionsTable/LendPositionsTable.style.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LendPositionsTable/LendPositionsTable.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LendPositionsTable/index.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/AssetCell.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/BalanceCell.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/LoanStatusTag.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/LoansBaseTable.style.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/LoansBaseTable.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/MonetaryCell.tsx delete mode 100644 src/pages/Loans/LoansOverview/components/LoansBaseTable/index.tsx delete mode 100644 src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.stories.tsx create mode 100644 src/pages/Wallet/WalletOverview/WalletOverview.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/ActionsCell.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/AvailableAssetsTable.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/index.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/StakingTable/StakingTable.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/StakingTable/index.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.style.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/WalletInsights/WalletMeta.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/WalletInsights/index.tsx create mode 100644 src/pages/Wallet/WalletOverview/components/WalletInsights/utils.ts create mode 100644 src/pages/Wallet/WalletOverview/components/index.tsx create mode 100644 src/pages/Wallet/WalletOverview/index.tsx create mode 100644 src/pages/Wallet/index.tsx create mode 100644 src/test/mocks/@interlay/interbtc-api/parachain/escrow.ts create mode 100644 src/test/mocks/@interlay/interbtc-api/parachain/vesting.ts create mode 100644 src/test/pages/Wallet.test.tsx create mode 100644 src/test/pages/utils/common.ts create mode 100644 src/test/pages/utils/list.ts rename src/{pages/Loans/LoansOverview/utils/get-subsidy-rewards-apy.ts => utils/helpers/loans.ts} (54%) create mode 100644 src/utils/helpers/pools.ts create mode 100644 src/utils/hooks/api/escrow/use-get-account-staking-data.tsx create mode 100644 src/utils/hooks/api/escrow/use-get-account-voting-balance.tsx create mode 100644 src/utils/hooks/api/use-get-vesting-data.tsx create mode 100644 src/utils/hooks/use-copy-tooltip.tsx diff --git a/.env.dev b/.env.dev index fd40ea1079..ac580353f8 100644 --- a/.env.dev +++ b/.env.dev @@ -1,8 +1,8 @@ /* FEATURE FLAGS */ -REACT_APP_FEATURE_FLAG_LENDING=disabled -REACT_APP_FEATURE_FLAG_AMM=disabled - +REACT_APP_FEATURE_FLAG_LENDING=enabled +REACT_APP_FEATURE_FLAG_AMM=enabled +REACT_APP_FEATURE_FLAG_WALLET=enabled /* DEVELOPMENT */ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0d5450023..03d6e5f643 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,7 @@ env: DOCKER_RELAY_CHAIN_CURRENCY: DOT REACT_APP_FEATURE_FLAG_LENDING: enabled REACT_APP_FEATURE_FLAG_AMM: enabled + REACT_APP_FEATURE_FLAG_WALLET: enabled jobs: lint: diff --git a/package.json b/package.json index a04eeee39b..cb4610b868 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "interbtc-ui", - "version": "2.28.8", + "version": "2.29.0", "private": true, "dependencies": { "@craco/craco": "^6.1.1", "@headlessui/react": "^1.1.1", "@heroicons/react": "^2.0.0", - "@interlay/bridge": "^0.2.3", + "@interlay/bridge": "^0.2.4", "@interlay/interbtc-api": "2.0.3", "@interlay/monetary-js": "0.7.2", "@polkadot/api": "9.14.2", @@ -20,6 +20,7 @@ "@react-aria/gridlist": "^3.1.2", "@react-aria/interactions": "^3.11.0", "@react-aria/label": "^3.4.3", + "@react-aria/link": "^3.4.0", "@react-aria/meter": "^3.2.1", "@react-aria/overlays": "^3.12.0", "@react-aria/progress": "^3.3.0", @@ -113,6 +114,7 @@ "eslint-plugin-simple-import-sort": "^7.0.0", "husky": "^8.0.1", "identity-obj-proxy": "^3.0.0", + "jest-matchmedia-mock": "^1.1.0", "lint-staged": "^10.5.4", "postcss": "7", "prettier": "2.2.1", @@ -128,7 +130,23 @@ "bn.js": "4.12.0", "react-error-overlay": "6.0.9", "styled-components": "^5", - "@types/history": "^4.7.1" + "@types/history": "^4.7.1", + "@polkadot/api": "^9.14.2", + "@polkadot/api-augment": "^9.14.2", + "@polkadot/api-base": "^9.14.2", + "@polkadot/api-contract": "^9.14.2", + "@polkadot/api-derive": "^9.14.2", + "@polkadot/rpc-augment": "^9.14.2", + "@polkadot/rpc-core": "^9.14.2", + "@polkadot/rpc-provider": "^9.14.2", + "@polkadot/types": "^9.14.2", + "@polkadot/types-augment": "^9.14.2", + "@polkadot/types-codec": "^9.14.2", + "@polkadot/types-create": "^9.14.2", + "@polkadot/types-known": "^9.14.2", + "@polkadot/types-support": "^9.14.2", + "@polkadot/util": "^10.2.4", + "@polkadot/util-crypto": "^10.2.4" }, "scripts": { "start": "craco start", diff --git a/src/App.tsx b/src/App.tsx index de336e0a25..fc2f89f241 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -37,6 +37,7 @@ const Vault = React.lazy(() => import(/* webpackChunkName: 'vault' */ '@/pages/V const Loans = React.lazy(() => import(/* webpackChunkName: 'loans' */ '@/pages/Loans')); const Swap = React.lazy(() => import(/* webpackChunkName: 'loans' */ '@/pages/AMM')); const Pools = React.lazy(() => import(/* webpackChunkName: 'loans' */ '@/pages/AMM/Pools')); +const Wallet = React.lazy(() => import(/* webpackChunkName: 'loans' */ '@/pages/Wallet')); const Actions = React.lazy(() => import(/* webpackChunkName: 'actions' */ '@/pages/Actions')); const NoMatch = React.lazy(() => import(/* webpackChunkName: 'no-match' */ '@/pages/NoMatch')); @@ -48,6 +49,7 @@ const App = (): JSX.Element => { const dispatch = useDispatch(); const isLendingEnabled = useFeatureFlag(FeatureFlags.LENDING); const isAMMEnabled = useFeatureFlag(FeatureFlags.AMM); + const isWalletEnabled = useFeatureFlag(FeatureFlags.WALLET); // Loads the connection to the faucet - only for testnet purposes const loadFaucet = React.useCallback(async (): Promise => { @@ -205,6 +207,11 @@ const App = (): JSX.Element => { )} + {isWalletEnabled && ( + + + + )} diff --git a/src/assets/icons/ArrowTopRightOnSquare.tsx b/src/assets/icons/ArrowTopRightOnSquare.tsx new file mode 100644 index 0000000000..68afeaa95c --- /dev/null +++ b/src/assets/icons/ArrowTopRightOnSquare.tsx @@ -0,0 +1,25 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const ArrowTopRightOnSquare = forwardRef((props, ref) => ( + + + +)); + +ArrowTopRightOnSquare.displayName = 'ArrowTopRightOnSquare'; + +export { ArrowTopRightOnSquare }; diff --git a/src/assets/icons/DocumentDuplicate.tsx b/src/assets/icons/DocumentDuplicate.tsx new file mode 100644 index 0000000000..9cb33fb1f1 --- /dev/null +++ b/src/assets/icons/DocumentDuplicate.tsx @@ -0,0 +1,25 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const DocumentDuplicate = forwardRef((props, ref) => ( + + + +)); + +DocumentDuplicate.displayName = 'DocumentDuplicate'; + +export { DocumentDuplicate }; diff --git a/src/assets/icons/PencilSquare.tsx b/src/assets/icons/PencilSquare.tsx new file mode 100644 index 0000000000..67493d6fa0 --- /dev/null +++ b/src/assets/icons/PencilSquare.tsx @@ -0,0 +1,25 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const PencilSquare = forwardRef((props, ref) => ( + + + +)); + +PencilSquare.displayName = 'PencilSquare'; + +export { PencilSquare }; diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index dd942553d2..7888df9310 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -1,7 +1,10 @@ export { ArrowsUpDown } from './ArrowsUpDown'; +export { ArrowTopRightOnSquare } from './ArrowTopRightOnSquare'; export { ChevronDown } from './ChevronDown'; export { Cog } from './Cog'; +export { DocumentDuplicate } from './DocumentDuplicate'; export { InformationCircle } from './InformationCircle'; +export { PencilSquare } from './PencilSquare'; export { PlusCircle } from './PlusCircle'; export { Warning } from './Warning'; export { XMark } from './XMark'; diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index 9e8dfcc585..f9d78922fa 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -89,6 +89,7 @@ "nav_terms_and_conditions": "Terms and Conditions", "nav_use_wrapped": "Use {{wrappedTokenSymbol}}", "nav_governance": "Governance", + "nav_wallet": "Wallet", "report_bug": "Report a bug:", "request_funds": "Faucet", "request_btc": "BTC Faucet", @@ -140,6 +141,17 @@ "insufficient_funds_fees": "Insufficient funds for fees", "successfully_claimed_rewards": "Successfully claimed rewards", "view_details": "View details", + "copied": "Copied", + "click_to_copy": "Click to copy", + "asset": "Asset", + "price": "Price", + "balance": "Balance", + "show_zero_balance": "Show Zero Balance", + "total_balance": "Total Balance", + "transferable_balance": "Transferable Balance", + "fund_wallet": "Fund Wallet", + "unlocks": "Unlocks", + "staked": "Staked", "redeem_page": { "maximum_in_single_request": "Max redeemable in single request", "redeem": "Redeem", @@ -236,8 +248,10 @@ } }, "burn_page": { - "burn_interbtc": "Burn {{wrappedTokenSymbol}} in exchange for {{collateralTokenSymbol}}", - "available": "{{wrappedTokenSymbol}} available to burn", + "burn_interbtc": "Burn {{wrappedTokenSymbol}}", + "available_total": "Total available {{wrappedTokenSymbol}} to burn", + "available_from_collateral": "{{wrappedTokenSymbol}} available to burn from {{collateralTokenSymbol}}", + "collateral_selector_label": "In exchange for", "burn": "Burn", "please_enter_the_amount": "Please enter the amount.", "successfully_burned": "Successfully burned.", @@ -555,7 +569,9 @@ "lend": "Lend", "my_lend_positions": "My Lend Positions", "my_borrow_positions": "My Borrow Positions", - "action_liquidation_risk": "{{action}} this amount will increase your LTV, thus also increasing the risk of liquidation." + "action_liquidation_risk": "{{action}} this amount will increase your LTV, thus also increasing the risk of liquidation.", + "no_loan_positions": "No {{loanType}} positions", + "your_loan_positions_will_show_here": "Your {{loanType}} positions will show here" }, "amm": { "pools": { @@ -573,7 +589,7 @@ "insufficient_liquidity_trade": "Insufficient liquidity for this trade", "from": "From", "to": "To", - "swap_has_price_inpact_of": "This swap has a price impact of", + "swap_has_price_inpact_of": "Considering external price sources, this swap has a price impact of", "you_are_swapping_input_for_output": "Your are swapping {{inputAmount}} {{inputTicker}} ({{inputAmountUSD}}) for {{outputAmount}} {{outputTicker}} ({{outputAmountUSD}})", "cancel_swap": "Cancel swap", "confirm_swap": "Confirm swap" @@ -593,5 +609,12 @@ "transfer_more_than_minimum": "Must transfer more than the minimum amount of {{ amount }}", "transfer_less_than_maximum": "Must transfer less than the maximum amount of {{ amount }}" } + }, + "wallet": { + "available_assets": "Available assets", + "no_assets_available": "No assets available", + "total_governance_locked": "Total {{token}} Locked", + "available_to_stake": "Available to stake", + "voting_power_governance": "Voting Power {{token}}" } } diff --git a/src/common/actions/general.actions.ts b/src/common/actions/general.actions.ts index c609d6b1cb..c6c464f6e1 100644 --- a/src/common/actions/general.actions.ts +++ b/src/common/actions/general.actions.ts @@ -13,7 +13,9 @@ import { IsFaucetLoaded, IsVaultClientLoaded, SHOW_ACCOUNT_MODAL, + SHOW_BUY_MODAL, ShowAccountModal, + ShowBuyModal, UPDATE_HEIGHTS, UPDATE_TOTALS, UpdateHeights, @@ -58,6 +60,11 @@ export const showAccountModalAction = (showAccountModal: boolean): ShowAccountMo showAccountModal }); +export const showBuyModal = (isBuyModalOpen: boolean): ShowBuyModal => ({ + type: SHOW_BUY_MODAL, + isBuyModalOpen +}); + export const updateHeightsAction = (btcRelayHeight: number, bitcoinHeight: number): UpdateHeights => ({ type: UPDATE_HEIGHTS, btcRelayHeight, diff --git a/src/common/reducers/general.reducer.ts b/src/common/reducers/general.reducer.ts index 6414b1e1bb..e4d93c5361 100644 --- a/src/common/reducers/general.reducer.ts +++ b/src/common/reducers/general.reducer.ts @@ -9,6 +9,7 @@ import { IS_BRIDGE_LOADED, IS_VAULT_CLIENT_LOADED, SHOW_ACCOUNT_MODAL, + SHOW_BUY_MODAL, UPDATE_HEIGHTS, UPDATE_TOTALS } from '../types/actions.types'; @@ -19,6 +20,7 @@ const initialState = { vaultClientLoaded: false, hasFeedbackModalBeenDisplayed: false, showAccountModal: false, + isBuyModalOpen: false, totalWrappedTokenAmount: BitcoinAmount.zero(), totalLockedCollateralTokenAmount: newMonetaryAmount(0, RELAY_CHAIN_NATIVE_TOKEN), btcRelayHeight: 0, @@ -57,6 +59,8 @@ export const generalReducer = (state: GeneralState = initialState, action: Gener return { ...state, vaultClientLoaded: action.isLoaded }; case SHOW_ACCOUNT_MODAL: return { ...state, showAccountModal: action.showAccountModal }; + case SHOW_BUY_MODAL: + return { ...state, isBuyModalOpen: action.isBuyModalOpen }; default: return state; } diff --git a/src/common/types/actions.types.ts b/src/common/types/actions.types.ts index c1ddaefba7..bfc8d94628 100644 --- a/src/common/types/actions.types.ts +++ b/src/common/types/actions.types.ts @@ -18,6 +18,7 @@ export const UPDATE_COLLATERAL_TOKEN_TRANSFERABLE_BALANCE = 'UPDATE_COLLATERAL_T export const SHOW_ACCOUNT_MODAL = 'SHOW_ACCOUNT_MODAL'; export const UPDATE_HEIGHTS = 'UPDATE_HEIGHTS'; export const UPDATE_TOTALS = 'UPDATE_TOTALS'; +export const SHOW_BUY_MODAL = 'SHOW_BUY_MODAL'; export interface UpdateTotals { type: typeof UPDATE_TOTALS; @@ -86,6 +87,11 @@ export interface ShowAccountModal { showAccountModal: boolean; } +export interface ShowBuyModal { + type: typeof SHOW_BUY_MODAL; + isBuyModalOpen: boolean; +} + export type GeneralActions = | IsBridgeLoaded | InitGeneralDataAction @@ -96,7 +102,8 @@ export type GeneralActions = | UpdateCollateralTokenTransferableBalance | ShowAccountModal | UpdateHeights - | UpdateTotals; + | UpdateTotals + | ShowBuyModal; // REDEEM export const ADD_VAULT_REDEEMS = 'ADD_VAULT_REDEEMS'; diff --git a/src/common/types/util.types.ts b/src/common/types/util.types.ts index f3cc043d6a..70f39523e6 100644 --- a/src/common/types/util.types.ts +++ b/src/common/types/util.types.ts @@ -49,6 +49,7 @@ export type GeneralState = { bridgeLoaded: boolean; vaultClientLoaded: boolean; showAccountModal: boolean; + isBuyModalOpen: boolean; totalWrappedTokenAmount: BitcoinAmount; totalLockedCollateralTokenAmount: MonetaryAmount; btcRelayHeight: number; diff --git a/src/component-library/CTA/CTA.style.tsx b/src/component-library/CTA/CTA.style.tsx index 3c1e833c6d..017da13651 100644 --- a/src/component-library/CTA/CTA.style.tsx +++ b/src/component-library/CTA/CTA.style.tsx @@ -23,6 +23,7 @@ const BaseCTA = styled.button` text-decoration: none; width: ${(props) => (props.$fullWidth ? '100%' : 'auto')}; background: none; + // TODO: enforce outline outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'}; &[aria-disabled='true'], diff --git a/src/component-library/CTA/CTALink.tsx b/src/component-library/CTA/CTALink.tsx index f0e3a3eea5..bc6809d758 100644 --- a/src/component-library/CTA/CTALink.tsx +++ b/src/component-library/CTA/CTALink.tsx @@ -1,6 +1,10 @@ +import { useFocusRing } from '@react-aria/focus'; +import { useLink } from '@react-aria/link'; +import { mergeProps } from '@react-aria/utils'; import { forwardRef } from 'react'; import { Link, LinkProps } from 'react-router-dom'; +import { useDOMRef } from '../utils/dom'; import { BaseCTA, BaseCTAProps } from './BaseCTA'; type Props = { @@ -8,28 +12,44 @@ type Props = { disabled?: boolean; }; -type NativeAttrs = Omit; +type NativeAttrs = Omit; -type InheritAttrs = Omit; +type AriaAttrs = Omit; -type CTALinkProps = Props & NativeAttrs & InheritAttrs; +type InheritAttrs = Omit; + +type CTALinkProps = Props & NativeAttrs & AriaAttrs & InheritAttrs; // TODO: Does this need to be changed to a React Router link component? const CTALink = forwardRef( - ({ disabled, onClick, external, to, ...props }, ref): JSX.Element => { - const linkProps: LinkProps = external - ? { to: { pathname: to as string }, target: '_blank', rel: 'noreferrer' } - : { to }; + ({ disabled, external, to: toProp, children, ...props }, ref): JSX.Element => { + const linkRef = useDOMRef(ref); + + const ariaProps = { + ...props, + isDisabled: disabled, + href: toProp, + ...(external && { target: '_blank', rel: 'noreferrer' }) + }; + + const { linkProps } = useLink(ariaProps, linkRef); + const { focusProps, isFocusVisible } = useFocusRing(); + + const to = external && typeof toProp === 'string' ? { pathname: toProp as string } : toProp; return ( + isFocusVisible={isFocusVisible} + {...mergeProps(props, linkProps, focusProps, { + href: undefined, + to, + ...(external && { target: '_blank', rel: 'noreferrer' }) + })} + > + {children} + ); } ); diff --git a/src/component-library/CTA/index.tsx b/src/component-library/CTA/index.tsx index 8e53ab575c..01bda90ceb 100644 --- a/src/component-library/CTA/index.tsx +++ b/src/component-library/CTA/index.tsx @@ -1,3 +1,5 @@ +export type { BaseCTAProps } from './BaseCTA'; +export { BaseCTA } from './BaseCTA'; export type { CTAProps } from './CTA'; export { CTA } from './CTA'; export type { CTALinkProps } from './CTALink'; diff --git a/src/component-library/Divider/Divider.style.tsx b/src/component-library/Divider/Divider.style.tsx index 9e76398fe0..28d8b361bc 100644 --- a/src/component-library/Divider/Divider.style.tsx +++ b/src/component-library/Divider/Divider.style.tsx @@ -1,17 +1,19 @@ import styled from 'styled-components'; -import { Colors, Orientation } from '../utils/prop-types'; +import { theme } from '../theme'; +import { DividerVariants, Orientation, Sizes } from '../utils/prop-types'; import { resolveColor } from '../utils/theme'; type StyledDividerProps = { - $color: Colors; + $color: DividerVariants; $orientation: Orientation; + $size: Sizes; }; const StyledDivider = styled.hr` - background-color: ${({ $color }) => resolveColor($color)}; - height: ${({ $orientation }) => ($orientation === 'horizontal' ? '2px' : 'auto')}; - width: ${({ $orientation }) => ($orientation === 'horizontal' ? '' : '2px')}; + background-color: ${({ $color }) => ($color === 'default' ? 'var(--colors-border)' : resolveColor($color))}; + height: ${({ $orientation, $size }) => ($orientation === 'horizontal' ? theme.divider.size[$size] : 'auto')}; + width: ${({ $orientation, $size }) => ($orientation === 'horizontal' ? '' : theme.divider.size[$size])}; border: 0; margin: 0; align-self: stretch; diff --git a/src/component-library/Divider/Divider.tsx b/src/component-library/Divider/Divider.tsx index 3d00633b53..6d1e3cebfa 100644 --- a/src/component-library/Divider/Divider.tsx +++ b/src/component-library/Divider/Divider.tsx @@ -2,12 +2,13 @@ import { useSeparator } from '@react-aria/separator'; import { mergeProps } from '@react-aria/utils'; import { forwardRef, HTMLAttributes } from 'react'; -import { Colors, ElementTypeProp, Orientation } from '../utils/prop-types'; +import { DividerVariants, ElementTypeProp, Orientation, Sizes } from '../utils/prop-types'; import { StyledDivider } from './Divider.style'; type Props = { orientation?: Orientation; - color?: Colors; + color?: DividerVariants; + size?: Sizes; }; type NativeAttrs = Omit, keyof Props>; @@ -15,7 +16,10 @@ type NativeAttrs = Omit, keyof Props>; type DividerProps = Props & NativeAttrs & ElementTypeProp; const Divider = forwardRef( - ({ elementType: elementTypeProp, orientation = 'horizontal', color = 'primary', ...props }, ref): JSX.Element => { + ( + { elementType: elementTypeProp, orientation = 'horizontal', color = 'primary', size = 'small', ...props }, + ref + ): JSX.Element => { const elementType = elementTypeProp || orientation === 'vertical' ? 'div' : 'hr'; const { separatorProps } = useSeparator({ @@ -29,6 +33,7 @@ const Divider = forwardRef( as={elementType} $color={color} $orientation={orientation} + $size={size} {...mergeProps(separatorProps, props)} /> ); diff --git a/src/component-library/Flex/Flex.style.tsx b/src/component-library/Flex/Flex.style.tsx index d51fe623e5..a039d16252 100644 --- a/src/component-library/Flex/Flex.style.tsx +++ b/src/component-library/Flex/Flex.style.tsx @@ -1,5 +1,6 @@ import styled from 'styled-components'; +import { marginCSS, StyledMarginProps } from '../css/margin'; import { theme } from '../theme'; import { AlignItems, AlignSelf, Direction, JustifyContent, Spacing, Wrap } from '../utils/prop-types'; @@ -11,7 +12,7 @@ type StyledFlexProps = { $flex?: string | number; $wrap?: Wrap; $alignSelf?: AlignSelf; -}; +} & StyledMarginProps; const StyledFlex = styled.div` display: flex; @@ -22,6 +23,7 @@ const StyledFlex = styled.div` flex: ${(props) => props.$flex}; flex-wrap: ${(props) => (typeof props.$wrap === 'boolean' ? 'wrap' : props.$wrap)}; align-self: ${(props) => props.$alignSelf}; + ${(props) => marginCSS(props)}; `; export { StyledFlex }; diff --git a/src/component-library/Flex/Flex.tsx b/src/component-library/Flex/Flex.tsx index ecc9da416c..827db075dc 100644 --- a/src/component-library/Flex/Flex.tsx +++ b/src/component-library/Flex/Flex.tsx @@ -1,6 +1,16 @@ -import { ElementType, forwardRef, HTMLAttributes } from 'react'; +import { forwardRef, HTMLAttributes } from 'react'; -import { AlignItems, AlignSelf, Direction, ElementTypeProp, JustifyContent, Spacing, Wrap } from '../utils/prop-types'; +import { + AlignItems, + AlignSelf, + Direction, + ElementTypeProp, + JustifyContent, + MarginProps, + Spacing, + Wrap +} from '../utils/prop-types'; +import { useStyleProps } from '../utils/use-style-props'; import { StyledFlex } from './Flex.style'; type Props = { @@ -11,33 +21,37 @@ type Props = { flex?: string | number; wrap?: Wrap | boolean; alignSelf?: AlignSelf; - elementType?: ElementType; }; type NativeAttrs = Omit, keyof Props>; -type FlexProps = Props & NativeAttrs & ElementTypeProp; +type FlexProps = Props & NativeAttrs & ElementTypeProp & MarginProps; const Flex = forwardRef( ( { children, gap, justifyContent, alignItems, direction, flex, wrap, alignSelf, elementType, ...props }, ref - ): JSX.Element => ( - - {children} - - ) + ): JSX.Element => { + const { styleProps, componentProps } = useStyleProps(props); + + return ( + + {children} + + ); + } ); Flex.displayName = 'Flex'; diff --git a/src/component-library/List/List.stories.tsx b/src/component-library/List/List.stories.tsx index f03b0b8cbf..8ad79ac4a3 100644 --- a/src/component-library/List/List.stories.tsx +++ b/src/component-library/List/List.stories.tsx @@ -3,23 +3,25 @@ import { Meta, Story } from '@storybook/react'; import { List, ListItem, ListProps } from '.'; const Template: Story = (args) => ( - - - IBTC - - - KINT - - - INTR - - - KSM - - - DOT - - +
+ + + IBTC + + + KINT + + + INTR + + + KSM + + + DOT + + +
); const Default = Template.bind({}); @@ -27,7 +29,13 @@ Default.args = { selectionMode: 'single' }; -export { Default }; +const Cards = Template.bind({}); +Cards.args = { + selectionMode: 'single', + variant: 'card' +}; + +export { Cards, Default }; export default { title: 'Collections/List', diff --git a/src/component-library/List/List.style.tsx b/src/component-library/List/List.style.tsx index 6117eacd01..1e6d436bfd 100644 --- a/src/component-library/List/List.style.tsx +++ b/src/component-library/List/List.style.tsx @@ -1,10 +1,22 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; +import { Flex } from '../Flex'; import { theme } from '../theme'; -import { Variants } from '../utils/prop-types'; +import { ListVariants, Variants } from '../utils/prop-types'; + +type StyledListProps = { + $variant: ListVariants; +}; + +const StyledList = styled(Flex)` + background-color: ${({ $variant }) => theme.list?.[$variant]?.bg}; + border-radius: ${({ $variant }) => theme.list[$variant].rounded}; + border: ${({ $variant }) => theme.list[$variant].border}; + overflow: hidden; +`; type StyledListItemProps = { - $variant: Variants; + $variant: Variants | 'card'; $isDisabled: boolean; $isHovered: boolean; $isInteractable: boolean; @@ -15,19 +27,31 @@ const StyledListItem = styled.li` flex: 1; align-self: stretch; padding: ${theme.spacing.spacing3}; - border-radius: ${theme.rounded.md}; + border-radius: ${({ $variant }) => theme.list.item[$variant].rounded}; background-color: ${({ $variant, $isHovered, $isFocusVisible }) => - $isHovered || $isFocusVisible ? theme.list[$variant].hover.bg : theme.list[$variant].bg}; - border: ${({ $variant }) => theme.list[$variant].border}; + $isHovered || $isFocusVisible ? theme.list.item[$variant].hover.bg : theme.list.item[$variant].bg}; + border: ${({ $variant }) => $variant !== 'card' && theme.list.item[$variant].border}; color: ${theme.colors.textPrimary}; cursor: ${({ $isInteractable }) => $isInteractable && 'pointer'}; outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'}; - &[aria-selected='true'] { - background-color: ${theme.colors.textSecondary}; - color: ${theme.list.text}; - border-color: ${theme.colors.textSecondary}; - } + ${({ $variant }) => { + if ($variant === 'card') { + return css` + &:not(:first-of-type) { + border-top: ${theme.list.item.card.border}; + } + `; + } + + return css` + &[aria-selected='true'] { + background-color: ${theme.colors.textSecondary}; + color: ${theme.list.text}; + border-color: ${theme.colors.textSecondary}; + } + `; + }} `; -export { StyledListItem }; +export { StyledList, StyledListItem }; diff --git a/src/component-library/List/List.tsx b/src/component-library/List/List.tsx index 5901f9f6e2..34b5e81eea 100644 --- a/src/component-library/List/List.tsx +++ b/src/component-library/List/List.tsx @@ -1,18 +1,22 @@ -import { useGridList } from '@react-aria/gridlist'; +import { AriaGridListOptions, useGridList } from '@react-aria/gridlist'; import { mergeProps } from '@react-aria/utils'; import { ListProps as StatelyListProps, useListState } from '@react-stately/list'; import { forwardRef } from 'react'; -import { Flex, FlexProps } from '../Flex'; +import { FlexProps } from '../Flex'; import { useDOMRef } from '../utils/dom'; -import { Variants } from '../utils/prop-types'; +import { ListVariants } from '../utils/prop-types'; +import { StyledList } from './List.style'; import { ListItem } from './ListItem'; type Props = { - variant?: Variants; + variant?: ListVariants; }; -type InheritAttrs = Omit>, keyof Props>; +type InheritAttrs = Omit< + StatelyListProps> & AriaGridListOptions>, + keyof Props +>; type NativeAttrs = Omit; @@ -26,11 +30,18 @@ const List = forwardRef( const { gridProps } = useGridList(ariaProps, state, listRef); return ( - + {[...state.collection].map((item) => ( ))} - + ); } ); diff --git a/src/component-library/List/ListItem.tsx b/src/component-library/List/ListItem.tsx index 07f0c38bcf..d3c9540d43 100644 --- a/src/component-library/List/ListItem.tsx +++ b/src/component-library/List/ListItem.tsx @@ -8,11 +8,11 @@ import { Node } from '@react-types/shared'; import { useMemo, useRef } from 'react'; import { Flex, FlexProps } from '../Flex'; -import { Variants } from '../utils/prop-types'; +import { ListVariants } from '../utils/prop-types'; import { StyledListItem } from './List.style'; type Props = { - variant?: Variants; + variant?: ListVariants; }; type InheritAttrs = Omit; diff --git a/src/component-library/Switch/Switch.tsx b/src/component-library/Switch/Switch.tsx index e407011a51..b478e0ef52 100644 --- a/src/component-library/Switch/Switch.tsx +++ b/src/component-library/Switch/Switch.tsx @@ -4,13 +4,13 @@ import { AriaSwitchProps, useSwitch } from '@react-aria/switch'; import { mergeProps } from '@react-aria/utils'; import { useToggleState } from '@react-stately/toggle'; import { PressEvent } from '@react-types/shared'; -import React, { forwardRef, HTMLAttributes, useRef } from 'react'; +import { ChangeEvent, forwardRef, HTMLAttributes, useRef } from 'react'; import { useDOMRef } from '../utils/dom'; import { StyledInput, StyledLabel, StyledSwitch, StyledWrapper } from './Switch.style'; type Props = { - onChange?: (e: React.ChangeEvent) => void; + onChange?: (e: ChangeEvent) => void; onPress?: (e: PressEvent) => void; }; @@ -20,13 +20,16 @@ type InheritAttrs = Omit; type SwitchProps = Props & NativeAttrs & InheritAttrs; +// TODO: add size const Switch = forwardRef( ({ children, onChange, className, style, hidden, ...props }, ref): JSX.Element => { const labelRef = useDOMRef(ref); const inputRef = useRef(null); - const state = useToggleState(props); - const { inputProps } = useSwitch(props, state, inputRef); + const ariaProps: AriaSwitchProps = { children, ...props }; + + const state = useToggleState(ariaProps); + const { inputProps } = useSwitch(ariaProps, state, inputRef); const { focusProps, isFocusVisible } = useFocusRing({ autoFocus: inputProps.autoFocus diff --git a/src/component-library/Table/Table.stories.tsx b/src/component-library/Table/Table.stories.tsx index f24086cafb..5aff3651b7 100644 --- a/src/component-library/Table/Table.stories.tsx +++ b/src/component-library/Table/Table.stories.tsx @@ -21,10 +21,7 @@ const Template: Story = (args) => { const Default = Template.bind({}); Default.args = {}; -const RowAction = Template.bind({}); -RowAction.args = { onRowAction: (key) => console.log(key) }; - -export { Default, RowAction }; +export { Default }; export default { title: 'Components/Table', diff --git a/src/component-library/TextLink/TextLink.tsx b/src/component-library/TextLink/TextLink.tsx index a31f6b54dd..87c8241811 100644 --- a/src/component-library/TextLink/TextLink.tsx +++ b/src/component-library/TextLink/TextLink.tsx @@ -13,6 +13,7 @@ type NativeAttrs = Omit; type TextLinkProps = Props & NativeAttrs; +// TODO: merge this with CTALink const TextLink = forwardRef( ({ color = 'primary', external, to, ...props }, ref): JSX.Element => { const linkProps: TextLinkProps = external diff --git a/src/component-library/WalletIcon/FallbackIcon.tsx b/src/component-library/WalletIcon/FallbackIcon.tsx new file mode 100644 index 0000000000..5520635a0d --- /dev/null +++ b/src/component-library/WalletIcon/FallbackIcon.tsx @@ -0,0 +1,17 @@ +import { forwardRef } from 'react'; + +import { WalletIconProps } from './WalletIcon'; +import { StyledFallbackIcon } from './WalletIcon.style'; + +const FallbackIcon = forwardRef( + ({ name, ...props }, ref): JSX.Element => ( + + {name} + + + ) +); + +FallbackIcon.displayName = 'FallbackIcon'; + +export { FallbackIcon }; diff --git a/src/component-library/WalletIcon/WalletIcon.stories.tsx b/src/component-library/WalletIcon/WalletIcon.stories.tsx new file mode 100644 index 0000000000..fc65b0077b --- /dev/null +++ b/src/component-library/WalletIcon/WalletIcon.stories.tsx @@ -0,0 +1,34 @@ +import { Meta, Story } from '@storybook/react'; + +import { Flex } from '../Flex'; +import { Span } from '../Text'; +import { WalletIcon, WalletIconProps } from './WalletIcon'; + +const Template: Story = (args) => ( + + + + SubWallet + + + + Talisman + + + + Polkadot.js + + +); + +const Default = Template.bind({}); +Default.args = { + size: 'xl' +}; + +export { Default }; + +export default { + title: 'Elements/WalletIcon', + component: WalletIcon +} as Meta; diff --git a/src/component-library/WalletIcon/WalletIcon.style.tsx b/src/component-library/WalletIcon/WalletIcon.style.tsx new file mode 100644 index 0000000000..9c5cc225c7 --- /dev/null +++ b/src/component-library/WalletIcon/WalletIcon.style.tsx @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +import { Icon } from '../Icon'; +import { theme } from '../theme'; + +const StyledFallbackIcon = styled(Icon)` + stroke: ${theme.icon.fallback.stroke}; + color: ${theme.icon.fallback.color}; +`; + +export { StyledFallbackIcon }; diff --git a/src/component-library/WalletIcon/WalletIcon.tsx b/src/component-library/WalletIcon/WalletIcon.tsx new file mode 100644 index 0000000000..b6834d6b12 --- /dev/null +++ b/src/component-library/WalletIcon/WalletIcon.tsx @@ -0,0 +1,38 @@ +import { forwardRef, ForwardRefExoticComponent, RefAttributes } from 'react'; + +import { IconProps } from '../Icon'; +import { FallbackIcon } from './FallbackIcon'; +import { PolkadotJS, SubWallet, Talisman } from './icons'; + +type WalletComponent = ForwardRefExoticComponent>; + +const wallet: Record = { + 'polkadot-js': PolkadotJS, + 'subwallet-js': SubWallet, + talisman: Talisman +}; + +type Props = { + name: string; +}; + +type NativeAttrs = Omit; + +type WalletIconProps = Props & NativeAttrs; + +const WalletIcon = forwardRef( + ({ name, ...props }, ref): JSX.Element => { + const WalletIcon = wallet[name]; + + if (!WalletIcon) { + return ; + } + + return ; + } +); + +WalletIcon.displayName = 'WalletIcon'; + +export { WalletIcon }; +export type { WalletIconProps }; diff --git a/src/component-library/WalletIcon/icons/PolkadotJS.tsx b/src/component-library/WalletIcon/icons/PolkadotJS.tsx new file mode 100644 index 0000000000..eeb174462e --- /dev/null +++ b/src/component-library/WalletIcon/icons/PolkadotJS.tsx @@ -0,0 +1,45 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const PolkadotJS = forwardRef((props, ref) => ( + + Polakdot.js + + + + + + + + +)); + +PolkadotJS.displayName = 'PolkadotJS'; + +export { PolkadotJS }; diff --git a/src/component-library/WalletIcon/icons/SubWallet.tsx b/src/component-library/WalletIcon/icons/SubWallet.tsx new file mode 100644 index 0000000000..6c760f802a --- /dev/null +++ b/src/component-library/WalletIcon/icons/SubWallet.tsx @@ -0,0 +1,101 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const SubWallet = forwardRef((props, ref) => ( + + SubWallet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)); + +SubWallet.displayName = 'SubWallet'; + +export { SubWallet }; diff --git a/src/component-library/WalletIcon/icons/Talisman.tsx b/src/component-library/WalletIcon/icons/Talisman.tsx new file mode 100644 index 0000000000..03eb5c8501 --- /dev/null +++ b/src/component-library/WalletIcon/icons/Talisman.tsx @@ -0,0 +1,39 @@ +import { forwardRef } from 'react'; + +import { Icon, IconProps } from '@/component-library/Icon'; + +const Talisman = forwardRef((props, ref) => ( + + Talisman + + + + + + + + + + +)); + +Talisman.displayName = 'Talisman'; + +export { Talisman }; diff --git a/src/component-library/WalletIcon/icons/index.ts b/src/component-library/WalletIcon/icons/index.ts new file mode 100644 index 0000000000..b8e4fc140a --- /dev/null +++ b/src/component-library/WalletIcon/icons/index.ts @@ -0,0 +1,3 @@ +export { PolkadotJS } from './PolkadotJS'; +export { SubWallet } from './SubWallet'; +export { Talisman } from './Talisman'; diff --git a/src/component-library/WalletIcon/index.tsx b/src/component-library/WalletIcon/index.tsx new file mode 100644 index 0000000000..131f35ecae --- /dev/null +++ b/src/component-library/WalletIcon/index.tsx @@ -0,0 +1,2 @@ +export type { WalletIconProps } from './WalletIcon'; +export { WalletIcon } from './WalletIcon'; diff --git a/src/component-library/css/margin.ts b/src/component-library/css/margin.ts new file mode 100644 index 0000000000..7214ed4d91 --- /dev/null +++ b/src/component-library/css/margin.ts @@ -0,0 +1,21 @@ +import { css, DefaultTheme, FlattenInterpolation } from 'styled-components'; + +import { theme } from '../theme'; +import { MarginProps, Spacing } from '../utils/prop-types'; + +type StyledMarginProps = { + [K in keyof MarginProps as `$${string & K}`]: MarginProps[K]; +}; + +const getThemeSpacing = (spacing?: Spacing) => spacing && theme.spacing[spacing]; + +const marginCSS = (props: StyledMarginProps): FlattenInterpolation => css` + margin: ${getThemeSpacing(props.$margin)}; + margin-top: ${getThemeSpacing(props.$marginTop || props.$marginY)}; + margin-bottom: ${getThemeSpacing(props.$marginBottom || props.$marginY)}; + margin-left: ${getThemeSpacing(props.$marginLeft || props.$marginX)}; + margin-right: ${getThemeSpacing(props.$marginRight || props.$marginX)}; +`; + +export type { StyledMarginProps }; +export { marginCSS }; diff --git a/src/component-library/css/responsive.ts b/src/component-library/css/responsive.ts new file mode 100644 index 0000000000..f8b293b1a8 --- /dev/null +++ b/src/component-library/css/responsive.ts @@ -0,0 +1,26 @@ +import { theme } from '../theme'; +import { BreakPoints, ResponsiveProp } from '../utils/prop-types'; + +const getResponsiveCSS = (key: string, prop?: ResponsiveProp): string | undefined => { + if (!prop) return undefined; + + if (typeof prop === 'object') { + let finalQuery = ''; + + for (const breakpoint of Object.keys(prop)) { + const query = ` + @media (min-width: ${theme.breakpoints.values[breakpoint as BreakPoints]}px){ + ${key}: ${prop[breakpoint as BreakPoints]}; + } + `; + + finalQuery = finalQuery.concat(query); + } + + return finalQuery; + } + + return `${key}: ${prop};`; +}; + +export { getResponsiveCSS }; diff --git a/src/component-library/index.tsx b/src/component-library/index.tsx index 6f2c8457b8..809606ecc7 100644 --- a/src/component-library/index.tsx +++ b/src/component-library/index.tsx @@ -36,7 +36,7 @@ export type { StackProps } from './Stack'; export { Stack } from './Stack'; export type { SwitchProps } from './Switch'; export { Switch } from './Switch'; -export type { TableProps } from './Table'; +export type { ColumnProps, RowProps, TableProps } from './Table'; export { Table } from './Table'; export type { TabsItemProps, TabsProps } from './Tabs'; export { Tabs, TabsItem } from './Tabs'; @@ -54,3 +54,6 @@ export type { TooltipProps } from './Tooltip'; export { Tooltip } from './Tooltip'; export * from './types'; export * from './utils/prop-types'; +export { useMediaQuery } from './utils/use-media-query'; +export type { WalletIconProps } from './WalletIcon'; +export { WalletIcon } from './WalletIcon'; diff --git a/src/component-library/theme/theme.ts b/src/component-library/theme/theme.ts index 824e710b93..d4d69a1fff 100644 --- a/src/component-library/theme/theme.ts +++ b/src/component-library/theme/theme.ts @@ -1,3 +1,5 @@ +import { breakpoints } from '../utils/breakpoints'; + const theme = { // Layout layout: { @@ -7,6 +9,7 @@ const theme = { lg: '48em' } }, + breakpoints, // Generic colors: { textPrimary: 'var(--colors-text-primary)', @@ -425,7 +428,12 @@ const theme = { } }, divider: { - bg: 'var(--colors-border)' + bg: 'var(--colors-border)', + size: { + small: '1px', + medium: '2px', + large: '3px' + } }, icon: { sizes: { @@ -443,17 +451,44 @@ const theme = { list: { text: 'var(--color-list-selected-text)', primary: { - bg: 'var(--color-list-primary-bg)', - border: '1px solid var(--colors-border)', - hover: { - bg: 'var(--color-list-primary-hover-bg)' - } + bg: '', + border: '', + rounded: '' }, secondary: { - bg: 'var(--color-list-secondary-bg)', - border: 'none', - hover: { - bg: 'var(--color-list-secondary-hover-bg)' + bg: '', + border: '', + rounded: '' + }, + card: { + bg: 'var(--colors-table-odd-row-bg)', + border: '1px solid var(--colors-border)', + rounded: 'var(--rounded-md)' + }, + item: { + primary: { + bg: 'var(--color-list-primary-bg)', + border: '1px solid var(--colors-border)', + hover: { + bg: 'var(--color-list-primary-hover-bg)' + }, + rounded: 'var(--rounded-md)' + }, + secondary: { + bg: 'var(--color-list-secondary-bg)', + border: 'none', + hover: { + bg: 'var(--color-list-secondary-hover-bg)' + }, + rounded: 'var(--rounded-md)' + }, + card: { + bg: 'var(--colors-table-odd-row-bg)', + border: '1px solid var(--colors-border)', + hover: { + bg: 'var(--color-list-primary-hover-bg)' + }, + rounded: '' } } }, diff --git a/src/component-library/utils/breakpoints.ts b/src/component-library/utils/breakpoints.ts new file mode 100644 index 0000000000..ab6781e397 --- /dev/null +++ b/src/component-library/utils/breakpoints.ts @@ -0,0 +1,17 @@ +import { BreakPoints } from './prop-types'; + +const values: Record = { + xs: 0, // phone + sm: 600, // tablet + md: 900, // small laptop + lg: 1200, // desktop + xl: 1536 // large screen +}; + +const breakpoints = { + values, + up: (key: BreakPoints): string => `(min-width:${values[key]}px)`, + down: (key: BreakPoints): string => `(max-width:${values[key]}px)` +}; + +export { breakpoints }; diff --git a/src/component-library/utils/prop-types.ts b/src/component-library/utils/prop-types.ts index b0265ec68a..74e793a13b 100644 --- a/src/component-library/utils/prop-types.ts +++ b/src/component-library/utils/prop-types.ts @@ -48,6 +48,10 @@ export type Variants = typeof variant[number]; export type CTAVariants = typeof ctaVariant[number]; +export type ListVariants = Variants | 'card'; + +export type DividerVariants = Colors | 'default'; + export type CTASizes = 'x-small' | 'small' | 'medium' | 'large'; export type Status = typeof status[number]; @@ -78,6 +82,18 @@ export interface ElementTypeProp { elementType?: ElementType; } +export interface MarginProps { + margin?: Spacing; + marginTop?: Spacing; + marginBottom?: Spacing; + marginLeft?: Spacing; + marginRight?: Spacing; + marginX?: Spacing; + marginY?: Spacing; +} + +export type ResponsiveProp = T | Partial<{ [K in BreakPoints]: T }>; + export type FontWeight = keyof typeof theme.fontWeight; export type Orientation = 'horizontal' | 'vertical'; @@ -85,3 +101,5 @@ export type Orientation = 'horizontal' | 'vertical'; export type IconSize = keyof typeof theme.icon.sizes; export type Overflow = 'auto' | 'hidden' | 'scroll' | 'visible' | 'inherit'; + +export type BreakPoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; diff --git a/src/component-library/utils/use-media-query.tsx b/src/component-library/utils/use-media-query.tsx new file mode 100644 index 0000000000..d689b1be9c --- /dev/null +++ b/src/component-library/utils/use-media-query.tsx @@ -0,0 +1,44 @@ +import { useEffect, useState } from 'react'; + +const useMediaQuery = (query: string): boolean => { + const getMatches = (query: string): boolean => { + // Prevents SSR issues + if (typeof window !== 'undefined') { + return window.matchMedia(query).matches; + } + return false; + }; + + const [matches, setMatches] = useState(getMatches(query)); + + function handleChange() { + setMatches(getMatches(query)); + } + + useEffect(() => { + const matchMedia = window.matchMedia(query); + + // Triggered at the first client-side load and if query changes + handleChange(); + + // Listen matchMedia + if (matchMedia.addListener) { + matchMedia.addListener(handleChange); + } else { + matchMedia.addEventListener('change', handleChange); + } + + return () => { + if (matchMedia.removeListener) { + matchMedia.removeListener(handleChange); + } else { + matchMedia.removeEventListener('change', handleChange); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query]); + + return matches; +}; + +export { useMediaQuery }; diff --git a/src/component-library/utils/use-style-props.tsx b/src/component-library/utils/use-style-props.tsx new file mode 100644 index 0000000000..40aeb26e1f --- /dev/null +++ b/src/component-library/utils/use-style-props.tsx @@ -0,0 +1,30 @@ +import { StyledMarginProps } from '../css/margin'; +import { MarginProps } from './prop-types'; + +type StyleProps = StyledMarginProps; + +type ComponentProps> = Omit; + +type UseStylePropsResult> = { styleProps: StyleProps; componentProps: ComponentProps }; + +// Extracts props that are solely for styling so that they get mapped to styled props +// This approach is used for a set of styling props that could be reused across different component +const useStyleProps = >(props: T): UseStylePropsResult => { + const { margin, marginTop, marginBottom, marginLeft, marginRight, marginX, marginY, ...componentProps } = props; + + return { + styleProps: { + $margin: margin, + $marginTop: marginTop, + $marginBottom: marginBottom, + $marginLeft: marginLeft, + $marginRight: marginRight, + $marginX: marginX, + $marginY: marginY + }, + componentProps + }; +}; + +export type { StyleProps, UseStylePropsResult }; +export { useStyleProps }; diff --git a/src/components/DataGrid/AssetCell.tsx b/src/components/DataGrid/AssetCell.tsx new file mode 100644 index 0000000000..c708f5898f --- /dev/null +++ b/src/components/DataGrid/AssetCell.tsx @@ -0,0 +1,24 @@ +import { CoinIcon, Flex, FlexProps, FontSize, IconSize, Span } from '@/component-library'; + +type Props = { + ticker: string; + tickers?: string[]; + size?: IconSize; + textSize?: FontSize; +}; + +type InheritAttrs = Omit; + +type AssetCellProps = Props & InheritAttrs; + +const AssetCell = ({ ticker, tickers, size, textSize = 's', ...props }: AssetCellProps): JSX.Element => ( + + + + {ticker} + + +); + +export { AssetCell }; +export type { AssetCellProps }; diff --git a/src/components/DataGrid/BalanceCell.tsx b/src/components/DataGrid/BalanceCell.tsx new file mode 100644 index 0000000000..c7d14845bb --- /dev/null +++ b/src/components/DataGrid/BalanceCell.tsx @@ -0,0 +1,20 @@ +import { CurrencyExt } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; + +import { formatUSD } from '@/common/utils/utils'; +import { AlignItems } from '@/component-library'; + +import { Cell } from './Cell'; + +type BalanceCellProps = { + amount: MonetaryAmount; + amountUSD: number; + alignItems?: AlignItems; +}; + +const BalanceCell = ({ amount, amountUSD, alignItems }: BalanceCellProps): JSX.Element => ( + +); + +export { BalanceCell }; +export type { BalanceCellProps }; diff --git a/src/components/DataGrid/Cell.tsx b/src/components/DataGrid/Cell.tsx new file mode 100644 index 0000000000..e1b8cef6ae --- /dev/null +++ b/src/components/DataGrid/Cell.tsx @@ -0,0 +1,33 @@ +import { forwardRef } from 'react'; + +import { Colors, Flex, FlexProps } from '@/component-library'; + +import { StyledCellLabel, StyledCellSubLabel } from './DataGrid.style'; + +type Props = { + label?: string; + sublabel?: string; + labelColor?: Colors; +}; + +type InheritAttrs = Omit; + +type CellProps = Props & InheritAttrs; + +const Cell = forwardRef( + ({ label, sublabel, labelColor: labelColorProp, alignItems, ...props }, ref): JSX.Element => { + const labelColor = labelColorProp || sublabel ? 'secondary' : undefined; + + return ( + + {label} + {sublabel && {sublabel}} + + ); + } +); + +Cell.displayName = 'Cell'; + +export { Cell }; +export type { CellProps }; diff --git a/src/components/DataGrid/DataGrid.style.tsx b/src/components/DataGrid/DataGrid.style.tsx new file mode 100644 index 0000000000..f66ce9de0b --- /dev/null +++ b/src/components/DataGrid/DataGrid.style.tsx @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +import { Span, theme } from '@/component-library'; + +const StyledCellLabel = styled(Span)` + font-weight: ${theme.fontWeight.bold}; + font-size: ${theme.text.s}; + display: inline-flex; + gap: ${theme.spacing.spacing1}; + align-items: baseline; +`; + +const StyledCellTickerLabel = styled(Span)` + font-size: ${theme.text.xs}; +`; + +const StyledCellSubLabel = styled(Span)` + font-size: ${theme.text.xs}; +`; + +export { StyledCellLabel, StyledCellSubLabel, StyledCellTickerLabel }; diff --git a/src/components/DataGrid/DataGrid.tsx b/src/components/DataGrid/DataGrid.tsx new file mode 100644 index 0000000000..54b9d08da4 --- /dev/null +++ b/src/components/DataGrid/DataGrid.tsx @@ -0,0 +1,35 @@ +import { useId } from '@react-aria/utils'; +import { ReactNode } from 'react'; + +import { BreakPoints, theme } from '@/component-library'; +import { useMediaQuery } from '@/component-library/utils/use-media-query'; + +import { List } from './List'; +import { Table, TableProps } from './Table'; + +type Props = { + title?: ReactNode; + className?: string; + actions?: ReactNode; + placeholder?: ReactNode; + responsive?: boolean; + breakpoint?: BreakPoints; +}; + +type InheritAttrs = Omit, keyof Props>; + +type DataGridProps = Props & InheritAttrs; + +const DataGrid = ({ responsive = true, breakpoint = 'md', ...props }: DataGridProps): JSX.Element => { + const titleId = useId(); + const isMobile = useMediaQuery(theme.breakpoints.down(breakpoint)); + + if (isMobile && responsive) { + return ; + } + + return ; +}; + +export { DataGrid }; +export type { DataGridProps }; diff --git a/src/components/DataGrid/List.tsx b/src/components/DataGrid/List.tsx new file mode 100644 index 0000000000..1985b1214a --- /dev/null +++ b/src/components/DataGrid/List.tsx @@ -0,0 +1,44 @@ +import { ReactNode } from 'react'; + +import { + Card, + List as LibList, + ListItem as LibListItem, + ListProps as LibListProps, + TableProps +} from '@/component-library'; + +import { ListItem } from './ListItem'; +import { TableWrapper } from './TableWrapper'; + +type Props = { + title?: ReactNode; + titleId?: string; + className?: string; + actions?: ReactNode; + placeholder?: ReactNode; +}; + +type TableAttrs = Omit, keyof Props>; + +type InheritAttrs = Omit; + +type ListProps = Props & TableAttrs & InheritAttrs; + +const List = ({ title, titleId, rows, columns, className, actions, placeholder, ...props }: ListProps): JSX.Element => ( + + {rows.length ? ( + + {rows.map((row) => ( + + + + ))} + + ) : ( + {placeholder} + )} + +); +export { List }; +export type { ListProps }; diff --git a/src/components/DataGrid/ListItem.tsx b/src/components/DataGrid/ListItem.tsx new file mode 100644 index 0000000000..14005810a9 --- /dev/null +++ b/src/components/DataGrid/ListItem.tsx @@ -0,0 +1,33 @@ +import { Fragment } from 'react'; + +import { Dd, Dl, DlGroup, DlProps, Dt, RowProps, TableProps } from '@/component-library'; + +type Props = { + row: RowProps; +}; + +type TableAttrs = Omit, keyof Props>; + +type InheritAttrs = Omit; + +type ListItemProps = Props & TableAttrs & InheritAttrs; + +const ListItem = ({ row, columns, ...props }: ListItemProps): JSX.Element => ( +
+ {columns.map((column) => { + const title = column.name; + const children = row[column.uid]; + + return title ? ( + +
{title}
+
{children}
+
+ ) : ( + {children} + ); + })} +
+); +export { ListItem }; +export type { ListItemProps }; diff --git a/src/components/DataGrid/Table.tsx b/src/components/DataGrid/Table.tsx new file mode 100644 index 0000000000..0b7cd8ab9d --- /dev/null +++ b/src/components/DataGrid/Table.tsx @@ -0,0 +1,38 @@ +import { ReactNode } from 'react'; + +import { Card, Table as LiTable, TableProps as LibTableProps } from '@/component-library'; + +import { TableWrapper } from './TableWrapper'; + +type Props = { + title?: ReactNode; + titleId?: string; + className?: string; + actions?: ReactNode; + placeholder?: ReactNode; +}; + +type InheritAttrs = Omit; + +type TableProps = Props & InheritAttrs; + +const Table = ({ + title, + titleId, + rows, + columns, + className, + actions, + placeholder, + ...props +}: TableProps): JSX.Element => ( + + + + {!rows.length && placeholder} + + +); + +export { Table }; +export type { TableProps }; diff --git a/src/components/DataGrid/TableWrapper.tsx b/src/components/DataGrid/TableWrapper.tsx new file mode 100644 index 0000000000..2cb273227b --- /dev/null +++ b/src/components/DataGrid/TableWrapper.tsx @@ -0,0 +1,32 @@ +import { ReactNode } from 'react'; + +import { Flex, FlexProps, H2 } from '@/component-library'; + +type Props = { + title?: ReactNode; + titleId?: string; + actions?: ReactNode; +}; + +type InheritAttrs = Omit; + +type TableWrapperProps = Props & InheritAttrs; + +const TableWrapper = ({ title, titleId, actions, children, ...props }: TableWrapperProps): JSX.Element => { + return ( + + + {title && ( +

+ {title} +

+ )} + {actions} +
+ {children} +
+ ); +}; + +export { TableWrapper }; +export type { TableWrapperProps }; diff --git a/src/components/DataGrid/index.tsx b/src/components/DataGrid/index.tsx new file mode 100644 index 0000000000..39b01973cd --- /dev/null +++ b/src/components/DataGrid/index.tsx @@ -0,0 +1,10 @@ +export type { AssetCellProps } from './AssetCell'; +export { AssetCell } from './AssetCell'; +export type { BalanceCellProps } from './BalanceCell'; +export { BalanceCell } from './BalanceCell'; +export type { CellProps } from './Cell'; +export { Cell } from './Cell'; +export type { DataGridProps } from './DataGrid'; +export { DataGrid } from './DataGrid'; +export type { TableProps } from './Table'; +export { Table } from './Table'; diff --git a/src/pages/Loans/LoansOverview/components/ApyTooltip/AssetGroup.tsx b/src/components/LoanApyTooltip/AssetGroup.tsx similarity index 93% rename from src/pages/Loans/LoansOverview/components/ApyTooltip/AssetGroup.tsx rename to src/components/LoanApyTooltip/AssetGroup.tsx index f637153f05..7c2a88ae38 100644 --- a/src/pages/Loans/LoansOverview/components/ApyTooltip/AssetGroup.tsx +++ b/src/components/LoanApyTooltip/AssetGroup.tsx @@ -6,7 +6,7 @@ import { Dd, Dt } from '@/component-library'; import { getTokenPrice } from '@/utils/helpers/prices'; import { Prices } from '@/utils/hooks/api/use-get-prices'; -import { StyledApyTooltipGroup } from './ApyTooltip.style'; +import { StyledApyTooltipGroup } from './LoanApyTooltip.style'; type AssetGroupProps = { amount: MonetaryAmount; diff --git a/src/pages/Loans/LoansOverview/components/ApyTooltip/BreakdownGroup.tsx b/src/components/LoanApyTooltip/BreakdownGroup.tsx similarity index 94% rename from src/pages/Loans/LoansOverview/components/ApyTooltip/BreakdownGroup.tsx rename to src/components/LoanApyTooltip/BreakdownGroup.tsx index eeba3c432d..2a11c2cb78 100644 --- a/src/pages/Loans/LoansOverview/components/ApyTooltip/BreakdownGroup.tsx +++ b/src/components/LoanApyTooltip/BreakdownGroup.tsx @@ -1,9 +1,9 @@ import Big from 'big.js'; import { Dd, Dl, DlGroup, Dt } from '@/component-library'; +import { getApyLabel } from '@/utils/helpers/loans'; -import { getApyLabel } from '../../utils/apy'; -import { StyledApyTooltipGroup, StyledApyTooltipTitle } from './ApyTooltip.style'; +import { StyledApyTooltipGroup, StyledApyTooltipTitle } from './LoanApyTooltip.style'; type BreakdownGroupProps = { apy: Big; diff --git a/src/pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.style.tsx b/src/components/LoanApyTooltip/LoanApyTooltip.style.tsx similarity index 100% rename from src/pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.style.tsx rename to src/components/LoanApyTooltip/LoanApyTooltip.style.tsx diff --git a/src/pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.tsx b/src/components/LoanApyTooltip/LoanApyTooltip.tsx similarity index 89% rename from src/pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.tsx rename to src/components/LoanApyTooltip/LoanApyTooltip.tsx index 5f811e27d1..37a2dbc5d2 100644 --- a/src/pages/Loans/LoansOverview/components/ApyTooltip/ApyTooltip.tsx +++ b/src/components/LoanApyTooltip/LoanApyTooltip.tsx @@ -6,9 +6,9 @@ import Big from 'big.js'; import { Dd, Dl, DlGroup } from '@/component-library'; import { Prices } from '@/utils/hooks/api/use-get-prices'; -import { StyledApyTooltipTitle, StyledTooltip } from './ApyTooltip.style'; import { AssetGroup } from './AssetGroup'; import { BreakdownGroup } from './BreakdownGroup'; +import { StyledApyTooltipTitle, StyledTooltip } from './LoanApyTooltip.style'; import { RewardsGroup } from './RewardsGroup'; type Props = { @@ -24,9 +24,9 @@ type Props = { type InheritAttrs = Omit; -type ApyTooltipProps = Props & InheritAttrs; +type LoanApyTooltipProps = Props & InheritAttrs; -const ApyTooltip = ({ +const LoanApyTooltip = ({ apy, currency, earnedInterest, @@ -36,7 +36,7 @@ const ApyTooltip = ({ prices, isBorrow, ...props -}: ApyTooltipProps): JSX.Element => { +}: LoanApyTooltipProps): JSX.Element => { const showEarnedRewards = !!rewards || !!earnedInterest; const label = ( @@ -75,5 +75,5 @@ const ApyTooltip = ({ return ; }; -export { ApyTooltip }; -export type { ApyTooltipProps }; +export { LoanApyTooltip }; +export type { LoanApyTooltipProps }; diff --git a/src/pages/Loans/LoansOverview/components/ApyTooltip/RewardsGroup.tsx b/src/components/LoanApyTooltip/RewardsGroup.tsx similarity index 94% rename from src/pages/Loans/LoansOverview/components/ApyTooltip/RewardsGroup.tsx rename to src/components/LoanApyTooltip/RewardsGroup.tsx index ef29a9ec59..dfeb949ccc 100644 --- a/src/pages/Loans/LoansOverview/components/ApyTooltip/RewardsGroup.tsx +++ b/src/components/LoanApyTooltip/RewardsGroup.tsx @@ -6,7 +6,7 @@ import { Dd, Dt } from '@/component-library'; import { getTokenPrice } from '@/utils/helpers/prices'; import { Prices } from '@/utils/hooks/api/use-get-prices'; -import { StyledApyTooltipGroup } from './ApyTooltip.style'; +import { StyledApyTooltipGroup } from './LoanApyTooltip.style'; type RewardsGroupProps = { rewards: MonetaryAmount; diff --git a/src/components/LoanApyTooltip/index.tsx b/src/components/LoanApyTooltip/index.tsx new file mode 100644 index 0000000000..062155f827 --- /dev/null +++ b/src/components/LoanApyTooltip/index.tsx @@ -0,0 +1,2 @@ +export type { LoanApyTooltipProps } from './LoanApyTooltip'; +export { LoanApyTooltip } from './LoanApyTooltip'; diff --git a/src/pages/Loans/LoansOverview/components/LoansBaseTable/ApyCell.tsx b/src/components/LoanPositionsTable/ApyCell.tsx similarity index 79% rename from src/pages/Loans/LoansOverview/components/LoansBaseTable/ApyCell.tsx rename to src/components/LoanPositionsTable/ApyCell.tsx index 7a4796dcec..7a0a7d0b4a 100644 --- a/src/pages/Loans/LoansOverview/components/LoansBaseTable/ApyCell.tsx +++ b/src/components/LoanPositionsTable/ApyCell.tsx @@ -3,12 +3,11 @@ import { MonetaryAmount } from '@interlay/monetary-js'; import Big from 'big.js'; import { Flex } from '@/component-library'; +import { getApyLabel, getSubsidyRewardApy } from '@/utils/helpers/loans'; import { Prices } from '@/utils/hooks/api/use-get-prices'; -import { getApyLabel } from '../../utils/apy'; -import { getSubsidyRewardApy } from '../../utils/get-subsidy-rewards-apy'; -import { ApyTooltip } from '../ApyTooltip'; -import { MonetaryCell } from './MonetaryCell'; +import { Cell } from '../DataGrid'; +import { LoanApyTooltip } from '../LoanApyTooltip'; type ApyCellProps = { apy: Big; @@ -40,9 +39,7 @@ const ApyCell = ({ const earnedAssetLabel = earnedAsset ? `${earnedAsset.toHuman(8)} ${earnedAsset.currency.ticker}` : undefined; - const children = ( - - ); + const children = ; if (!prices) { return children; @@ -51,7 +48,7 @@ const ApyCell = ({ // MEMO: wrapping around a Flex so tooltip is placed correctly return ( - {children} - + ); }; diff --git a/src/components/LoanPositionsTable/LoanPositionsTable.tsx b/src/components/LoanPositionsTable/LoanPositionsTable.tsx new file mode 100644 index 0000000000..5dd60b7919 --- /dev/null +++ b/src/components/LoanPositionsTable/LoanPositionsTable.tsx @@ -0,0 +1,153 @@ +import { BorrowPosition, CollateralPosition, LoanAsset, TickerToData } from '@interlay/interbtc-api'; +import { useId } from '@react-aria/utils'; +import { Key, ReactNode, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { convertMonetaryAmountToValueInUSD } from '@/common/utils/utils'; +import { Switch } from '@/component-library'; +import { LoanType } from '@/types/loans'; +import { getTokenPrice } from '@/utils/helpers/prices'; +import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; + +import { AssetCell, BalanceCell, Table, TableProps } from '../DataGrid'; +import { ApyCell } from './ApyCell'; +import { LoanTablePlaceholder } from './LoanTablePlaceholder'; + +enum LoanPositionTableColumns { + ASSET = 'asset', + APY = 'apy', + AMOUNT = 'amount', + COLLATERAL = 'collateral' +} + +type LoanPositionTableRow = { + id: string; + [LoanPositionTableColumns.ASSET]: ReactNode; + [LoanPositionTableColumns.APY]: ReactNode; + [LoanPositionTableColumns.AMOUNT]: ReactNode; + [LoanPositionTableColumns.COLLATERAL]?: ReactNode; +}; + +type Props = { + variant?: LoanType; + title?: ReactNode; + assets: TickerToData; + positions: BorrowPosition[] | CollateralPosition[]; + onPressCollateralSwitch?: (ticker: string) => void; +}; + +type InheritAttrs = Omit; + +type LoanPositionsTableProps = Props & InheritAttrs; + +const LoanPositionsTable = ({ + variant = 'lend', + title, + assets, + positions, + onRowAction, + onPressCollateralSwitch, + ...props +}: LoanPositionsTableProps): JSX.Element | null => { + const titleId = useId(); + const { t } = useTranslation(); + const prices = useGetPrices(); + + const isLending = variant === 'lend'; + const showCollateral = !!onPressCollateralSwitch && isLending; + + const columns = useMemo(() => { + if (isLending) { + const lendingColumns = [ + { name: 'Asset', uid: LoanPositionTableColumns.ASSET }, + { name: 'APY / Earned', uid: LoanPositionTableColumns.APY }, + { name: 'Supplied', uid: LoanPositionTableColumns.AMOUNT } + ]; + + if (showCollateral) { + lendingColumns.push({ name: 'Collateral', uid: LoanPositionTableColumns.COLLATERAL }); + } + + return lendingColumns; + } + + return [ + { name: 'Asset', uid: LoanPositionTableColumns.ASSET }, + { name: 'APY / Accrued', uid: LoanPositionTableColumns.APY }, + { name: 'Borrowed', uid: LoanPositionTableColumns.AMOUNT } + ]; + }, [isLending, showCollateral]); + + const rows: LoanPositionTableRow[] = useMemo( + () => + positions.map(({ amount: amountProp, ...position }) => { + const { currency } = amountProp; + const asset = ; + + const { borrowApy, borrowReward, lendApy, lendReward } = assets[currency.ticker]; + + const apyCellProps = isLending + ? { apy: lendApy, rewards: lendReward } + : { + apy: borrowApy, + rewards: borrowReward, + accumulatedDebt: (position as BorrowPosition).accumulatedDebt, + isBorrow: true + }; + + const apy = ( + onRowAction?.(currency.ticker as Key)} + /> + ); + + const amountUSD = amountProp + ? convertMonetaryAmountToValueInUSD(amountProp, getTokenPrice(prices, currency.ticker)?.usd) + : 0; + + const amount = ( + + ); + + const collateral = showCollateral ? ( + onPressCollateralSwitch?.(currency.ticker)} + isSelected={(position as CollateralPosition).isCollateral} + aria-label={`toggle ${currency.ticker} collateral`} + /> + ) : undefined; + + return { + id: currency.ticker, + asset, + apy, + amount, + collateral + }; + }), + [assets, isLending, onPressCollateralSwitch, onRowAction, positions, prices, showCollateral] + ); + + return ( +
} + {...props} + /> + ); +}; + +export { LoanPositionsTable }; +export type { LoanPositionsTableProps }; diff --git a/src/components/LoanPositionsTable/LoanTablePlaceholder.tsx b/src/components/LoanPositionsTable/LoanTablePlaceholder.tsx new file mode 100644 index 0000000000..902a831b79 --- /dev/null +++ b/src/components/LoanPositionsTable/LoanTablePlaceholder.tsx @@ -0,0 +1,22 @@ +import { useTranslation } from 'react-i18next'; + +import { Flex, P, Strong } from '@/component-library'; +import { LoanType } from '@/types/loans'; + +type LoanTablePlaceholderProps = { + variant?: LoanType; +}; + +const LoanTablePlaceholder = ({ variant = 'lend' }: LoanTablePlaceholderProps): JSX.Element | null => { + const { t } = useTranslation(); + + return ( + + {t('loans.no_loan_positions', { loanType: variant })} +

{t('loans.your_loan_positions_will_show_here', { loanType: variant })}

+
+ ); +}; + +export { LoanTablePlaceholder }; +export type { LoanTablePlaceholderProps }; diff --git a/src/components/LoanPositionsTable/index.tsx b/src/components/LoanPositionsTable/index.tsx new file mode 100644 index 0000000000..32994089c7 --- /dev/null +++ b/src/components/LoanPositionsTable/index.tsx @@ -0,0 +1,4 @@ +export type { LoanPositionsTableProps } from './LoanPositionsTable'; +export { LoanPositionsTable } from './LoanPositionsTable'; +export type { LoanTablePlaceholderProps } from './LoanTablePlaceholder'; +export { LoanTablePlaceholder } from './LoanTablePlaceholder'; diff --git a/src/pages/AMM/Pools/components/PoolsTables/PoolsTable.tsx b/src/components/PoolsTable/PoolsTable.tsx similarity index 65% rename from src/pages/AMM/Pools/components/PoolsTables/PoolsTable.tsx rename to src/components/PoolsTable/PoolsTable.tsx index d7986e77ad..3285d3ca5c 100644 --- a/src/pages/AMM/Pools/components/PoolsTables/PoolsTable.tsx +++ b/src/components/PoolsTable/PoolsTable.tsx @@ -1,18 +1,18 @@ import { LiquidityPool, LpCurrency } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; +import { useId } from '@react-aria/utils'; import { ReactNode, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { formatPercentage, formatUSD } from '@/common/utils/utils'; import { calculateAccountLiquidityUSD, calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; +import { getCoinIconProps } from '@/utils/helpers/coin-icon'; +import { getFarmingApr } from '@/utils/helpers/pools'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; -import { PoolName } from '../PoolName'; -import { BalanceCell, PoolsBaseTable, PoolsBaseTableProps } from '../PoolsBaseTable'; -import { MonetaryCell } from '../PoolsBaseTable/MonetaryCell'; -import { getFarmingApr } from './utils'; +import { AssetCell, BalanceCell, Cell, Table, TableProps } from '../DataGrid'; -enum BorrowAssetsColumns { +enum PoolsTableColumns { POOL_NAME = 'poolName', APR = 'apr', TOTAL_LIQUIDITY = 'totalLiquidity', @@ -22,57 +22,54 @@ enum BorrowAssetsColumns { type PoolsTableRow = { id: string; - [BorrowAssetsColumns.POOL_NAME]: ReactNode; - [BorrowAssetsColumns.APR]: ReactNode; - [BorrowAssetsColumns.TOTAL_LIQUIDITY]: ReactNode; - // [BorrowAssetsColumns.SEVEN_DAY_VOLUME]: ReactNode; - [BorrowAssetsColumns.ACCOUNT_LIQUIDITY]?: ReactNode; + [PoolsTableColumns.POOL_NAME]: ReactNode; + [PoolsTableColumns.APR]: ReactNode; + [PoolsTableColumns.TOTAL_LIQUIDITY]: ReactNode; + // [PoolsTableColumns.SEVEN_DAY_VOLUME]: ReactNode; + [PoolsTableColumns.ACCOUNT_LIQUIDITY]?: ReactNode; }; type PoolsTableProps = { variant: 'available-pools' | 'account-pools'; pools: Array<{ data: LiquidityPool; amount?: MonetaryAmount }>; - onRowAction: PoolsBaseTableProps['onRowAction']; + onRowAction?: TableProps['onRowAction']; + title?: ReactNode; }; -const PoolsTable = ({ variant, pools, onRowAction }: PoolsTableProps): JSX.Element => { +const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JSX.Element => { const { t } = useTranslation(); const prices = useGetPrices(); + const titleId = useId(); const isAccountPools = variant === 'account-pools'; const commonColumns = [ - { name: t('amm.pools.pool_name'), uid: BorrowAssetsColumns.POOL_NAME }, - { name: t('apr'), uid: BorrowAssetsColumns.APR }, - { name: t('total_liquidity'), uid: BorrowAssetsColumns.TOTAL_LIQUIDITY } - // { name: t('7_day_volume'), uid: BorrowAssetsColumns.SEVEN_DAY_VOLUME } + { name: t('amm.pools.pool_name'), uid: PoolsTableColumns.POOL_NAME }, + { name: t('apr'), uid: PoolsTableColumns.APR }, + { name: t('total_liquidity'), uid: PoolsTableColumns.TOTAL_LIQUIDITY } + // { name: t('7_day_volume'), uid: PoolsTableColumns.SEVEN_DAY_VOLUME } ]; const borrowAssetsColumns = isAccountPools - ? [...commonColumns, { name: t('my_liquidity'), uid: BorrowAssetsColumns.ACCOUNT_LIQUIDITY }] + ? [...commonColumns, { name: t('my_liquidity'), uid: PoolsTableColumns.ACCOUNT_LIQUIDITY }] : commonColumns; const rows: PoolsTableRow[] = useMemo( () => pools.map(({ data, amount: accountLPTokenAmount }) => { const { pooledCurrencies, lpToken, rewardAmountsYearly, totalSupply } = data; - const poolName = ( - pooledCurrencies.currency.ticker)} - /> - ); + const poolName = ; const totalLiquidityUSD = calculateTotalLiquidityUSD(pooledCurrencies, prices); const farmingApr = getFarmingApr(rewardAmountsYearly, totalSupply, totalLiquidityUSD, prices); // TODO: add also APR from trading volume based on squid data const aprAmount = farmingApr; - const apr = ; + const apr = ; // TODO: revert alignItems prop when `sevenDayVolume` is adressed const totalLiquidity = ( - @@ -103,8 +100,9 @@ const PoolsTable = ({ variant, pools, onRowAction }: PoolsTableProps): JSX.Eleme ); return ( - void; + fullWidth?: boolean; } -const TokenSelector = ({ variant, tokenOptions, currentToken, onChange, showBalances }: Props): JSX.Element => { +const TokenSelector = ({ + variant, + tokenOptions, + currentToken, + onChange, + showBalances, + fullWidth +}: Props): JSX.Element => { return ( <> {currentToken && (
- - ) : ( - - - {emptyTitle} -

{emptyDescription}

-
-
- )} - - ); -}; - -export { LoansBaseTable }; -export type { LoansBaseTableProps }; diff --git a/src/pages/Loans/LoansOverview/components/LoansBaseTable/MonetaryCell.tsx b/src/pages/Loans/LoansOverview/components/LoansBaseTable/MonetaryCell.tsx deleted file mode 100644 index b9b3f97d26..0000000000 --- a/src/pages/Loans/LoansOverview/components/LoansBaseTable/MonetaryCell.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { forwardRef } from 'react'; - -import { AlignItems, Colors, Flex, FlexProps } from '@/component-library'; - -import { StyledCellLabel, StyledCellSubLabel } from './LoansBaseTable.style'; - -type Props = { - label?: string; - sublabel?: string; - labelColor?: Colors; - alignItems?: AlignItems; -}; - -type InheritAttrs = Omit; - -type MonetaryCellProps = Props & InheritAttrs; - -const MonetaryCell = forwardRef( - ({ label, sublabel, labelColor, alignItems, ...props }, ref): JSX.Element => ( - - {label} - {sublabel && {sublabel}} - - ) -); - -MonetaryCell.displayName = 'MonetaryCell'; - -export { MonetaryCell }; -export type { MonetaryCellProps }; diff --git a/src/pages/Loans/LoansOverview/components/LoansBaseTable/index.tsx b/src/pages/Loans/LoansOverview/components/LoansBaseTable/index.tsx deleted file mode 100644 index d331777994..0000000000 --- a/src/pages/Loans/LoansOverview/components/LoansBaseTable/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -export type { ApyCellProps } from './ApyCell'; -export { ApyCell } from './ApyCell'; -export type { AssetCellProps } from './AssetCell'; -export { AssetCell } from './AssetCell'; -export type { BalanceCellProps } from './BalanceCell'; -export { BalanceCell } from './BalanceCell'; -export type { LoansBaseTableProps } from './LoansBaseTable'; -export { LoansBaseTable } from './LoansBaseTable'; diff --git a/src/pages/Loans/LoansOverview/components/LoansTables/BorrowTables.tsx b/src/pages/Loans/LoansOverview/components/LoansTables/BorrowTables.tsx index 397514b3c3..19e5dd4b65 100644 --- a/src/pages/Loans/LoansOverview/components/LoansTables/BorrowTables.tsx +++ b/src/pages/Loans/LoansOverview/components/LoansTables/BorrowTables.tsx @@ -2,9 +2,8 @@ import { BorrowPosition, LoanAsset, TickerToData } from '@interlay/interbtc-api' import { Key, useState } from 'react'; import { getPosition } from '../../utils/get-position'; -import { BorrowAssetsTable } from '../BorrowAssetsTable'; -import { BorrowPositionsTable } from '../BorrowPositionsTable'; import { LoanModal } from '../LoanModal'; +import { StyledBorrowAssetsTable, StyledBorrowPositionsTable } from './LoansTables.style'; type UseAssetState = { data?: LoanAsset; @@ -35,14 +34,15 @@ const BorrowTables = ({ assets, positions, disabledAssets, hasPositions }: Borro return ( <> {hasPositions && ( - )} - + {hasPositions && ( - )} - + ` } `; -export { StyledTablesWrapper }; +export { + StyledBorrowAssetsTable, + StyledBorrowPositionsTable, + StyledLendAssetsTable, + StyledLendPositionsTable, + StyledTablesWrapper +}; diff --git a/src/pages/Staking/LockTimeField/index.tsx b/src/pages/Staking/LockTimeField/index.tsx index 983e3df038..1e55b5f43c 100644 --- a/src/pages/Staking/LockTimeField/index.tsx +++ b/src/pages/Staking/LockTimeField/index.tsx @@ -50,7 +50,7 @@ const LockTimeField = React.forwardRef( className={clsx('!text-xs', LABEL_TEXT_COLOR_CLASSES)} required={optional === false} > - Max {STAKE_LOCK_TIME.MAX} Weeks + Total {STAKE_LOCK_TIME.MAX} Weeks
{optional === true && ( @@ -65,7 +65,7 @@ const LockTimeField = React.forwardRef( {t('vault.deposit_collateral')} - +
diff --git a/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.stories.tsx b/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.stories.tsx deleted file mode 100644 index b33a6f17cc..0000000000 --- a/src/pages/Vaults/VaultsOverview/components/InfoBox/InfoBox.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Meta, Story } from '@storybook/react'; - -import { InfoBox, InfoBoxProps } from '.'; - -const Template: Story = (args) => ; - -const WithoutCTA = Template.bind({}); -WithoutCTA.args = { - title: 'My vaults at risk', - text: '0' -}; - -const WithCTA = Template.bind({}); -WithCTA.args = { - title: 'My vaults at risk', - text: '0', - ctaOnClick: () => { - alert('CTA action'); - }, - ctaText: 'Claim' -}; - -export { WithCTA, WithoutCTA }; - -export default { - title: 'Components/InfoBox', - component: InfoBox -} as Meta; diff --git a/src/pages/Wallet/WalletOverview/WalletOverview.tsx b/src/pages/Wallet/WalletOverview/WalletOverview.tsx new file mode 100644 index 0000000000..5506cf3f7e --- /dev/null +++ b/src/pages/Wallet/WalletOverview/WalletOverview.tsx @@ -0,0 +1,57 @@ +import { LoanPositionsTable, PoolsTable } from '@/components'; +import FullLoadingSpinner from '@/legacy-components/FullLoadingSpinner'; +import MainContainer from '@/parts/MainContainer'; +import { getPooledTickers } from '@/utils/helpers/pools'; +import { useGetAccountPools } from '@/utils/hooks/api/amm/use-get-account-pools'; +import { useGetLiquidityPools } from '@/utils/hooks/api/amm/use-get-liquidity-pools'; +import { useGetAccountStakingData } from '@/utils/hooks/api/escrow/use-get-account-staking-data'; +import { useGetAccountVotingBalance } from '@/utils/hooks/api/escrow/use-get-account-voting-balance'; +import { useGetAccountPositions } from '@/utils/hooks/api/loans/use-get-account-positions'; +import { useGetLoanAssets } from '@/utils/hooks/api/loans/use-get-loan-assets'; +import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; +import useAccountId from '@/utils/hooks/use-account-id'; + +import { AvailableAssetsTable, StakingTable, WalletInsights } from './components'; + +const WalletOverview = (): JSX.Element => { + const accountId = useAccountId(); + const { data: balances } = useGetBalances(); + const { data: accountPoolsData } = useGetAccountPools(); + const { data: liquidityPools } = useGetLiquidityPools(); + const { data: accountStakingData } = useGetAccountStakingData(); + const { data: accountVotingBalance } = useGetAccountVotingBalance(); + const { + data: { borrowPositions, lendPositions } + } = useGetAccountPositions(); + const { data: assets } = useGetLoanAssets(); + + if (accountId !== undefined && !balances) { + return ; + } + + const hasStakingTable = + accountStakingData && + accountVotingBalance && + (!accountStakingData?.balance.isZero() || !accountVotingBalance?.isZero()); + + const pooledTickers = liquidityPools && getPooledTickers(liquidityPools); + + return ( + + + + {!!lendPositions?.length && assets && ( + + )} + {!!borrowPositions?.length && assets && ( + + )} + {!!accountPoolsData?.positions.length && ( + + )} + {hasStakingTable && } + + ); +}; + +export default WalletOverview; diff --git a/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/ActionsCell.tsx b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/ActionsCell.tsx new file mode 100644 index 0000000000..ca103cb82d --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/ActionsCell.tsx @@ -0,0 +1,131 @@ +import { CurrencyExt } from '@interlay/interbtc-api'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from 'react-query'; +import { useDispatch } from 'react-redux'; +import { toast } from 'react-toastify'; + +import { showBuyModal } from '@/common/actions/general.actions'; +import { CTA, CTALink, CTAProps, Divider, Flex, theme } from '@/component-library'; +import { useMediaQuery } from '@/component-library/utils/use-media-query'; +import { WRAPPED_TOKEN } from '@/config/relay-chains'; +import { PAGES, QUERY_PARAMETERS } from '@/utils/constants/links'; + +const queryString = require('query-string'); + +const claimVesting = async () => { + await window.bridge.api.tx.vesting.claim(); +}; + +type ActionsCellProps = { + currency: CurrencyExt; + isWrappedToken: boolean; + isRedeemable: boolean; + isPooledAsset: boolean; + isGovernanceToken: boolean; + isVestingClaimable: boolean; +}; + +const ActionsCell = ({ + currency, + isGovernanceToken, + isPooledAsset, + isRedeemable, + isVestingClaimable, + isWrappedToken +}: ActionsCellProps): JSX.Element | null => { + const { t } = useTranslation(); + const dispatch = useDispatch(); + + const isMobile = useMediaQuery(theme.breakpoints.down('md')); + const isSmallMobile = useMediaQuery(theme.breakpoints.down('sm')); + + const handleClaimVestingSuccess = () => { + toast.success('Successfully claimed vesting'); + }; + + const handleClaimVestingError = (error: Error) => { + toast.success(error); + }; + + const claimVestingMutation = useMutation(claimVesting, { + onSuccess: handleClaimVestingSuccess, + onError: handleClaimVestingError + }); + + const handlePressClaimVesting = () => claimVestingMutation.mutate(); + + const handlePressBuyGovernance = () => dispatch(showBuyModal(true)); + + const commonCTAProps: CTAProps = { + fullWidth: isMobile, + variant: 'outlined', + size: isMobile && !isSmallMobile ? 'medium' : 'small' + }; + + return ( + + {isMobile && } + + {isWrappedToken && ( + + {t('issue')} + + )} + {isRedeemable && ( + + {t('redeem')} + + )} + {/* TODO: add when xcm re-vamp is added */} + {/* + {t('transfer')} + */} + {isPooledAsset && ( + + {t('amm.swap')} + + )} + {isGovernanceToken && ( + <> + + Buy + + {isVestingClaimable && ( + + Claim vesting + + )} + + )} + + + ); +}; + +export { ActionsCell }; +export type { ActionsCellProps }; diff --git a/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/AvailableAssetsTable.tsx b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/AvailableAssetsTable.tsx new file mode 100644 index 0000000000..923a7eeec2 --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/AvailableAssetsTable.tsx @@ -0,0 +1,130 @@ +import { isCurrencyEqual } from '@interlay/interbtc-api'; +import { ReactNode, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { convertMonetaryAmountToValueInUSD, formatUSD } from '@/common/utils/utils'; +import { P, Switch, theme } from '@/component-library'; +import { useMediaQuery } from '@/component-library/utils/use-media-query'; +import { Cell } from '@/components'; +import { AssetCell, DataGrid } from '@/components/DataGrid'; +import { GOVERNANCE_TOKEN, WRAPPED_TOKEN } from '@/config/relay-chains'; +import { getCoinIconProps } from '@/utils/helpers/coin-icon'; +import { getTokenPrice } from '@/utils/helpers/prices'; +import { BalanceData } from '@/utils/hooks/api/tokens/use-get-balances'; +import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; +import { useGetVestingData } from '@/utils/hooks/api/use-get-vesting-data'; + +import { ActionsCell } from './ActionsCell'; + +enum AvailableAssetsColumns { + ASSET = 'asset', + PRICE = 'price', + BALANCE = 'balance', + ACTIONS = 'actions' +} + +type AvailableAssetsRows = { + id: string; + [AvailableAssetsColumns.ASSET]: ReactNode; + [AvailableAssetsColumns.PRICE]: ReactNode; + [AvailableAssetsColumns.BALANCE]: ReactNode; + [AvailableAssetsColumns.ACTIONS]: ReactNode; +}; + +type AvailableAssetsTableProps = { + balances?: BalanceData; + pooledTickers?: Set; +}; + +const AvailableAssetsTable = ({ balances, pooledTickers }: AvailableAssetsTableProps): JSX.Element => { + const { t } = useTranslation(); + const prices = useGetPrices(); + const { data: vestingData } = useGetVestingData(); + const isMobile = useMediaQuery(theme.breakpoints.down('md')); + + const [showZeroBalances, setShowZeroBalances] = useState(false); + + const rows: AvailableAssetsRows[] = useMemo(() => { + const data = balances ? Object.values(balances) : []; + const filteredData = showZeroBalances ? data : data.filter((balance) => !balance.transferable.isZero()); + + return filteredData.map( + ({ currency, transferable }): AvailableAssetsRows => { + const asset = ( + + ); + + const tokenPrice = getTokenPrice(prices, currency.ticker)?.usd || 0; + + const assetPriceLabel = formatUSD(getTokenPrice(prices, currency.ticker)?.usd || 0, { compact: true }); + const price = ; + + const balanceLabel = transferable.toString(); + const balanceSublabel = formatUSD(convertMonetaryAmountToValueInUSD(transferable, tokenPrice) || 0, { + compact: true + }); + const balance = ( + + ); + + const isWrappedToken = isCurrencyEqual(currency, WRAPPED_TOKEN); + const isRedeemable = isWrappedToken && !transferable.isZero(); + const isPooledAsset = !!pooledTickers?.has(currency.ticker); + const isGovernanceToken = isCurrencyEqual(currency, GOVERNANCE_TOKEN); + const isVestingClaimable = isGovernanceToken && !!vestingData?.isClaimable; + + const hasActions = isRedeemable || isPooledAsset || isVestingClaimable; + + const actions = hasActions ? ( + + ) : null; + + return { + id: currency.ticker, + asset, + price, + balance, + actions + }; + } + ); + }, [balances, showZeroBalances, isMobile, prices, pooledTickers, vestingData?.isClaimable]); + + const actions = ( + setShowZeroBalances(e.target.checked)}> + {t('show_zero_balance')} + + ); + + const columns = [ + { name: isMobile ? '' : t('asset'), uid: AvailableAssetsColumns.ASSET }, + { name: t('price'), uid: AvailableAssetsColumns.PRICE }, + { name: t('balance'), uid: AvailableAssetsColumns.BALANCE }, + { name: '', uid: AvailableAssetsColumns.ACTIONS } + ]; + + return ( + {t('wallet.no_assets_available')}

} + /> + ); +}; + +export { AvailableAssetsTable }; +export type { AvailableAssetsTableProps }; diff --git a/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/index.tsx b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/index.tsx new file mode 100644 index 0000000000..1b84d782aa --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/AvailableAssetsTable/index.tsx @@ -0,0 +1,2 @@ +export type { AvailableAssetsTableProps } from './AvailableAssetsTable'; +export { AvailableAssetsTable } from './AvailableAssetsTable'; diff --git a/src/pages/Wallet/WalletOverview/components/StakingTable/StakingTable.tsx b/src/pages/Wallet/WalletOverview/components/StakingTable/StakingTable.tsx new file mode 100644 index 0000000000..d5fc3e645c --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/StakingTable/StakingTable.tsx @@ -0,0 +1,94 @@ +import { CurrencyExt } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; +import { useId } from '@react-aria/utils'; +import { differenceInDays, format, formatDistanceToNowStrict } from 'date-fns'; +import { ReactNode, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { convertMonetaryAmountToValueInUSD, formatUSD } from '@/common/utils/utils'; +import { CoinIcon, Flex } from '@/component-library'; +import { Cell, Table } from '@/components'; +import { GOVERNANCE_TOKEN, VOTE_GOVERNANCE_TOKEN } from '@/config/relay-chains'; +import { YEAR_MONTH_DAY_PATTERN } from '@/utils/constants/date-time'; +import { getTokenPrice } from '@/utils/helpers/prices'; +import { GetAccountStakingData } from '@/utils/hooks/api/escrow/use-get-account-staking-data'; +import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; +import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; + +enum StakingTableColumns { + ASSET = 'asset', + UNLOCKS = 'unlocks', + AVAILABLE = 'available', + VOTING_POWER = 'votingPower' +} + +type StakingTableRows = { + id: string; + [StakingTableColumns.ASSET]: ReactNode; + [StakingTableColumns.UNLOCKS]: ReactNode; + [StakingTableColumns.AVAILABLE]: ReactNode; + [StakingTableColumns.VOTING_POWER]: ReactNode; +}; + +type StakingTableProps = { + data: GetAccountStakingData; + votingBalance: MonetaryAmount; +}; + +const StakingTable = ({ data, votingBalance }: StakingTableProps): JSX.Element => { + const { t } = useTranslation(); + const titleId = useId(); + const prices = useGetPrices(); + const { getAvailableBalance } = useGetBalances(); + + const columns = [ + { name: t('wallet.total_governance_locked', { token: GOVERNANCE_TOKEN.ticker }), uid: StakingTableColumns.ASSET }, + { name: t('unlocks'), uid: StakingTableColumns.UNLOCKS }, + { name: t('wallet.available_to_stake'), uid: StakingTableColumns.AVAILABLE }, + { + name: t('wallet.voting_power_governance', { token: VOTE_GOVERNANCE_TOKEN.ticker }), + uid: StakingTableColumns.VOTING_POWER + } + ]; + + const rows = useMemo((): StakingTableRows[] => { + const { balance, unlock } = data; + const stakingBalancePrice = + convertMonetaryAmountToValueInUSD(balance, getTokenPrice(prices, balance.currency.ticker)?.usd) || 0; + + const asset = ( + + + + + ); + + const unlockDateLabel = format(unlock.date, YEAR_MONTH_DAY_PATTERN); + const difference = differenceInDays(unlock.date, new Date()); + const unlockDaysLabel = formatDistanceToNowStrict(unlock.date); + const unlockDaysIndicatorLabel = difference < 0 ? `-${unlockDaysLabel}` : unlockDaysLabel; + const unlocksLabel = `${unlockDateLabel} (${unlockDaysIndicatorLabel})`; + + const unlocks = ; + + const available = ; + + const votingPower = ; + + return [ + { + id: balance.currency.ticker, + asset, + unlocks, + available, + votingPower + } + ]; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [prices, data, votingBalance]); + + return
; +}; + +export { StakingTable }; +export type { StakingTableProps }; diff --git a/src/pages/Wallet/WalletOverview/components/StakingTable/index.tsx b/src/pages/Wallet/WalletOverview/components/StakingTable/index.tsx new file mode 100644 index 0000000000..67b407a1ac --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/StakingTable/index.tsx @@ -0,0 +1,2 @@ +export type { StakingTableProps } from './StakingTable'; +export { StakingTable } from './StakingTable'; diff --git a/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.style.tsx b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.style.tsx new file mode 100644 index 0000000000..700a6824d8 --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.style.tsx @@ -0,0 +1,14 @@ +import styled from 'styled-components'; + +import { Dd, Dt, theme } from '@/component-library'; + +const StyledDt = styled(Dt)` + font-weight: ${theme.fontWeight.semibold}; + white-space: nowrap; +`; + +const StyledDd = styled(Dd)` + font-weight: ${theme.fontWeight.bold}; +`; + +export { StyledDd, StyledDt }; diff --git a/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.tsx b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.tsx new file mode 100644 index 0000000000..234b4368db --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletInsights.tsx @@ -0,0 +1,85 @@ +import Big from 'big.js'; +import { useTranslation } from 'react-i18next'; + +import { convertMonetaryAmountToValueInUSD, formatUSD } from '@/common/utils/utils'; +import { Card, Dd, Dl, DlGroup, Dt, theme } from '@/component-library'; +import { useMediaQuery } from '@/component-library/utils/use-media-query'; +import { getTokenPrice } from '@/utils/helpers/prices'; +import { BalanceData } from '@/utils/hooks/api/tokens/use-get-balances'; +import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; + +import { WalletMeta } from './WalletMeta'; + +type WalletInsightsProps = { + balances?: BalanceData; +}; + +const WalletInsights = ({ balances }: WalletInsightsProps): JSX.Element => { + const { t } = useTranslation(); + + const prices = useGetPrices(); + const isMobile = useMediaQuery(theme.breakpoints.down('md')); + + const totalBalance = + balances && + Object.values(balances).reduce( + (total, balance) => + total.add( + convertMonetaryAmountToValueInUSD( + balance.free.add(balance.reserved), + getTokenPrice(prices, balance.currency.ticker)?.usd + ) || 0 + ), + new Big(0) + ); + + const totalBalanceLabel = totalBalance ? formatUSD(totalBalance.toNumber(), { compact: true }) : '-'; + + const transfarableBalance = + balances && + Object.values(balances).reduce( + (total, balance) => + total.add( + convertMonetaryAmountToValueInUSD( + balance.transferable, + getTokenPrice(prices, balance.currency.ticker)?.usd + ) || 0 + ), + new Big(0) + ); + + const transfarableBalanceLabel = transfarableBalance + ? formatUSD(transfarableBalance.toNumber(), { compact: true }) + : '-'; + + return ( +
+ + + + + +
+ {t('total_balance')} +
+
+ {totalBalanceLabel} +
+
+
+ + +
+ {t('transferable_balance')} +
+
+ {transfarableBalanceLabel} +
+
+
+
+ ); +}; + +export { WalletInsights }; +export type { WalletInsightsProps }; diff --git a/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletMeta.tsx b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletMeta.tsx new file mode 100644 index 0000000000..3b79462324 --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/WalletInsights/WalletMeta.tsx @@ -0,0 +1,85 @@ +import { mergeProps } from '@react-aria/utils'; +import { useDispatch } from 'react-redux'; +import { useCopyToClipboard } from 'react-use'; + +import { ArrowTopRightOnSquare, DocumentDuplicate, PencilSquare } from '@/assets/icons'; +import { showAccountModalAction } from '@/common/actions/general.actions'; +import { shortAddress } from '@/common/utils/utils'; +import { CTA, CTALink, Dd, DlGroup, Dt, Flex, FlexProps, P, Tooltip, WalletIcon } from '@/component-library'; +import { AuthCTA } from '@/components'; +import { SUBSCAN_LINK } from '@/config/relay-chains'; +import { useSubstrateState } from '@/lib/substrate'; +import { useCopyTooltip } from '@/utils/hooks/use-copy-tooltip'; + +type WalletMetaProps = FlexProps; + +const WalletMeta = (props: WalletMetaProps): JSX.Element => { + const { selectedAccount } = useSubstrateState(); + const dispatch = useDispatch(); + + const [, copy] = useCopyToClipboard(); + const { buttonProps, tooltipProps } = useCopyTooltip(); + + if (!selectedAccount) { + return ( + +

No Account Connected

+ Connect Account +
+ ); + } + + const handleCopy = () => copy(selectedAccount.address); + + return ( + + + + + +
+ {selectedAccount.meta.name} +
+
{shortAddress(selectedAccount.address)}
+
+
+ + + + + + + dispatch(showAccountModalAction(true))} + variant='text' + size='x-small' + > + + + + + + +
+ {/* TODO: add back when banxa on-ramp is added */} + {/* + {t('fund_wallet')} + View History + */} +
+ ); +}; + +export { WalletMeta }; diff --git a/src/pages/Wallet/WalletOverview/components/WalletInsights/index.tsx b/src/pages/Wallet/WalletOverview/components/WalletInsights/index.tsx new file mode 100644 index 0000000000..ebc0b4243a --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/WalletInsights/index.tsx @@ -0,0 +1,2 @@ +export type { WalletInsightsProps } from './WalletInsights'; +export { WalletInsights } from './WalletInsights'; diff --git a/src/pages/Wallet/WalletOverview/components/WalletInsights/utils.ts b/src/pages/Wallet/WalletOverview/components/WalletInsights/utils.ts new file mode 100644 index 0000000000..f5d171d2a3 --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/WalletInsights/utils.ts @@ -0,0 +1,24 @@ +import { CurrencyExt, LpCurrency } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; + +import { calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; +import { Prices } from '@/utils/hooks/api/use-get-prices'; + +const calculateClaimableFarmingRewardUSD = ( + claimableRewards: Map[]> | undefined, + prices: Prices | undefined +): number => { + if (claimableRewards === undefined) { + return 0; + } + const flattenedRewardAmounts: Array> = []; + for (const [, rewardAmounts] of claimableRewards.entries()) { + flattenedRewardAmounts.push(...rewardAmounts); + } + + const totalRewardUSD = calculateTotalLiquidityUSD(flattenedRewardAmounts, prices); + + return totalRewardUSD; +}; + +export { calculateClaimableFarmingRewardUSD }; diff --git a/src/pages/Wallet/WalletOverview/components/index.tsx b/src/pages/Wallet/WalletOverview/components/index.tsx new file mode 100644 index 0000000000..e4670e5c97 --- /dev/null +++ b/src/pages/Wallet/WalletOverview/components/index.tsx @@ -0,0 +1,6 @@ +import { AvailableAssetsTable, AvailableAssetsTableProps } from './AvailableAssetsTable'; +import { StakingTable, StakingTableProps } from './StakingTable'; +import { WalletInsights, WalletInsightsProps } from './WalletInsights'; + +export { AvailableAssetsTable, StakingTable, WalletInsights }; +export type { AvailableAssetsTableProps, StakingTableProps, WalletInsightsProps }; diff --git a/src/pages/Wallet/WalletOverview/index.tsx b/src/pages/Wallet/WalletOverview/index.tsx new file mode 100644 index 0000000000..ab4e95ed6f --- /dev/null +++ b/src/pages/Wallet/WalletOverview/index.tsx @@ -0,0 +1,3 @@ +import WalletOverview from './WalletOverview'; + +export default WalletOverview; diff --git a/src/pages/Wallet/index.tsx b/src/pages/Wallet/index.tsx new file mode 100644 index 0000000000..ab4e95ed6f --- /dev/null +++ b/src/pages/Wallet/index.tsx @@ -0,0 +1,3 @@ +import WalletOverview from './WalletOverview'; + +export default WalletOverview; diff --git a/src/parts/Sidebar/SidebarContent/Navigation/index.tsx b/src/parts/Sidebar/SidebarContent/Navigation/index.tsx index 29315fb7f9..83581e5880 100644 --- a/src/parts/Sidebar/SidebarContent/Navigation/index.tsx +++ b/src/parts/Sidebar/SidebarContent/Navigation/index.tsx @@ -12,7 +12,8 @@ import { HandRaisedIcon, PresentationChartBarIcon, ScaleIcon, - Square3Stack3DIcon + Square3Stack3DIcon, + UserIcon } from '@heroicons/react/24/outline'; import clsx from 'clsx'; import * as React from 'react'; @@ -68,9 +69,16 @@ const Navigation = ({ const { vaultClientLoaded } = useSelector((state: StoreType) => state.general); const isLendingEnabled = useFeatureFlag(FeatureFlags.LENDING); const isAMMEnabled = useFeatureFlag(FeatureFlags.AMM); + const isWalletEnabled = useFeatureFlag(FeatureFlags.WALLET); const NAVIGATION_ITEMS = React.useMemo( () => [ + { + name: 'nav_wallet', + link: PAGES.WALLET, + icon: UserIcon, + disabled: !isWalletEnabled + }, { name: 'nav_bridge', link: PAGES.BRIDGE, @@ -185,7 +193,7 @@ const Navigation = ({ } } ], - [isLendingEnabled, isAMMEnabled, selectedAccount?.address, vaultClientLoaded] + [isWalletEnabled, isLendingEnabled, isAMMEnabled, selectedAccount?.address, vaultClientLoaded] ); return ( diff --git a/src/parts/Topbar/GetGovernanceTokenUI/index.tsx b/src/parts/Topbar/GetGovernanceTokenUI/index.tsx index 6379e6d166..474238bc04 100644 --- a/src/parts/Topbar/GetGovernanceTokenUI/index.tsx +++ b/src/parts/Topbar/GetGovernanceTokenUI/index.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; import { ReactComponent as AcalaLogoIcon } from '@/assets/img/exchanges/acala-logo.svg'; import { ReactComponent as GateLogoIcon } from '@/assets/img/exchanges/gate-logo.svg'; @@ -10,6 +11,8 @@ import { ReactComponent as MexcLogoForInterlayIcon } from '@/assets/img/exchange import { ReactComponent as MexcLogoForKintsugiIcon } from '@/assets/img/exchanges/mexc-logo-for-kintsugi.svg'; import { ReactComponent as StellaSwapLogoIcon } from '@/assets/img/exchanges/stellaswap-logo.svg'; import { ReactComponent as ZenlinkLogoIcon } from '@/assets/img/exchanges/zenlink-logo.svg'; +import { showBuyModal } from '@/common/actions/general.actions'; +import { StoreType } from '@/common/types/util.types'; import { GOVERNANCE_TOKEN_SYMBOL } from '@/config/relay-chains'; import InterlayDefaultOutlinedButton, { Props as InterlayDefaultOutlinedButtonProps @@ -94,15 +97,16 @@ const ExchangeLink = ({ href, icon }: ExchangeLinkProps) => { }; const GetGovernanceTokenUI = (props: InterlayDefaultOutlinedButtonProps): JSX.Element => { - const [modalOpen, setModalOpen] = React.useState(false); + const { isBuyModalOpen } = useSelector((state: StoreType) => state.general); const focusRef = React.useRef(null); const { t } = useTranslation(); + const dispatch = useDispatch(); const handleModalOpen = () => { - setModalOpen(true); + dispatch(showBuyModal(true)); }; const handleModalClose = () => { - setModalOpen(false); + dispatch(showBuyModal(false)); }; const getGovernanceTokenLabel = t('get_governance_token', { @@ -118,7 +122,7 @@ const GetGovernanceTokenUI = (props: InterlayDefaultOutlinedButtonProps): JSX.El {getGovernanceTokenLabel} - +
diff --git a/src/test/mocks/@interlay/interbtc-api/index.ts b/src/test/mocks/@interlay/interbtc-api/index.ts index 88110a8ffb..592472d6ce 100644 --- a/src/test/mocks/@interlay/interbtc-api/index.ts +++ b/src/test/mocks/@interlay/interbtc-api/index.ts @@ -14,6 +14,7 @@ import { mockFeeGetIssueFee, mockFeeGetIssueGriefingCollateralRate, mockGetCurrentActiveBlockNumber, + mockGetCurrentBlockNumber, mockGetFutureBlockNumber, mockGetStableBitcoinConfirmations, mockGetStableParachainConfirmations, @@ -51,6 +52,7 @@ import { mockSwap } from './parachain/amm'; import { mockGetForeignAssets } from './parachain/assetRegistry'; +import { mockGetStakedBalance, mockVotingBalance } from './parachain/escrow'; import { mockBorrow, mockClaimAllSubsidyRewards, @@ -68,6 +70,7 @@ import { mockWithdraw, mockWithdrawAll } from './parachain/loans'; +import { mockClaimVesting, mockVestingSchedules } from './parachain/vesting'; const DEFAULT_ACCOUNT_ADDRESS = 'a3aTRC4zs1djutYS9QuZSB3XmfRgNzFfyRtbZKaoQyv67Yzcc'; @@ -91,7 +94,17 @@ const mockInterBtcApi: RecursivePartial = { chainType: mockChainType } }, - on: jest.fn() + on: jest.fn(), + query: { + vesting: { + vestingSchedules: mockVestingSchedules as any + } + }, + tx: { + vesting: { + claim: mockClaimVesting + } + } }, assetRegistry: { getForeignAssets: mockGetForeignAssets @@ -144,7 +157,8 @@ const mockInterBtcApi: RecursivePartial = { system: { getStatusCode: mockSystemGetStatusCode, getFutureBlockNumber: mockGetFutureBlockNumber, - getCurrentActiveBlockNumber: mockGetCurrentActiveBlockNumber + getCurrentActiveBlockNumber: mockGetCurrentActiveBlockNumber, + getCurrentBlockNumber: mockGetCurrentBlockNumber }, tokens: { balance: mockTokensBalance, @@ -167,6 +181,10 @@ const mockInterBtcApi: RecursivePartial = { getOptimalTrade: mockGetOptimalTrade, swap: mockSwap, claimFarmingRewards: mockClaimFarmingRewards + }, + escrow: { + getStakedBalance: mockGetStakedBalance, + votingBalance: mockVotingBalance } }; diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/amm.ts b/src/test/mocks/@interlay/interbtc-api/parachain/amm.ts index 16a84846ba..8d08541ec5 100644 --- a/src/test/mocks/@interlay/interbtc-api/parachain/amm.ts +++ b/src/test/mocks/@interlay/interbtc-api/parachain/amm.ts @@ -92,7 +92,9 @@ const mockAddLiquidity = jest.fn(); const mockRemoveLiquidity = jest.fn(); -const mockGetLpTokens = jest.fn().mockResolvedValue([DEFAULT_LP_TOKEN_1, DEFAULT_LP_TOKEN_2]); +const DEFAULT_LP_TOKENS = [DEFAULT_LP_TOKEN_1, DEFAULT_LP_TOKEN_2]; + +const mockGetLpTokens = jest.fn().mockResolvedValue(DEFAULT_LP_TOKENS); const DEFAULT_TRADE_AMOUNT = { INPUT: newMonetaryAmount(1, RELAY_CHAIN_NATIVE_TOKEN, true), @@ -133,6 +135,7 @@ export { DEFAULT_LIQUIDITY_POOLS, DEFAULT_LP_TOKEN_1, DEFAULT_LP_TOKEN_2, + DEFAULT_LP_TOKENS, DEFAULT_MULTI_PATH_ELEMENT, DEFAULT_POOLED_CURRENCIES_1, DEFAULT_POOLED_CURRENCIES_2, diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/escrow.ts b/src/test/mocks/@interlay/interbtc-api/parachain/escrow.ts new file mode 100644 index 0000000000..8d27cc7621 --- /dev/null +++ b/src/test/mocks/@interlay/interbtc-api/parachain/escrow.ts @@ -0,0 +1,25 @@ +import '@testing-library/jest-dom'; + +import { newMonetaryAmount } from '@interlay/interbtc-api'; + +import { GOVERNANCE_TOKEN } from '@/config/relay-chains'; + +const DEFAULT_STAKED_AMOUNT = newMonetaryAmount(10, GOVERNANCE_TOKEN, true); + +const DEFAULT_STAKED_BALANCE = { amount: DEFAULT_STAKED_AMOUNT, endBlock: 0 }; + +const EMPTY_STAKED_BALANCE = { amount: newMonetaryAmount(0, GOVERNANCE_TOKEN), endBlock: 0 }; + +const mockGetStakedBalance = jest.fn().mockResolvedValue(DEFAULT_STAKED_BALANCE); + +const DEFAULT_VOTING_BALANCE = newMonetaryAmount(10, GOVERNANCE_TOKEN, true); + +const mockVotingBalance = jest.fn().mockResolvedValue(DEFAULT_VOTING_BALANCE); + +export { + DEFAULT_STAKED_BALANCE, + DEFAULT_VOTING_BALANCE, + EMPTY_STAKED_BALANCE, + mockGetStakedBalance, + mockVotingBalance +}; diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts b/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts index 27cfd19fa0..e29119298d 100644 --- a/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts +++ b/src/test/mocks/@interlay/interbtc-api/parachain/loans.ts @@ -124,7 +124,7 @@ const DEFAULT_ASSETS: TickerToData = { }; const mockGetLendPositionsOfAccount = jest.fn().mockReturnValue(DEFAULT_LEND_POSITIONS); -const mockGetBorrowPositionsOfAccount = jest.fn().mockRejectedValue(DEFAULT_BORROW_POSITIONS); +const mockGetBorrowPositionsOfAccount = jest.fn().mockReturnValue(DEFAULT_BORROW_POSITIONS); const mockGetLoanAssets = jest.fn().mockReturnValue(DEFAULT_ASSETS); const mockGetAccountSubsidyRewards = jest.fn().mockReturnValue(DEFAULT_INTR.MONETARY.MEDIUM); diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/redeem.ts b/src/test/mocks/@interlay/interbtc-api/parachain/redeem.ts index 8049710c54..23956e2c63 100644 --- a/src/test/mocks/@interlay/interbtc-api/parachain/redeem.ts +++ b/src/test/mocks/@interlay/interbtc-api/parachain/redeem.ts @@ -11,6 +11,7 @@ const MOCK_BURN_EXCHANGE_RATE = '150000'; const mockRedeemGetMaxBurnableTokens = jest.fn((_currency: CurrencyExt) => newMonetaryAmount(MOCK_MAX_BURNABLE_TOKENS, WRAPPED_TOKEN) ); + const mockRedeemGetBurnExchangeRate = jest.fn( (collateralCurrency: CollateralCurrencyExt) => new ExchangeRate(Bitcoin, collateralCurrency, Big(MOCK_BURN_EXCHANGE_RATE)) diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/system.ts b/src/test/mocks/@interlay/interbtc-api/parachain/system.ts index acbe20b37f..5c1622cbcb 100644 --- a/src/test/mocks/@interlay/interbtc-api/parachain/system.ts +++ b/src/test/mocks/@interlay/interbtc-api/parachain/system.ts @@ -11,10 +11,16 @@ const DEFAULT_CURRENT_ACTIVE_BLOCK_NUMBER = 1; const mockGetCurrentActiveBlockNumber = jest.fn().mockResolvedValue(DEFAULT_CURRENT_ACTIVE_BLOCK_NUMBER); +const DEFAULT_CURRENT_BLOCK_NUMBER = 0; + +const mockGetCurrentBlockNumber = jest.fn().mockReturnValue(DEFAULT_CURRENT_BLOCK_NUMBER); + export { DEFAULT_CURRENT_ACTIVE_BLOCK_NUMBER, + DEFAULT_CURRENT_BLOCK_NUMBER, DEFAULT_DEADLINE_BLOCK_NUMBER, mockGetCurrentActiveBlockNumber, + mockGetCurrentBlockNumber, mockGetFutureBlockNumber, mockSystemGetStatusCode }; diff --git a/src/test/mocks/@interlay/interbtc-api/parachain/vesting.ts b/src/test/mocks/@interlay/interbtc-api/parachain/vesting.ts new file mode 100644 index 0000000000..8725706d9d --- /dev/null +++ b/src/test/mocks/@interlay/interbtc-api/parachain/vesting.ts @@ -0,0 +1,9 @@ +const SOME_VESTING_SCHEDULES = [{ start: 0, period: 0, periodCount: 1, perPeriod: 1 }]; + +const EMPTY_VESTING_SCHEDULES: any[] = []; + +const mockVestingSchedules = jest.fn().mockReturnValue(EMPTY_VESTING_SCHEDULES); + +const mockClaimVesting = jest.fn(); + +export { EMPTY_VESTING_SCHEDULES, mockClaimVesting, mockVestingSchedules, SOME_VESTING_SCHEDULES }; diff --git a/src/test/pages/Burn.test.tsx b/src/test/pages/Burn.test.tsx index a8d0babf37..64cacffe5e 100644 --- a/src/test/pages/Burn.test.tsx +++ b/src/test/pages/Burn.test.tsx @@ -9,24 +9,14 @@ import { mockRedeemBurn, mockRedeemGetMaxBurnableTokens } from '../mocks/@interl import { act, render, screen, userEvent, waitFor } from '../test-utils'; describe('Burn page', () => { - it('if the burn tab is displayed when there is a liquidated vault', async () => { + it('the burn tab is displayed when there is a liquidated vault', async () => { await render(, { path: '/bridge?tab=burn' }); const burnTab = screen.getByRole('tab', { name: /burn/i }); expect(burnTab).toBeVisible(); }); - it('if the burn tab is not displayed when there is no liquidated vault', async () => { - mockRedeemGetMaxBurnableTokens.mockImplementationOnce(() => newMonetaryAmount('0', WRAPPED_TOKEN)); - - await render(, { path: '/bridge?tab=burn' }); - - await waitFor(() => { - expect(screen.queryByText(/Burn/i)).not.toBeInTheDocument(); - }); - }); - - it('if the burn method is called', async () => { + it('the burn method is called', async () => { await render(, { path: '/bridge?tab=burn' }); const burnTab = screen.getByRole('tab', { name: /burn/i }); @@ -49,4 +39,14 @@ describe('Burn page', () => { // Check that burn method was called. await waitFor(() => expect(mockRedeemBurn).toHaveBeenCalledTimes(1)); }); + + it('the burn tab is not displayed when there is no liquidated vault', async () => { + mockRedeemGetMaxBurnableTokens.mockImplementation(() => newMonetaryAmount('0', WRAPPED_TOKEN)); + + await render(, { path: '/bridge?tab=burn' }); + + await waitFor(() => { + expect(screen.queryByText(/Burn/i)).not.toBeInTheDocument(); + }); + }); }); diff --git a/src/test/pages/Loans/index.test.tsx b/src/test/pages/Loans/index.test.tsx index 0e67a76187..5d71f63017 100644 --- a/src/test/pages/Loans/index.test.tsx +++ b/src/test/pages/Loans/index.test.tsx @@ -20,7 +20,7 @@ import { } from '@/test/mocks/@interlay/interbtc-api/parachain/loans'; import { render, screen, userEvent, waitFor } from '../../test-utils'; -import { getTableRow } from '../utils/table'; +import { getTableRow, withinTable } from '../utils/table'; import { TABLES } from './constants'; const path = '/lending'; @@ -63,7 +63,9 @@ describe('Loans page', () => { await render(, { path }); - expect(screen.queryByRole('grid', { name: new RegExp(TABLES.BORROW.POSITION, 'i') })).not.toBeInTheDocument(); + const table = withinTable(TABLES.BORROW.POSITION); + + expect(table.queryAllByRole('row')).toHaveLength(0); expect(screen.getByText(/no borrow positions/i)).toBeInTheDocument(); }); }); diff --git a/src/test/pages/Swap.test.tsx b/src/test/pages/Swap.test.tsx index cd0367a2f7..80897a7014 100644 --- a/src/test/pages/Swap.test.tsx +++ b/src/test/pages/Swap.test.tsx @@ -258,4 +258,28 @@ describe('Swap Page', () => { expect(mockSwap).toHaveBeenCalledTimes(1); }); }); + + it('should setup input and output currencies from search query', async () => { + await render(, { path: `${path}?from=${WRAPPED_TOKEN.ticker}&to=${RELAY_CHAIN_NATIVE_TOKEN.ticker}` }); + + await waitFor(() => { + expect(screen.getByRole('textbox', { name: /choose token for from field/i })).toHaveValue(WRAPPED_TOKEN.ticker); + + expect(screen.getByRole('textbox', { name: /choose token for to field/i })).toHaveValue( + RELAY_CHAIN_NATIVE_TOKEN.ticker + ); + }); + }); + + it('should setup input and output currencies to default pair when query is invalid', async () => { + await render(, { path: `${path}?from=&to=` }); + + await waitFor(() => { + expect(screen.getByRole('textbox', { name: /choose token for from field/i })).toHaveValue( + RELAY_CHAIN_NATIVE_TOKEN.ticker + ); + + expect(screen.getByRole('textbox', { name: /choose token for to field/i })).not.toHaveValue(); + }); + }); }); diff --git a/src/test/pages/Wallet.test.tsx b/src/test/pages/Wallet.test.tsx new file mode 100644 index 0000000000..c2e1d5bcc0 --- /dev/null +++ b/src/test/pages/Wallet.test.tsx @@ -0,0 +1,250 @@ +import MatchMediaMock from 'jest-matchmedia-mock'; + +import App from '@/App'; +import { theme } from '@/component-library'; +import { GOVERNANCE_TOKEN, RELAY_CHAIN_NATIVE_TOKEN, WRAPPED_TOKEN } from '@/config/relay-chains'; +import { NATIVE_CURRENCIES } from '@/utils/constants/currency'; +import { PAGES, QUERY_PARAMETERS } from '@/utils/constants/links'; + +import { + DEFAULT_CURRENT_BLOCK_NUMBER, + DEFAULT_TOKENS_BALANCE_FN, + EMPTY_TOKENS_BALANCE_FN, + mockGetCurrentBlockNumber, + mockTokensBalance +} from '../mocks/@interlay/interbtc-api'; +import { + ACCOUNT_WITH_FULL_LIQUIDITY, + DEFAULT_ACCOUNT_LIQUIDITY, + mockGetLiquidityProvidedByAccount, + mockGetLpTokens +} from '../mocks/@interlay/interbtc-api/parachain/amm'; +import { + DEFAULT_STAKED_BALANCE, + EMPTY_STAKED_BALANCE, + mockGetStakedBalance +} from '../mocks/@interlay/interbtc-api/parachain/escrow'; +import { + DEFAULT_BORROW_POSITIONS, + DEFAULT_LEND_POSITIONS, + mockGetBorrowPositionsOfAccount, + mockGetLendPositionsOfAccount +} from '../mocks/@interlay/interbtc-api/parachain/loans'; +import { + EMPTY_VESTING_SCHEDULES, + mockClaimVesting, + mockVestingSchedules, + SOME_VESTING_SCHEDULES +} from '../mocks/@interlay/interbtc-api/parachain/vesting'; +import { render, screen, userEvent, waitFor } from '../test-utils'; +import { withinList } from './utils/list'; +import { queryTable, withinTable, withinTableRow } from './utils/table'; + +jest.mock('@/pages/AMM', () => ({ __esModule: true, default: () =>
Swap page
})); + +const path = '/wallet'; + +const TABLES = { + AVAILABLE_ASSETS: 'available assets', + LEND_POSITIONS: 'lend positions', + BORROW_POSITIONS: 'borrow positions', + LIQUIDITY_POOLS: 'liquidity pools', + STAKED: 'staked' +}; + +describe('Wallet Page', () => { + let matchMedia: MatchMediaMock; + + beforeEach(() => { + matchMedia = new MatchMediaMock(); + + // ignoring lp-tokens + mockGetLpTokens.mockResolvedValue([]); + mockTokensBalance.mockImplementation(DEFAULT_TOKENS_BALANCE_FN); + mockGetLendPositionsOfAccount.mockReturnValue(DEFAULT_LEND_POSITIONS); + mockGetBorrowPositionsOfAccount.mockReturnValue(DEFAULT_BORROW_POSITIONS); + mockGetLiquidityProvidedByAccount.mockReturnValue(DEFAULT_ACCOUNT_LIQUIDITY); + mockGetStakedBalance.mockReturnValue(DEFAULT_STAKED_BALANCE); + mockGetCurrentBlockNumber.mockReturnValue(DEFAULT_CURRENT_BLOCK_NUMBER); + mockVestingSchedules.mockReturnValue(EMPTY_VESTING_SCHEDULES); + }); + + afterEach(() => { + matchMedia.clear(); + }); + + // TODO: add tests for Buy and Transfer CTALinks + describe('Available Assets', () => { + it('should render table (desktop)', async () => { + await render(, { path }); + + const table = withinTable(TABLES.AVAILABLE_ASSETS); + + expect(table.getAllByRole('row')).toHaveLength(NATIVE_CURRENCIES.length); + }); + + it('should render list (mobile)', async () => { + matchMedia.useMediaQuery(theme.breakpoints.down('md')); + + await render(, { path }); + + const list = withinList(TABLES.AVAILABLE_ASSETS); + + expect(list.getAllByRole('row')).toHaveLength(NATIVE_CURRENCIES.length); + }); + + it('should be able to navigate to issue page', async () => { + const { history } = await render(, { path }); + + const row = withinTableRow(TABLES.AVAILABLE_ASSETS, WRAPPED_TOKEN.ticker); + + userEvent.click(row.getByRole('link', { name: /issue/i })); + + expect(history.location.pathname).toBe(PAGES.BRIDGE); + expect(history.location.search).toMatch(`${QUERY_PARAMETERS.TAB}=issue`); + }); + + // TODO: enable when banxa e merged + it.skip('should be able to open buy dialog', async () => { + await render(, { path }); + + const row = withinTableRow(TABLES.AVAILABLE_ASSETS, GOVERNANCE_TOKEN.ticker); + + userEvent.click(row.getByRole('button', { name: /buy/i })); + + await waitFor(() => { + expect(screen.getByRole('dialog')).toBeInTheDocument(); + }); + }); + + it('should be able to claim vesting', async () => { + mockGetCurrentBlockNumber.mockReturnValue(10); + mockVestingSchedules.mockReturnValue(SOME_VESTING_SCHEDULES); + + await render(, { path }); + + const row = withinTableRow(TABLES.AVAILABLE_ASSETS, GOVERNANCE_TOKEN.ticker); + + userEvent.click(row.getByRole('button', { name: /claim vesting/i })); + + await waitFor(() => { + expect(mockClaimVesting).toHaveBeenCalledTimes(1); + }); + }); + + it(`should be able to navigate to swap page using ${WRAPPED_TOKEN.ticker}`, async () => { + const { history } = await render(, { path }); + + const row = withinTableRow(TABLES.AVAILABLE_ASSETS, WRAPPED_TOKEN.ticker); + + userEvent.click(row.getByRole('link', { name: /swap/i })); + + expect(history.location.pathname).toBe(PAGES.SWAP); + expect(history.location.search).toMatch(`${QUERY_PARAMETERS.SWAP.FROM}=${WRAPPED_TOKEN.ticker}`); + }); + + it(`should be able to navigate to swap page using ${RELAY_CHAIN_NATIVE_TOKEN.ticker}`, async () => { + const { history } = await render(, { path }); + + const row = withinTableRow(TABLES.AVAILABLE_ASSETS, RELAY_CHAIN_NATIVE_TOKEN.ticker); + + userEvent.click(row.getByRole('link', { name: /swap/i })); + + expect(history.location.pathname).toBe(PAGES.SWAP); + expect(history.location.search).toMatch( + `${QUERY_PARAMETERS.SWAP.FROM}=${RELAY_CHAIN_NATIVE_TOKEN.ticker}&${QUERY_PARAMETERS.SWAP.TO}=${WRAPPED_TOKEN.ticker}` + ); + }); + + it('should display zero balance assets', async () => { + mockTokensBalance.mockImplementation(EMPTY_TOKENS_BALANCE_FN); + + await render(, { path }); + + const table = withinTable(TABLES.AVAILABLE_ASSETS); + + expect(table.queryAllByRole('row')).toHaveLength(0); + expect(screen.getByText(/no assets available/i)).toBeInTheDocument(); + + userEvent.click(screen.getByRole('switch', { name: /show zero balance/i })); + + await waitFor(() => { + expect(table.queryAllByRole('row')).toHaveLength(NATIVE_CURRENCIES.length); + }); + }); + }); + + describe('Lending Positions', () => { + it('should display table', async () => { + await render(, { path }); + + const table = withinTable(TABLES.LEND_POSITIONS); + + expect(table.getAllByRole('row')).toHaveLength(DEFAULT_LEND_POSITIONS.length); + }); + + it('should not display table', async () => { + mockGetLendPositionsOfAccount.mockReturnValue([]); + + await render(, { path }); + + expect(queryTable(TABLES.LEND_POSITIONS)).not.toBeInTheDocument(); + }); + }); + + describe('Borrow Positions', () => { + it('should display table', async () => { + await render(, { path }); + + const table = withinTable(TABLES.BORROW_POSITIONS); + + expect(table.getAllByRole('row')).toHaveLength(DEFAULT_BORROW_POSITIONS.length); + }); + + it('should not display table', async () => { + mockGetBorrowPositionsOfAccount.mockReturnValue([]); + + await render(, { path }); + + expect(queryTable(TABLES.BORROW_POSITIONS)).not.toBeInTheDocument(); + }); + }); + + describe('Liquidity Pools', () => { + it('should display table', async () => { + mockGetLiquidityProvidedByAccount.mockResolvedValue(ACCOUNT_WITH_FULL_LIQUIDITY); + + await render(, { path }); + + const table = withinTable(TABLES.LIQUIDITY_POOLS); + + expect(table.getAllByRole('row')).toHaveLength(ACCOUNT_WITH_FULL_LIQUIDITY.length); + }); + + it('should not display table', async () => { + mockGetLiquidityProvidedByAccount.mockReturnValue(DEFAULT_ACCOUNT_LIQUIDITY); + + await render(, { path }); + + expect(queryTable(TABLES.LIQUIDITY_POOLS)).not.toBeInTheDocument(); + }); + }); + + describe('Staking', () => { + it('should display table', async () => { + await render(, { path }); + + const table = withinTable(TABLES.STAKED); + + expect(table.getAllByRole('row')).toHaveLength(1); + }); + + it('should not display table', async () => { + mockGetStakedBalance.mockReturnValue(EMPTY_STAKED_BALANCE); + + await render(, { path }); + + expect(queryTable(TABLES.LIQUIDITY_POOLS)).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/test/pages/utils/common.ts b/src/test/pages/utils/common.ts new file mode 100644 index 0000000000..223d6c77f2 --- /dev/null +++ b/src/test/pages/utils/common.ts @@ -0,0 +1,6 @@ +type ElementName = string | RegExp; + +const composeName = (name: ElementName): RegExp => (typeof name === 'string' ? new RegExp(name, 'i') : name); + +export { composeName }; +export type { ElementName }; diff --git a/src/test/pages/utils/list.ts b/src/test/pages/utils/list.ts new file mode 100644 index 0000000000..2818e63523 --- /dev/null +++ b/src/test/pages/utils/list.ts @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { screen, within } from '../../test-utils'; +import { composeName, ElementName } from './common'; + +const getList = (name: ElementName) => screen.getByRole('grid', { name: composeName(name) }); + +const withinList = (name: ElementName) => within(getList(name)); + +const getListRow = (listName: ElementName, rowName: ElementName) => { + const table = withinList(listName); + + return table.getByRole('row', { name: composeName(rowName) }); +}; + +const withinListRow = (listName: string, asset: string) => within(getListRow(listName, asset)); + +export { getList, getListRow, withinList, withinListRow }; diff --git a/src/test/pages/utils/table.ts b/src/test/pages/utils/table.ts index 96037c9ea9..bad822e8a3 100644 --- a/src/test/pages/utils/table.ts +++ b/src/test/pages/utils/table.ts @@ -1,12 +1,11 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { screen, userEvent, waitFor, waitForElementToBeRemoved, within } from '../../test-utils'; - -type ElementName = string | RegExp; - -const composeName = (name: ElementName) => (typeof name === 'string' ? new RegExp(name, 'i') : name); +import { composeName, ElementName } from './common'; const getTable = (name: ElementName) => screen.getByRole('grid', { name: composeName(name) }); +const queryTable = (name: ElementName) => screen.queryByRole('grid', { name: composeName(name) }); + const withinTable = (name: ElementName) => { const table = within(getTable(name)); return within(table.getAllByRole('rowgroup')[1]); @@ -68,4 +67,4 @@ const submitForm = async (tabPanel: ReturnType, butt await waitForElementToBeRemoved(screen.getByRole('dialog')); }; -export { getTable, getTableRow, submitForm, withinModalTabPanel, withinTable, withinTableRow }; +export { getTable, getTableRow, queryTable, submitForm, withinModalTabPanel, withinTable, withinTableRow }; diff --git a/src/test/test-utils.tsx b/src/test/test-utils.tsx index e0f8fd3c73..3dc04831db 100644 --- a/src/test/test-utils.tsx +++ b/src/test/test-utils.tsx @@ -40,7 +40,10 @@ const ProvidersWrapper: (history: MemoryHistory) => FC<{ children?: React.ReactN ); }; -const customRender = async (ui: ReactElement, options?: CustomRenderOptions): Promise> => { +const customRender = async ( + ui: ReactElement, + options?: CustomRenderOptions +): Promise & { history: MemoryHistory }> => { const history = createMemoryHistory(); if (options?.path) { history.push(options.path); @@ -53,7 +56,7 @@ const customRender = async (ui: ReactElement, options?: CustomRenderOptions): Pr _render = render(ui, { wrapper: ProvidersWrapper(history), ...options }); }); - return _render as any; + return { ...(_render as any), history }; }; export * from '@testing-library/react'; diff --git a/src/utils/constants/links.ts b/src/utils/constants/links.ts index 6eaf055a0d..852612b127 100644 --- a/src/utils/constants/links.ts +++ b/src/utils/constants/links.ts @@ -28,7 +28,8 @@ const PAGES = Object.freeze({ ACTIONS: '/actions', LOANS: '/lending', SWAP: '/swap', - POOLS: '/pools' + POOLS: '/pools', + WALLET: '/wallet' }); const QUERY_PARAMETERS = Object.freeze({ @@ -37,7 +38,11 @@ const QUERY_PARAMETERS = Object.freeze({ ISSUE_REQUESTS_PAGE: 'issueRequestPage', REDEEM_REQUESTS_PAGE: 'redeemRequestPage', ISSUE_REQUEST_ID: 'issueRequestId', - REDEEM_REQUEST_ID: 'redeemRequestId' + REDEEM_REQUEST_ID: 'redeemRequestId', + SWAP: { + FROM: 'from', + TO: 'to' + } }); export { PAGES, QUERY_PARAMETERS, URL_PARAMETERS }; diff --git a/src/utils/helpers/coin-icon.ts b/src/utils/helpers/coin-icon.ts index 66abef5069..766d60c95a 100644 --- a/src/utils/helpers/coin-icon.ts +++ b/src/utils/helpers/coin-icon.ts @@ -2,7 +2,7 @@ import { CurrencyExt, StandardLpToken } from '@interlay/interbtc-api'; import { CoinIconProps } from '@/component-library'; -const getCoinIconProps = (currency: CurrencyExt): CoinIconProps => { +const getCoinIconProps = (currency: CurrencyExt): Pick => { if ((currency as StandardLpToken)?.lpToken) { return { ticker: currency.ticker, diff --git a/src/pages/Loans/LoansOverview/utils/get-subsidy-rewards-apy.ts b/src/utils/helpers/loans.ts similarity index 54% rename from src/pages/Loans/LoansOverview/utils/get-subsidy-rewards-apy.ts rename to src/utils/helpers/loans.ts index 13061b9ef3..c7241abb5e 100644 --- a/src/pages/Loans/LoansOverview/utils/get-subsidy-rewards-apy.ts +++ b/src/utils/helpers/loans.ts @@ -2,8 +2,27 @@ import { CurrencyExt } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; import Big from 'big.js'; -import { getTokenPrice } from '../../../../utils/helpers/prices'; -import { Prices } from '../../../../utils/hooks/api/use-get-prices'; +import { formatPercentage } from '@/common/utils/utils'; + +import { Prices } from '../hooks/api/use-get-prices'; +import { getTokenPrice } from './prices'; + +const MIN_DECIMAL_NUMBER = 0.01; + +// MEMO: returns formatted apy or better representation of a very small apy +const getApyLabel = (apy: Big): string => { + const isPositive = apy.gt(0); + const isTinyApy = isPositive ? apy.lt(MIN_DECIMAL_NUMBER) : apy.gt(-MIN_DECIMAL_NUMBER); + + if (isTinyApy) { + const tinyIndicator = apy.gt(0) ? '<' : '>'; + const minDecimal = isPositive ? MIN_DECIMAL_NUMBER : -MIN_DECIMAL_NUMBER; + + return `${tinyIndicator}${minDecimal}%`; + } + + return formatPercentage(apy.toNumber()); +}; const getSubsidyRewardApy = ( positionCurrency: CurrencyExt | undefined, @@ -27,4 +46,4 @@ const getSubsidyRewardApy = ( return apy; }; -export { getSubsidyRewardApy }; +export { getApyLabel, getSubsidyRewardApy }; diff --git a/src/utils/helpers/pools.ts b/src/utils/helpers/pools.ts new file mode 100644 index 0000000000..e75c766884 --- /dev/null +++ b/src/utils/helpers/pools.ts @@ -0,0 +1,32 @@ +import { CurrencyExt, LiquidityPool, LpCurrency } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; +import Big from 'big.js'; + +import { calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; + +import { Prices } from '../hooks/api/use-get-prices'; + +const getPooledTickers = (liquidityPools: LiquidityPool[]): Set => + liquidityPools.reduce((acc, pool) => { + pool.pooledCurrencies.forEach((curr) => acc.add(curr.currency.ticker)); + + return acc; + }, new Set()); + +const getFarmingApr = ( + rewardAmountsYearly: Array>, + lpTotalSupply: MonetaryAmount, + totalLiquidityUSD: number, + prices: Prices | undefined +): Big => { + if (prices === undefined || lpTotalSupply.toBig().eq(0) || totalLiquidityUSD === 0) { + return new Big(0); + } + const totalRewardsPerTokenUSD = calculateTotalLiquidityUSD(rewardAmountsYearly, prices); + + const farmingApr = new Big(totalRewardsPerTokenUSD).div(totalLiquidityUSD).mul(100); + + return farmingApr; +}; + +export { getFarmingApr, getPooledTickers }; diff --git a/src/utils/hooks/api/escrow/use-get-account-staking-data.tsx b/src/utils/hooks/api/escrow/use-get-account-staking-data.tsx new file mode 100644 index 0000000000..31aebac5d7 --- /dev/null +++ b/src/utils/hooks/api/escrow/use-get-account-staking-data.tsx @@ -0,0 +1,71 @@ +import { CurrencyExt } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; +import { AccountId } from '@polkadot/types/interfaces'; +import { add } from 'date-fns'; +import { useErrorHandler } from 'react-error-boundary'; +import { useQuery } from 'react-query'; + +import { BLOCK_TIME } from '@/config/parachain'; +import { BLOCKTIME_REFETCH_INTERVAL } from '@/utils/constants/api'; + +import useAccountId from '../../use-account-id'; + +type AccountUnlockStakingData = { + date: Date; + block: number; +}; + +type GetAccountStakingData = { + unlock: AccountUnlockStakingData; + balance: MonetaryAmount; +}; + +const getUnlockData = (stakeEndBlock: number, currentBlockNumber: number): AccountUnlockStakingData => { + const blocksUntilUnlockDate = stakeEndBlock - currentBlockNumber; + + const unlockDate = add(new Date(), { seconds: blocksUntilUnlockDate * BLOCK_TIME }); + + return { + date: unlockDate, + block: stakeEndBlock + }; +}; + +const getAccountStakingData = async (accountId: AccountId): Promise => { + const stakedBalancePromise = window.bridge.escrow.getStakedBalance(accountId); + const currentBlockNumberPromise = window.bridge.system.getCurrentBlockNumber(); + + const [stakedBalance, currentBlockNumber] = await Promise.all([stakedBalancePromise, currentBlockNumberPromise]); + + const unlock = getUnlockData(stakedBalance.endBlock, currentBlockNumber); + + return { + unlock, + balance: stakedBalance.amount + }; +}; + +interface GetAccountStakingDataResult { + data: GetAccountStakingData | undefined; + refetch: () => void; +} + +const useGetAccountStakingData = (): GetAccountStakingDataResult => { + const accountId = useAccountId(); + + const queryKey = ['staking', accountId]; + + const { data, error, refetch } = useQuery({ + queryKey, + queryFn: () => accountId && getAccountStakingData(accountId), + refetchInterval: BLOCKTIME_REFETCH_INTERVAL, + enabled: !!accountId + }); + + useErrorHandler(error); + + return { data, refetch }; +}; + +export { useGetAccountStakingData }; +export type { AccountUnlockStakingData, GetAccountStakingData, GetAccountStakingDataResult }; diff --git a/src/utils/hooks/api/escrow/use-get-account-voting-balance.tsx b/src/utils/hooks/api/escrow/use-get-account-voting-balance.tsx new file mode 100644 index 0000000000..649e79e61c --- /dev/null +++ b/src/utils/hooks/api/escrow/use-get-account-voting-balance.tsx @@ -0,0 +1,37 @@ +import { CurrencyExt } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; +import { AccountId } from '@polkadot/types/interfaces'; +import { useErrorHandler } from 'react-error-boundary'; +import { useQuery } from 'react-query'; + +import { BLOCKTIME_REFETCH_INTERVAL } from '@/utils/constants/api'; + +import useAccountId from '../../use-account-id'; + +const getAccountVotingBalance = async (accountId: AccountId): Promise> => + window.bridge.escrow.votingBalance(accountId); + +interface GetAccountVotingBalanceResult { + data: MonetaryAmount | undefined; + refetch: () => void; +} + +const useGetAccountVotingBalance = (): GetAccountVotingBalanceResult => { + const accountId = useAccountId(); + + const queryKey = ['voting', accountId]; + + const { data, error, refetch } = useQuery({ + queryKey, + queryFn: () => accountId && getAccountVotingBalance(accountId), + refetchInterval: BLOCKTIME_REFETCH_INTERVAL, + enabled: !!accountId + }); + + useErrorHandler(error); + + return { data, refetch }; +}; + +export { useGetAccountVotingBalance }; +export type { GetAccountVotingBalanceResult }; diff --git a/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx b/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx index fbb860faba..b9211bba93 100644 --- a/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx +++ b/src/utils/hooks/api/loans/use-get-account-lending-statistics.tsx @@ -11,7 +11,7 @@ import Big from 'big.js'; import { useMemo } from 'react'; import { convertMonetaryAmountToValueInUSD, convertMonetaryBtcToUSD } from '@/common/utils/utils'; -import { getSubsidyRewardApy } from '@/pages/Loans/LoansOverview/utils/get-subsidy-rewards-apy'; +import { getSubsidyRewardApy } from '@/utils/helpers/loans'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetLoanAssets } from '@/utils/hooks/api/loans/use-get-loan-assets'; diff --git a/src/utils/hooks/api/use-get-currencies.tsx b/src/utils/hooks/api/use-get-currencies.tsx index f6833b3758..1442f6a14c 100644 --- a/src/utils/hooks/api/use-get-currencies.tsx +++ b/src/utils/hooks/api/use-get-currencies.tsx @@ -68,18 +68,6 @@ const useGetCurrencies = (bridgeLoaded: boolean): UseGetCurrenciesResult => { [queryResult] ); - // export declare type StandardLpToken = Currency & { - // lpToken: { - // token0: StandardLpUnderlyingToken; - // token1: StandardLpUnderlyingToken; - // }; - // }; - // export declare type StableLpToken = Currency & { - // stableLpToken: { - // poolId: number; - // }; - // }; - // Throws when passed parameter is not id of any foreign currency or currencies are not loaded yet. const getLendCurrencyFromId = useCallback( (id: number): CurrencyExt => { diff --git a/src/utils/hooks/api/use-get-vesting-data.tsx b/src/utils/hooks/api/use-get-vesting-data.tsx new file mode 100644 index 0000000000..48972a88f1 --- /dev/null +++ b/src/utils/hooks/api/use-get-vesting-data.tsx @@ -0,0 +1,50 @@ +import { AccountId } from '@polkadot/types/interfaces'; +import { Codec } from '@polkadot/types/types'; +import { useErrorHandler } from 'react-error-boundary'; +import { useQuery } from 'react-query'; + +import { BLOCKTIME_REFETCH_INTERVAL } from '@/utils/constants/api'; + +import useAccountId from '../use-account-id'; + +type VestingData = { + schedules: Codec; + isClaimable: boolean; +}; + +interface UseGetVestingResult { + data: VestingData | undefined; + refetch: () => void; +} + +const getVestingData = async (accountId: AccountId): Promise => { + const currentBlockNumber = await window.bridge.system.getCurrentBlockNumber(); + + const schedules = await window.bridge.api.query.vesting.vestingSchedules(accountId); + + const schedule = schedules[0]; + const isClaimable = !!schedule && currentBlockNumber > schedule.start + schedule.period; + + return { + schedules, + isClaimable + }; +}; + +const useGetVestingData = (): UseGetVestingResult => { + const accountId = useAccountId(); + + const queryKey = ['vesting-schedule', accountId]; + const { data, error, refetch } = useQuery({ + queryKey, + queryFn: () => accountId && getVestingData(accountId), + refetchInterval: BLOCKTIME_REFETCH_INTERVAL + }); + + useErrorHandler(error); + + return { data, refetch }; +}; + +export { useGetVestingData }; +export type { UseGetVestingResult }; diff --git a/src/utils/hooks/api/xcm/use-xcm-bridge.ts b/src/utils/hooks/api/xcm/use-xcm-bridge.ts index 390d10958f..4b086c55c8 100644 --- a/src/utils/hooks/api/xcm/use-xcm-bridge.ts +++ b/src/utils/hooks/api/xcm/use-xcm-bridge.ts @@ -5,13 +5,13 @@ import { firstValueFrom } from 'rxjs'; import { XCM_ADAPTERS } from '@/config/relay-chains'; import { BITCOIN_NETWORK } from '@/constants'; +// MEMO: BitcoinNetwork type is not available on XCM bridge +const XCMNetwork = BITCOIN_NETWORK === 'mainnet' ? 'mainnet' : 'testnet'; + const XCMBridge = new Bridge({ adapters: Object.values(XCM_ADAPTERS) }); -// MEMO: BitcoinNetwork type is not available on XCM bridge -const XCMNetwork = BITCOIN_NETWORK === 'mainnet' ? 'mainnet' : 'testnet'; - // TODO: This config needs to be pushed higher up the app. // Not sure how this will look: something to decide when // adding USDT support. diff --git a/src/utils/hooks/use-copy-tooltip.tsx b/src/utils/hooks/use-copy-tooltip.tsx new file mode 100644 index 0000000000..36ec13ccd4 --- /dev/null +++ b/src/utils/hooks/use-copy-tooltip.tsx @@ -0,0 +1,63 @@ +import { HoverProps, useHover } from '@react-aria/interactions'; +import { mergeProps } from '@react-aria/utils'; +import { DOMAttributes, FocusableElement } from '@react-types/shared'; +import { useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useTimeoutFn } from 'react-use'; + +type CopyTooltipProp = Pick; + +type CopyTooltipResult = { + buttonProps: DOMAttributes; + tooltipProps: { + isOpen: boolean; + label: string; + }; +}; + +const useCopyTooltip = (props?: CopyTooltipProp): CopyTooltipResult => { + const { t } = useTranslation(); + + const defaultTooltipProps = useMemo(() => ({ isOpen: false, label: t('click_to_copy') }), [t]); + + const [tooltipProps, setTooltipProps] = useState(defaultTooltipProps); + const [isReadyToDefaultLabel, cancelLabelReset, setToDefaultLabel] = useTimeoutFn( + () => setTooltipProps((s) => ({ ...s, label: t('click_to_copy') })), + 1000 + ); + + const [isReadyToExit, cancelExit, delayExit] = useTimeoutFn(() => { + setTooltipProps((s) => ({ ...s, isOpen: false })); + }, 500); + + const defaultHoverProps = { + onHoverStart: () => { + // Cancel exit if is still ongoing + if (!isReadyToExit()) { + cancelExit(); + } + + setTooltipProps({ label: t('click_to_copy'), isOpen: true }); + }, + onHoverEnd: delayExit + }; + + const { hoverProps } = useHover({ ...props, ...defaultHoverProps }); + + const handlePress = () => { + // Cancel setting label to default if is still ongoing + if (!isReadyToDefaultLabel()) { + cancelLabelReset(); + } + setTooltipProps({ isOpen: true, label: t('copied') }); + setToDefaultLabel(); + }; + + return { + buttonProps: mergeProps(hoverProps, { onPress: handlePress }), + tooltipProps + }; +}; + +export { useCopyTooltip }; +export type { CopyTooltipResult }; diff --git a/src/utils/hooks/use-feature-flag.ts b/src/utils/hooks/use-feature-flag.ts index 2a56a1d222..58ae2cb1f7 100644 --- a/src/utils/hooks/use-feature-flag.ts +++ b/src/utils/hooks/use-feature-flag.ts @@ -1,11 +1,13 @@ enum FeatureFlags { LENDING = 'lending', - AMM = 'amm' + AMM = 'amm', + WALLET = 'wallet' } const featureFlags: Record = { [FeatureFlags.LENDING]: process.env.REACT_APP_FEATURE_FLAG_LENDING, - [FeatureFlags.AMM]: process.env.REACT_APP_FEATURE_FLAG_AMM + [FeatureFlags.AMM]: process.env.REACT_APP_FEATURE_FLAG_AMM, + [FeatureFlags.WALLET]: process.env.REACT_APP_FEATURE_FLAG_WALLET }; const useFeatureFlag = (feature: FeatureFlags): boolean => featureFlags[feature] === 'enabled'; diff --git a/yarn.lock b/yarn.lock index ee187abc45..e1db99f1ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,13 +30,13 @@ integrity sha512-oBgXGUjRW+lRo9TWGtCB1+OpEOFfhxW//wReb7V/YdbEElVvYuKw3lmfly/eZ/mdBgqxA3eXxNW0AgXiyOn2NQ== "@acala-network/eth-providers@^2.5.4": - version "2.5.9" - resolved "https://registry.yarnpkg.com/@acala-network/eth-providers/-/eth-providers-2.5.9.tgz#8cd6cb2932f5c270892a4e9c5e754d7c52e0b2a3" - integrity sha512-qYDRxr9XNTIsekuSju+oZPFiRj0Hhg7gkkBEhnn5AOYsj83zh4rgGHEtLef7D6Xk7Uf6+X+Ute7qtlw8XRj6hQ== + version "2.6.5" + resolved "https://registry.yarnpkg.com/@acala-network/eth-providers/-/eth-providers-2.6.5.tgz#9087abe44a0686de5188ea962961519ecff20e66" + integrity sha512-Y0hi0LRN8pJ144dv9WcSi9nPn5Wez0h745EGa1/6NFtU7jsua0jg25WYJ53s17rXIMz8GUKdln9SAIeShQiEtw== dependencies: "@acala-network/api" "~4.1.8-9" "@acala-network/contracts" "~4.3.4" - "@acala-network/eth-transactions" "2.5.9" + "@acala-network/eth-transactions" "2.6.5" "@acala-network/types" "~4.1.8-9" "@ethersproject/abstract-provider" "~5.7.0" "@ethersproject/address" "~5.7.0" @@ -50,23 +50,23 @@ "@ethersproject/providers" "~5.7.0" "@ethersproject/transactions" "~5.7.0" "@ethersproject/wallet" "~5.7.0" - "@polkadot/api" "^9.9.1" - "@polkadot/api-augment" "9.9.1" - "@polkadot/api-derive" "^9.9.1" - "@polkadot/keyring" "^10.1.13" - "@polkadot/types" "^9.9.1" - "@polkadot/util" "^10.1.13" - "@polkadot/util-crypto" "^10.1.13" + "@polkadot/api" "9.10.3" + "@polkadot/api-augment" "9.10.3" + "@polkadot/api-derive" "9.10.3" + "@polkadot/keyring" "^10.2.1" + "@polkadot/types" "9.10.3" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" bn.js "~5.2.0" ethers "~5.7.0" graphql "~16.0.1" graphql-request "~3.6.1" lru-cache "~7.8.2" -"@acala-network/eth-transactions@2.5.9": - version "2.5.9" - resolved "https://registry.yarnpkg.com/@acala-network/eth-transactions/-/eth-transactions-2.5.9.tgz#5e8d7c0e1ef1e49290aabd08ae2161f3321bf564" - integrity sha512-Aev44uUwDuYLXDuLrPTl99W9TgJevKhFUuBUUmeb00Uwf4KWzHFbDbI/PD1GwgetCmOe+wv7IqYrHha+R627kQ== +"@acala-network/eth-transactions@2.6.5": + version "2.6.5" + resolved "https://registry.yarnpkg.com/@acala-network/eth-transactions/-/eth-transactions-2.6.5.tgz#ddc93a3cd766c89aa81acdcd4aa9d00854b2116d" + integrity sha512-r+1i3AWHpg+vWZbiTldDSztZAPh+lJl4d9NKh7DCRgEd5/yOXgK5D05j1tTISut3ckENHBE2m0MKDp/4xX+3Eg== dependencies: "@ethersproject/address" "~5.7.0" "@ethersproject/bignumber" "~5.7.0" @@ -77,7 +77,7 @@ "@ethersproject/rlp" "~5.7.0" "@ethersproject/transactions" "~5.7.0" "@ethersproject/wallet" "~5.7.0" - "@polkadot/util-crypto" "^9.0.1" + "@polkadot/util-crypto" "^10.2.1" "@acala-network/sdk-core@4.1.8-9": version "4.1.8-9" @@ -1536,7 +1536,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.14.6", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6": +"@babel/runtime@^7.14.6", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.1", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== @@ -1564,13 +1564,6 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.20.1": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" - integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg== - dependencies: - regenerator-runtime "^0.13.10" - "@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" @@ -2549,10 +2542,10 @@ resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== -"@interlay/bridge@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@interlay/bridge/-/bridge-0.2.3.tgz#60e2329a036ef328d82d11f098b9cf2170ede4cb" - integrity sha512-zS8b4uGU7pqsihQR5BH3cNg4tEQUSY0YOVkjBC34p9WRAvE0NsllwEZe26eVjliHIPYOPD7LtiqyU4eHogogag== +"@interlay/bridge@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@interlay/bridge/-/bridge-0.2.4.tgz#83f446575d1b66cac7601bc4b771c3b19b9137b5" + integrity sha512-XYgLhd4anvoaLL9C+Su/BDATd0K6rQipZXjQW3wuqTYyy+Pr7ItNGu4FbSGLqid1osn7b7No4sXQ5WwFJsZSQA== dependencies: "@acala-network/api" "4.1.8-9" "@acala-network/sdk" "4.1.8-9" @@ -3026,31 +3019,11 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@noble/hashes@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.0.0.tgz#d5e38bfbdaba174805a4e649f13be9a9ed3351ae" - integrity sha512-DZVbtY62kc3kkBtMHqwCOfXrT/hnoORy5BJ4+HU1IR59X0KWAOqsfzQPcUl/lQLlG7qXbe/fZ3r/emxtAl+sqg== - -"@noble/hashes@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" - integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== - "@noble/hashes@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== -"@noble/secp256k1@1.5.5": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.5.5.tgz#315ab5745509d1a8c8e90d0bdf59823ccf9bcfc3" - integrity sha512-sZ1W6gQzYnu45wPrWx8D3kwI2/U29VYTx9OjbDAd7jwRItJ0cSTMPRL/C8AWZFn9kWFLQGqEXVEE86w4Z8LpIQ== - -"@noble/secp256k1@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.0.tgz#602afbbfcfb7e169210469b697365ef740d7e930" - integrity sha512-DWSsg8zMHOYMYBqIQi96BQuthZrp98LCeMNcUOaffCIVYQ5yxDbNikLF+H7jEnmNNmXbtVic46iCuVWzar+MgA== - "@noble/secp256k1@1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -3324,33 +3297,7 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@polkadot/api-augment@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-7.15.1.tgz#120b766feeaa96996f1c6717a5261c2e0845c1e0" - integrity sha512-7csQLS6zuYuGq7W1EkTBz1ZmxyRvx/Qpz7E7zPSwxmY8Whb7Yn2effU9XF0eCcRpyfSW8LodF8wMmLxGYs1OaQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/api-base" "7.15.1" - "@polkadot/rpc-augment" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-augment" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/util" "^8.7.1" - -"@polkadot/api-augment@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-8.14.1.tgz#f44a2e1952cb158bce55db687be9e3ac7113c87e" - integrity sha512-65GMlgVnZd08Ifh8uAj+p/+MlXxvsAfBcCHjQhOmbCE0dki+rzTPUR31LsWyDKtuw+nUBj0iZN4PelO+wU4r0g== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/api-base" "8.14.1" - "@polkadot/rpc-augment" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-augment" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/util" "^10.1.1" - -"@polkadot/api-augment@9.14.2": +"@polkadot/api-augment@9.10.3", "@polkadot/api-augment@9.14.2", "@polkadot/api-augment@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-9.14.2.tgz#2c49cdcfdf7057523db1dc8d7b0801391a8a2e69" integrity sha512-19MmW8AHEcLkdcUIo3LLk0eCQgREWqNSxkUyOeWn7UiNMY1AhDOOwMStUBNCvrIDK6VL6GGc1sY7rkPCLMuKSw== @@ -3363,42 +3310,7 @@ "@polkadot/types-codec" "9.14.2" "@polkadot/util" "^10.4.2" -"@polkadot/api-augment@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-9.9.1.tgz#5615ed8117a385d7ade3609fb51ea6119b79b8ef" - integrity sha512-0HS6Kit9ZiO2iQU/aS/jpOjXl9rFcwW6FdUs1eSXvWjvAFpoxwCMG8bv8wVjNZcCUuA2w5U0+2B+Xa612QEQQg== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/api-base" "9.9.1" - "@polkadot/rpc-augment" "9.9.1" - "@polkadot/types" "9.9.1" - "@polkadot/types-augment" "9.9.1" - "@polkadot/types-codec" "9.9.1" - "@polkadot/util" "^10.1.13" - -"@polkadot/api-base@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-7.15.1.tgz#7567595be68431cc4085c48b18ba66933ff7b4d9" - integrity sha512-UlhLdljJPDwGpm5FxOjvJNFTxXMRFaMuVNx6EklbuetbBEJ/Amihhtj0EJRodxQwtZ4ZtPKYKt+g+Dn7OJJh4g== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/rpc-core" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/util" "^8.7.1" - rxjs "^7.5.5" - -"@polkadot/api-base@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-8.14.1.tgz#a9380b11b74f2bc60dbf62b562b78c779e1d5b24" - integrity sha512-EXFhNXIfpirf18IsqcG2pGQW1/Xn+bfjqVYQMMJ4ZONtYH4baZZlXk7SoXCCHonN2x1ixs4DOcRx5oVxjabdIQ== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/rpc-core" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/util" "^10.1.1" - rxjs "^7.5.6" - -"@polkadot/api-base@9.14.2": +"@polkadot/api-base@9.14.2", "@polkadot/api-base@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-9.14.2.tgz#605b44e3692a125bd8d97eed9cea8af9d0c454e2" integrity sha512-ky9fmzG1Tnrjr/SBZ0aBB21l0TFr+CIyQenQczoUyVgiuxVaI/2Bp6R2SFrHhG28P+PW2/RcYhn2oIAR2Z2fZQ== @@ -3409,50 +3321,21 @@ "@polkadot/util" "^10.4.2" rxjs "^7.8.0" -"@polkadot/api-base@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-9.9.1.tgz#716143c3a9849570a499a7b44d82fd2533f141de" - integrity sha512-uJDLi+nHQ08QZ+p1ldzwMeNjCyIkpR1DOzvKV3M3bLepglF8r7V/7W5dXk+qlClMqgB92RgKwo4R6EPRgr5BcA== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/rpc-core" "9.9.1" - "@polkadot/types" "9.9.1" - "@polkadot/util" "^10.1.13" - rxjs "^7.5.7" - -"@polkadot/api-derive@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-7.15.1.tgz#450542bb7d848013225d6c8480648340e5ee6a61" - integrity sha512-CsOQppksQBaa34L1fWRzmfQQpoEBwfH0yTTQxgj3h7rFYGVPxEKGeFjo1+IgI2vXXvOO73Z8E4H/MnbxvKrs1Q== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/api" "7.15.1" - "@polkadot/api-augment" "7.15.1" - "@polkadot/api-base" "7.15.1" - "@polkadot/rpc-core" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/util" "^8.7.1" - "@polkadot/util-crypto" "^8.7.1" - rxjs "^7.5.5" - -"@polkadot/api-derive@8.14.1", "@polkadot/api-derive@^8.5.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-8.14.1.tgz#9079ad58f66e6a2d45d57947e3d8a40135eba9b9" - integrity sha512-eWG1MrQhHMUjt9gDHN9/9/ZMATu1MolqcalPFhNoGtdON3+I0J3ntjQ4y5X7+p2OGwQplpYRKqbK4k7tKzu8tA== +"@polkadot/api-contract@^9.14.2": + version "9.14.2" + resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-9.14.2.tgz#42ca46eecd6cef64b6c453b452bdb5d22a29b6a3" + integrity sha512-gAAHEh+tOIKuAJWxbAuB8Imo+Z8s0FHdICN6/q4JOxBhONJNA9beHB4wmqWSKvYqYmWrJvtv3HensLaITzAcrQ== dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/api" "8.14.1" - "@polkadot/api-augment" "8.14.1" - "@polkadot/api-base" "8.14.1" - "@polkadot/rpc-core" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/util" "^10.1.1" - "@polkadot/util-crypto" "^10.1.1" - rxjs "^7.5.6" + "@babel/runtime" "^7.20.13" + "@polkadot/api" "9.14.2" + "@polkadot/types" "9.14.2" + "@polkadot/types-codec" "9.14.2" + "@polkadot/types-create" "9.14.2" + "@polkadot/util" "^10.4.2" + "@polkadot/util-crypto" "^10.4.2" + rxjs "^7.8.0" -"@polkadot/api-derive@9.14.2", "@polkadot/api-derive@^9.7.1", "@polkadot/api-derive@^9.9.1": +"@polkadot/api-derive@9.10.3", "@polkadot/api-derive@9.14.2", "@polkadot/api-derive@^8.5.1", "@polkadot/api-derive@^9.14.2", "@polkadot/api-derive@^9.7.1": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-9.14.2.tgz#e8fcd4ee3f2b80b9fe34d4dec96169c3bdb4214d" integrity sha512-yw9OXucmeggmFqBTMgza0uZwhNjPxS7MaT7lSCUIRKckl1GejdV+qMhL3XFxPFeYzXwzFpdPG11zWf+qJlalqw== @@ -3468,53 +3351,7 @@ "@polkadot/util-crypto" "^10.4.2" rxjs "^7.8.0" -"@polkadot/api@7.15.1", "@polkadot/api@^7.2.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-7.15.1.tgz#24eaeaa8ffbc6f30ff3d9846a816a18a688ceb8b" - integrity sha512-z0z6+k8+R9ixRMWzfsYrNDnqSV5zHKmyhTCL0I7+1I081V18MJTCFUKubrh0t1gD0/FCt3U9Ibvr4IbtukYLrQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/api-augment" "7.15.1" - "@polkadot/api-base" "7.15.1" - "@polkadot/api-derive" "7.15.1" - "@polkadot/keyring" "^8.7.1" - "@polkadot/rpc-augment" "7.15.1" - "@polkadot/rpc-core" "7.15.1" - "@polkadot/rpc-provider" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-augment" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/types-create" "7.15.1" - "@polkadot/types-known" "7.15.1" - "@polkadot/util" "^8.7.1" - "@polkadot/util-crypto" "^8.7.1" - eventemitter3 "^4.0.7" - rxjs "^7.5.5" - -"@polkadot/api@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-8.14.1.tgz#e2f543700db84f89e873c4e1f8eb78d9e648797e" - integrity sha512-jg26eIKFYqVfDBTAopHL3aDaNw9j6TdUkXuvYJOnynpecU4xwbTVKcOtSOjJ2eRX4MgMQ4zlyMHJx3iKw0uUTA== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/api-augment" "8.14.1" - "@polkadot/api-base" "8.14.1" - "@polkadot/api-derive" "8.14.1" - "@polkadot/keyring" "^10.1.1" - "@polkadot/rpc-augment" "8.14.1" - "@polkadot/rpc-core" "8.14.1" - "@polkadot/rpc-provider" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-augment" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/types-create" "8.14.1" - "@polkadot/types-known" "8.14.1" - "@polkadot/util" "^10.1.1" - "@polkadot/util-crypto" "^10.1.1" - eventemitter3 "^4.0.7" - rxjs "^7.5.6" - -"@polkadot/api@9.14.2", "@polkadot/api@^9.11.1", "@polkadot/api@^9.4.2", "@polkadot/api@^9.7.1", "@polkadot/api@^9.8.1", "@polkadot/api@^9.9.1", "@polkadot/api@latest": +"@polkadot/api@9.10.3", "@polkadot/api@9.14.2", "@polkadot/api@^7.2.1", "@polkadot/api@^9.11.1", "@polkadot/api@^9.14.2", "@polkadot/api@^9.4.2", "@polkadot/api@^9.7.1", "@polkadot/api@^9.8.1", "@polkadot/api@^9.9.1", "@polkadot/api@latest": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-9.14.2.tgz#d5cee02236654c6063d7c4b70c78c290db5aba8d" integrity sha512-R3eYFj2JgY1zRb+OCYQxNlJXCs2FA+AU4uIEiVcXnVLmR3M55tkRNEwYAZmiFxx0pQmegGgPMc33q7TWGdw24A== @@ -3602,7 +3439,7 @@ "@polkadot/util-crypto" "^9.4.1" "@polkadot/x-global" "^9.4.1" -"@polkadot/keyring@^10.1.1", "@polkadot/keyring@^10.1.13", "@polkadot/keyring@^10.1.6", "@polkadot/keyring@^10.4.2": +"@polkadot/keyring@^10.1.6", "@polkadot/keyring@^10.2.1", "@polkadot/keyring@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-10.4.2.tgz#793377fdb9076df0af771df11388faa6be03c70d" integrity sha512-7iHhJuXaHrRTG6cJDbZE9G+c1ts1dujp0qbO4RfAPmT7YUvphHvAtCKueN9UKPz5+TYDL+rP/jDEaSKU8jl/qQ== @@ -3629,7 +3466,7 @@ "@polkadot/util" "7.9.2" "@polkadot/util-crypto" "7.9.2" -"@polkadot/keyring@^8.2.2", "@polkadot/keyring@^8.7.1": +"@polkadot/keyring@^8.2.2": version "8.7.1" resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-8.7.1.tgz#07cf6d6ee351dcf70fbf965b1d6d96c5025ae1b8" integrity sha512-t6ZgQVC+nQT7XwbWtEhkDpiAzxKVJw8Xd/gWdww6xIrawHu7jo3SGB4QNdPgkf8TvDHYAAJiupzVQYAlOIq3GA== @@ -3638,18 +3475,7 @@ "@polkadot/util" "8.7.1" "@polkadot/util-crypto" "8.7.1" -"@polkadot/metadata@4.17.1": - version "4.17.1" - resolved "https://registry.yarnpkg.com/@polkadot/metadata/-/metadata-4.17.1.tgz#4da9ee5b2b816493910abfd302a50b58141ceca2" - integrity sha512-219isiCWVfbu5JxZnOPj+cV4T+S0XHS4+Jal3t3xz9y4nbgr+25Pa4KInEsJPx0u8EZAxMeiUCX3vd5U7oe72g== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/types" "4.17.1" - "@polkadot/types-known" "4.17.1" - "@polkadot/util" "^6.11.1" - "@polkadot/util-crypto" "^6.11.1" - -"@polkadot/networks@10.4.2", "@polkadot/networks@^10.1.1", "@polkadot/networks@^10.1.11", "@polkadot/networks@^10.1.6", "@polkadot/networks@^10.4.2": +"@polkadot/networks@10.4.2", "@polkadot/networks@^10.1.11", "@polkadot/networks@^10.1.6", "@polkadot/networks@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-10.4.2.tgz#d7878c6aad8173c800a21140bfe5459261724456" integrity sha512-FAh/znrEvWBiA/LbcT5GXHsCFUl//y9KqxLghSr/CreAmAergiJNT0MVUezC7Y36nkATgmsr4ylFwIxhVtuuCw== @@ -3658,61 +3484,7 @@ "@polkadot/util" "10.4.2" "@substrate/ss58-registry" "^1.38.0" -"@polkadot/networks@6.11.1", "@polkadot/networks@^6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-6.11.1.tgz#8fd189593f6ee4f8bf64378d0aaae09e39a37d35" - integrity sha512-0C6Ha2kvr42se3Gevx6UhHzv3KnPHML0N73Amjwvdr4y0HLZ1Nfw+vcm5yqpz5gpiehqz97XqFrsPRauYdcksQ== - dependencies: - "@babel/runtime" "^7.14.6" - -"@polkadot/networks@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-7.9.2.tgz#03e3f3ac6bdea177517436537826055df60bcb9a" - integrity sha512-4obI1RdW5/7TFwbwKA9oqw8aggVZ65JAUvIFMd2YmMC2T4+NiZLnok0WhRkhZkUnqjLIHXYNwq7Ho1i39dte0g== - dependencies: - "@babel/runtime" "^7.16.3" - -"@polkadot/networks@8.7.1", "@polkadot/networks@^8.1.2", "@polkadot/networks@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-8.7.1.tgz#26c2ec6158c985bb77c510d98a3ab1c7e049f89c" - integrity sha512-8xAmhDW0ry5EKcEjp6VTuwoTm0DdDo/zHsmx88P6sVL87gupuFsL+B6TrsYLl8GcaqxujwrOlKB+CKTUg7qFKg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/util" "8.7.1" - "@substrate/ss58-registry" "^1.17.0" - -"@polkadot/networks@9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-9.7.2.tgz#9064f0578b293245bee263367d6f1674eb06e506" - integrity sha512-oMAdF8Y9CLBI0EUZBcycHcvbQQdbkJHevPJ/lwnZXJTaueXuav/Xm2yiFj5J3V8meIjLocURlMawgsAVItXOBQ== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/util" "9.7.2" - "@substrate/ss58-registry" "^1.23.0" - -"@polkadot/rpc-augment@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-7.15.1.tgz#391a42a9c3e553335a2a544598a717b47654ad6e" - integrity sha512-sK0+mphN7nGz/eNPsshVi0qd0+N0Pqxuebwc1YkUGP0f9EkDxzSGp6UjGcSwWVaAtk9WZZ1MpK1Jwb/2GrKV7Q== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/rpc-core" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/util" "^8.7.1" - -"@polkadot/rpc-augment@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-8.14.1.tgz#1b55c9e66a8aaafb76e6ed6a37b0682a4331b2a7" - integrity sha512-0dIsNVIMeCp0kV7+Obz0Odt6K32Ka2ygwhiV5jhhJthy8GJBPo94mKDed5gzln3Dgl2LEdJJt1h/pgCx4a2i4A== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/rpc-core" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/util" "^10.1.1" - -"@polkadot/rpc-augment@9.14.2": +"@polkadot/rpc-augment@9.14.2", "@polkadot/rpc-augment@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-9.14.2.tgz#eb70d5511463dab8d995faeb77d4edfe4952fe26" integrity sha512-mOubRm3qbKZTbP9H01XRrfTk7k5it9WyzaWAg72DJBQBYdgPUUkGSgpPD/Srkk5/5GAQTWVWL1I2UIBKJ4TJjQ== @@ -3723,42 +3495,7 @@ "@polkadot/types-codec" "9.14.2" "@polkadot/util" "^10.4.2" -"@polkadot/rpc-augment@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-9.9.1.tgz#84f71a818bfcc5c33ff87252ffa263344f69255b" - integrity sha512-t3gTendxM9KD9Sg+hT7Wn72Xdusl25EsXcdOjFqQWUtFL8xjYcFngrTTifG90e+ciFIk1DWps2+zc6lbDwBfeA== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/rpc-core" "9.9.1" - "@polkadot/types" "9.9.1" - "@polkadot/types-codec" "9.9.1" - "@polkadot/util" "^10.1.13" - -"@polkadot/rpc-core@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-7.15.1.tgz#47855cf05bd2f8dbf87d9f1f77343114e61c664a" - integrity sha512-4Sb0e0PWmarCOizzxQAE1NQSr5z0n+hdkrq3+aPohGu9Rh4PodG+OWeIBy7Ov/3GgdhNQyBLG+RiVtliXecM3g== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/rpc-augment" "7.15.1" - "@polkadot/rpc-provider" "7.15.1" - "@polkadot/types" "7.15.1" - "@polkadot/util" "^8.7.1" - rxjs "^7.5.5" - -"@polkadot/rpc-core@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-8.14.1.tgz#0b9a408a03ecde820d0d55287efbfb4cb95b537a" - integrity sha512-deQ8Ob59ao/1fZQdaVtFjYR/HCBdxSYvQGt7/alBu1Uig9Sahx9oKcMkU5rWY36XqGZYos4zLay98W2hDlf+6Q== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/rpc-augment" "8.14.1" - "@polkadot/rpc-provider" "8.14.1" - "@polkadot/types" "8.14.1" - "@polkadot/util" "^10.1.1" - rxjs "^7.5.6" - -"@polkadot/rpc-core@9.14.2", "@polkadot/rpc-core@^9.9.1": +"@polkadot/rpc-core@9.14.2", "@polkadot/rpc-core@^9.14.2", "@polkadot/rpc-core@^9.9.1": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-9.14.2.tgz#26d4f00ac7abbf880f8280e9b96235880d35794b" integrity sha512-krA/mtQ5t9nUQEsEVC1sjkttLuzN6z6gyJxK2IlpMS3S5ncy/R6w4FOpy+Q0H18Dn83JBo0p7ZtY7Y6XkK48Kw== @@ -3770,57 +3507,7 @@ "@polkadot/util" "^10.4.2" rxjs "^7.8.0" -"@polkadot/rpc-core@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-9.9.1.tgz#f66318fe54f66652287dab9c4d611b71863b266a" - integrity sha512-ij1OxDfbPpdZ9+aN8oicZrysIfUjC7INBhDwwoZ4R/4jhqJvIV1fisgj6XOdHGlZGl+vQBnObOw0nEOU7apdQg== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/rpc-augment" "9.9.1" - "@polkadot/rpc-provider" "9.9.1" - "@polkadot/types" "9.9.1" - "@polkadot/util" "^10.1.13" - rxjs "^7.5.7" - -"@polkadot/rpc-provider@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-7.15.1.tgz#a213de907a6f4f480c3c819aa95e4e60d4247f84" - integrity sha512-n0RWfSaD/r90JXeJkKry1aGZwJeBUUiMpXUQ9Uvp6DYBbYEDs0fKtWLpdT3PdFrMbe5y3kwQmNLxwe6iF4+mzg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/keyring" "^8.7.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-support" "7.15.1" - "@polkadot/util" "^8.7.1" - "@polkadot/util-crypto" "^8.7.1" - "@polkadot/x-fetch" "^8.7.1" - "@polkadot/x-global" "^8.7.1" - "@polkadot/x-ws" "^8.7.1" - "@substrate/connect" "0.7.0-alpha.0" - eventemitter3 "^4.0.7" - mock-socket "^9.1.2" - nock "^13.2.4" - -"@polkadot/rpc-provider@8.14.1", "@polkadot/rpc-provider@^8.7.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-8.14.1.tgz#d318a3cb3c71410cea6a9c2c609d39e3fc62d8bb" - integrity sha512-pAUSHZiSWLhBSYf4LmLc8iCaeqTu7Ajn8AzyqxvZDHGnIrzV5M7eTjpNDP84qno6jWRHKQ/IILr62hausEmS5w== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/keyring" "^10.1.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-support" "8.14.1" - "@polkadot/util" "^10.1.1" - "@polkadot/util-crypto" "^10.1.1" - "@polkadot/x-fetch" "^10.1.1" - "@polkadot/x-global" "^10.1.1" - "@polkadot/x-ws" "^10.1.1" - "@substrate/connect" "0.7.9" - eventemitter3 "^4.0.7" - mock-socket "^9.1.5" - nock "^13.2.9" - -"@polkadot/rpc-provider@9.14.2": +"@polkadot/rpc-provider@9.14.2", "@polkadot/rpc-provider@^8.7.1", "@polkadot/rpc-provider@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-9.14.2.tgz#0dea667f3a03bf530f202cba5cd360df19b32e30" integrity sha512-YTSywjD5PF01V47Ru5tln2LlpUwJiSOdz6rlJXPpMaY53hUp7+xMU01FVAQ1bllSBNisSD1Msv/mYHq84Oai2g== @@ -3840,46 +3527,7 @@ optionalDependencies: "@substrate/connect" "0.7.19" -"@polkadot/rpc-provider@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-9.9.1.tgz#1dcddb127aca53fcf1f269bbf7cac68982c67854" - integrity sha512-YyIwYDAgeEAAjvsH/v5v6sFkhkoaER98rPIcfP+81sGcxpjBCArg4feDtzTPQMsnUcbj3708ppJicu6ECc1xFg== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/keyring" "^10.1.13" - "@polkadot/types" "9.9.1" - "@polkadot/types-support" "9.9.1" - "@polkadot/util" "^10.1.13" - "@polkadot/util-crypto" "^10.1.13" - "@polkadot/x-fetch" "^10.1.13" - "@polkadot/x-global" "^10.1.13" - "@polkadot/x-ws" "^10.1.13" - "@substrate/connect" "0.7.17" - eventemitter3 "^4.0.7" - mock-socket "^9.1.5" - nock "^13.2.9" - -"@polkadot/types-augment@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-7.15.1.tgz#437047f961b8d29e5ffd4fd59cd35f0e6374750b" - integrity sha512-aqm7xT/66TCna0I2utpIekoquKo0K5pnkA/7WDzZ6gyD8he2h0IXfe8xWjVmuyhjxrT/C/7X1aUF2Z0xlOCwzQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/types" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/util" "^8.7.1" - -"@polkadot/types-augment@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-8.14.1.tgz#6868d7f1321f6cd2b5028374bc496e5174fcf15e" - integrity sha512-Xa4TUFqyZT+IJ6pBSwDjWcF42u/E34OyC+gbs5Z2vWQ4EzSDkq4xNoUKjJlEEgTemsD9lhPOIc4jvqTCefwxEw== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/types" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/util" "^10.1.1" - -"@polkadot/types-augment@9.14.2", "@polkadot/types-augment@^9.11.1": +"@polkadot/types-augment@9.14.2", "@polkadot/types-augment@^9.11.1", "@polkadot/types-augment@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-9.14.2.tgz#1a478e18e713b04038f3e171287ee5abe908f0aa" integrity sha512-WO9d7RJufUeY3iFgt2Wz762kOu1tjEiGBR5TT4AHtpEchVHUeosVTrN9eycC+BhleqYu52CocKz6u3qCT/jKLg== @@ -3889,34 +3537,7 @@ "@polkadot/types-codec" "9.14.2" "@polkadot/util" "^10.4.2" -"@polkadot/types-augment@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-9.9.1.tgz#77e7d9df2a3bd69236c7fa8c02b6574b1e232d84" - integrity sha512-h4DhtVPbe7/6Mdwickqih3ltvEV9y08a8LVvjxVVaGw1gRcoQpcMLkvsyWh5caYBPCKuJvXV40p4PnvO/HtW2A== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/types" "9.9.1" - "@polkadot/types-codec" "9.9.1" - "@polkadot/util" "^10.1.13" - -"@polkadot/types-codec@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-7.15.1.tgz#c0155867efd3ae35e15fea6a8aab49c2c63988fa" - integrity sha512-nI11dT7FGaeDd/fKPD8iJRFGhosOJoyjhZ0gLFFDlKCaD3AcGBRTTY8HFJpP/5QXXhZzfZsD93fVKrosnegU0Q== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/util" "^8.7.1" - -"@polkadot/types-codec@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-8.14.1.tgz#b5342fa38e17eb1183434981e23334d5bd1ecd2e" - integrity sha512-y6YDN4HwvEgSWlgrEV04QBBxDxES1cTuUQFzZJzOTuZCWpA371Mdj3M9wYxGXMnj0wa+rCQGECHPZZaNxBMiKg== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/util" "^10.1.1" - "@polkadot/x-bigint" "^10.1.1" - -"@polkadot/types-codec@9.14.2": +"@polkadot/types-codec@9.14.2", "@polkadot/types-codec@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-9.14.2.tgz#d625c80495d7a68237b3d5c0a60ff10d206131fa" integrity sha512-AJ4XF7W1no4PENLBRU955V6gDxJw0h++EN3YoDgThozZ0sj3OxyFupKgNBZcZb2V23H8JxQozzIad8k+nJbO1w== @@ -3925,34 +3546,7 @@ "@polkadot/util" "^10.4.2" "@polkadot/x-bigint" "^10.4.2" -"@polkadot/types-codec@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-9.9.1.tgz#4a5f789bedb29f27af612afe789d91e78d6bd136" - integrity sha512-vBzInneVp2ClDD/bmrf9HUp9La0udBJnhvyqwdLA2IKQBjIYOxVtuC62D4dg1Svp34NH4+b/nAtWlOvflSjOQQ== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/util" "^10.1.13" - "@polkadot/x-bigint" "^10.1.13" - -"@polkadot/types-create@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-7.15.1.tgz#ec4cafa314a82a25a109f0f52207e9169fc9b003" - integrity sha512-+HiaHn7XOwP0kv/rVdORlVkNuMoxuvt+jd67A/CeEreJiXqRLu+S61Mdk7wi6719PTaOal1hTDFfyGrtUd8FSQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/types-codec" "7.15.1" - "@polkadot/util" "^8.7.1" - -"@polkadot/types-create@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-8.14.1.tgz#46af719c33581576eed03658baf3aaa932b3d89c" - integrity sha512-fb9yyblj5AYAPzeCIq0kYSfzDxRDi/0ud9gN2UzB3H7M/O4n2mPC1vD4UOLF+B7l9QzCrt4e+k+/riGp7GfvyA== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/types-codec" "8.14.1" - "@polkadot/util" "^10.1.1" - -"@polkadot/types-create@9.14.2": +"@polkadot/types-create@9.14.2", "@polkadot/types-create@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-9.14.2.tgz#aec515a2d3bc7e7b7802095cdd35ece48dc442bc" integrity sha512-nSnKpBierlmGBQT8r6/SHf6uamBIzk4WmdMsAsR4uJKJF1PtbIqx2W5PY91xWSiMSNMzjkbCppHkwaDAMwLGaw== @@ -3961,60 +3555,7 @@ "@polkadot/types-codec" "9.14.2" "@polkadot/util" "^10.4.2" -"@polkadot/types-create@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-9.9.1.tgz#4a9c6596a2adb879e878a6fba6f1bb967567a637" - integrity sha512-fzHTdWdXPbJxAYNP2nFzM9B1Nom7wiIFalltIj3jLQYF8uCgPuMF4/nLDi5uEg5YpCBCTagqyoVUuEd4riDS/Q== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/types-codec" "9.9.1" - "@polkadot/util" "^10.1.13" - -"@polkadot/types-known@4.17.1": - version "4.17.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-4.17.1.tgz#71c18dda4967a13ec34fbbf0c4ef264e882c2688" - integrity sha512-YkOwGrO+k9aVrBR8FgYHnfJKhOfpdgC5ZRYNL/xJ9oa7lBYqPts9ENAxeBmJS/5IGeDF9f32MNyrCP2umeCXWg== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/networks" "^6.11.1" - "@polkadot/types" "4.17.1" - "@polkadot/util" "^6.11.1" - -"@polkadot/types-known@6.12.1": - version "6.12.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-6.12.1.tgz#2dd3ca4e4aa20b86ef182eb75672690f8c14a84e" - integrity sha512-Z8bHpPQy+mqUm0uR1tai6ra0bQIoPmgRcGFYUM+rJtW1kx/6kZLh10HAICjLpPeA1cwLRzaxHRDqH5MCU6OgXw== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/networks" "^8.1.2" - "@polkadot/types" "6.12.1" - "@polkadot/util" "^8.1.2" - -"@polkadot/types-known@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-7.15.1.tgz#71dbf0835a48cdc97d0f50b0000298687e29818d" - integrity sha512-LMcNP0CxT84DqAKV62/qDeeIVIJCR5yzE9b+9AsYhyfhE4apwxjrThqZA7K0CF56bOdQJSexAerYB/jwk2IijA== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/networks" "^8.7.1" - "@polkadot/types" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/types-create" "7.15.1" - "@polkadot/util" "^8.7.1" - -"@polkadot/types-known@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-8.14.1.tgz#86103e2b58da15cf74d2babc0cba544a2b12702a" - integrity sha512-GP7gRo9nmitykkrRnoLF61Qm19UFdTwMsOnJkdm7AOeWDmZGxutacgO6k1tBsHr38hsiCCGsB/JiseUgywvGIw== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/networks" "^10.1.1" - "@polkadot/types" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/types-create" "8.14.1" - "@polkadot/util" "^10.1.1" - -"@polkadot/types-known@9.14.2": +"@polkadot/types-known@9.14.2", "@polkadot/types-known@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-9.14.2.tgz#17fe5034a5b907bd006093a687f112b07edadf10" integrity sha512-iM8WOCgguzJ3TLMqlm4K1gKQEwWm2zxEKT1HZZ1irs/lAbBk9MquDWDvebryiw3XsLB8xgrp3RTIBn2Q4FjB2A== @@ -4026,23 +3567,7 @@ "@polkadot/types-create" "9.14.2" "@polkadot/util" "^10.4.2" -"@polkadot/types-support@7.15.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-7.15.1.tgz#9c274759647dd89d46ea9cf74d593bcedcd85527" - integrity sha512-FIK251ffVo+NaUXLlaJeB5OvT7idDd3uxaoBM6IwsS87rzt2CcWMyCbu0uX89AHZUhSviVx7xaBxfkGEqMePWA== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/util" "^8.7.1" - -"@polkadot/types-support@8.14.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-8.14.1.tgz#a227266aa296847c43f6d51426c22ce68357bd2c" - integrity sha512-XqR4qq6pCZyNBuFVod8nFSNUmLssrjoU9bOIn4Ua2cqNlI9xsuKaI1X5ySEn/oWOtKQ2L5hbCm9vkXrEtXBl1w== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/util" "^10.1.1" - -"@polkadot/types-support@9.14.2": +"@polkadot/types-support@9.14.2", "@polkadot/types-support@^9.14.2": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-9.14.2.tgz#d25e8d4e5ec3deef914cb55fc8bc5448431ddd18" integrity sha512-VWCOPgXDK3XtXT7wMLyIWeNDZxUbNcw/8Pn6n6vMogs7o/n4h6WGbGMeTIQhPWyn831/RmkVs5+2DUC+2LlOhw== @@ -4050,65 +3575,7 @@ "@babel/runtime" "^7.20.13" "@polkadot/util" "^10.4.2" -"@polkadot/types-support@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-9.9.1.tgz#d93ddf1d68de39ff7241d7962cf50b9f7fe6d0f6" - integrity sha512-PGu80mMvyr+rD6pi8Z/r9l650cadpW4X+pWt4tJnKYAbtiaE9mQJGFwq+HgY3vExzRDhaXNOUDg9d1ry5XUvJQ== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/util" "^10.1.13" - -"@polkadot/types@4.17.1", "@polkadot/types@^4.13.1": - version "4.17.1" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-4.17.1.tgz#41d43621d53820ee930ba4036bfa8b16cf98ca6f" - integrity sha512-rjW4OFdwvFekzN3ATLibC2JPSd8AWt5YepJhmuCPdwH26r3zB8bEC6dM7YQExLVUmygVPvgXk5ffHI6RAdXBMg== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/metadata" "4.17.1" - "@polkadot/util" "^6.11.1" - "@polkadot/util-crypto" "^6.11.1" - "@polkadot/x-rxjs" "^6.11.1" - -"@polkadot/types@6.12.1", "@polkadot/types@^6.0.5": - version "6.12.1" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-6.12.1.tgz#e5d6dff997740c3da947fa67abe2e1ec144c4757" - integrity sha512-O37cAGUL0xiXTuO3ySweVh0OuFUD6asrd0TfuzGsEp3jAISWdElEHV5QDiftWq8J9Vf8BMgTcP2QLFbmSusxqA== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/types-known" "6.12.1" - "@polkadot/util" "^8.1.2" - "@polkadot/util-crypto" "^8.1.2" - rxjs "^7.4.0" - -"@polkadot/types@7.15.1", "@polkadot/types@^7.2.1": - version "7.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-7.15.1.tgz#fb78886f4437fbc472e01019846fb1f229d2a177" - integrity sha512-KawZVS+eLR1D6O7c/P5cSUwr6biM9Qd2KwKtJIO8l1Mrxp7r+y2tQnXSSXVAd6XPdb3wVMhnIID+NW3W99TAnQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/keyring" "^8.7.1" - "@polkadot/types-augment" "7.15.1" - "@polkadot/types-codec" "7.15.1" - "@polkadot/types-create" "7.15.1" - "@polkadot/util" "^8.7.1" - "@polkadot/util-crypto" "^8.7.1" - rxjs "^7.5.5" - -"@polkadot/types@8.14.1", "@polkadot/types@^8.7.1": - version "8.14.1" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-8.14.1.tgz#a0149680d06b02bc23b842865b84840a5bc8b870" - integrity sha512-Xza16ejKrSd4XhTOlbfISyxZ2sRmbMAZk5pX7VEMHVZHqV98o+bJ2f9Kk7F8YJijkHHGosCLDestP9R5nLoOoA== - dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/keyring" "^10.1.1" - "@polkadot/types-augment" "8.14.1" - "@polkadot/types-codec" "8.14.1" - "@polkadot/types-create" "8.14.1" - "@polkadot/util" "^10.1.1" - "@polkadot/util-crypto" "^10.1.1" - rxjs "^7.5.6" - -"@polkadot/types@9.14.2", "@polkadot/types@^9.11.1", "@polkadot/types@^9.7.1", "@polkadot/types@^9.9.1": +"@polkadot/types@9.10.3", "@polkadot/types@9.14.2", "@polkadot/types@^4.13.1", "@polkadot/types@^6.0.5", "@polkadot/types@^7.2.1", "@polkadot/types@^8.7.1", "@polkadot/types@^9.11.1", "@polkadot/types@^9.14.2", "@polkadot/types@^9.7.1", "@polkadot/types@^9.9.1": version "9.14.2" resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-9.14.2.tgz#5105f41eb9e8ea29938188d21497cbf1753268b8" integrity sha512-hGLddTiJbvowhhUZJ3k+olmmBc1KAjWIQxujIUIYASih8FQ3/YJDKxaofGOzh0VygOKW3jxQBN2VZPofyDP9KQ== @@ -4122,20 +3589,6 @@ "@polkadot/util-crypto" "^10.4.2" rxjs "^7.8.0" -"@polkadot/types@9.9.1": - version "9.9.1" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-9.9.1.tgz#ef223eb82066303c807828d23668672a8153712e" - integrity sha512-WK0CPj0LZhb5ZSfhMvT5ZZv0nnqz9wQdRSehjqeuq7DD2TgTIPZL22zP4UjJPAJEyTtwyfcRn6+ZhL2JS5w0Jg== - dependencies: - "@babel/runtime" "^7.20.1" - "@polkadot/keyring" "^10.1.13" - "@polkadot/types-augment" "9.9.1" - "@polkadot/types-codec" "9.9.1" - "@polkadot/types-create" "9.9.1" - "@polkadot/util" "^10.1.13" - "@polkadot/util-crypto" "^10.1.13" - rxjs "^7.5.7" - "@polkadot/ui-keyring@^2.9.7": version "2.9.7" resolved "https://registry.yarnpkg.com/@polkadot/ui-keyring/-/ui-keyring-2.9.7.tgz#b79b056b4c26866b3e87569407bcc16b95894545" @@ -4161,7 +3614,7 @@ eventemitter3 "^4.0.7" store "^2.0.12" -"@polkadot/util-crypto@10.4.2", "@polkadot/util-crypto@^10.1.1", "@polkadot/util-crypto@^10.1.12", "@polkadot/util-crypto@^10.1.13", "@polkadot/util-crypto@^10.1.6", "@polkadot/util-crypto@^10.4.2": +"@polkadot/util-crypto@10.4.2", "@polkadot/util-crypto@6.11.1", "@polkadot/util-crypto@7.9.2", "@polkadot/util-crypto@8.7.1", "@polkadot/util-crypto@^10.1.12", "@polkadot/util-crypto@^10.1.6", "@polkadot/util-crypto@^10.2.1", "@polkadot/util-crypto@^10.2.4", "@polkadot/util-crypto@^10.4.2", "@polkadot/util-crypto@^9.4.1": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-10.4.2.tgz#871fb69c65768bd48c57bb5c1f76a85d979fb8b5" integrity sha512-RxZvF7C4+EF3fzQv8hZOLrYCBq5+wA+2LWv98nECkroChY3C2ZZvyWDqn8+aonNULt4dCVTWDZM0QIY6y4LUAQ== @@ -4178,85 +3631,7 @@ ed2curve "^0.3.0" tweetnacl "^1.0.3" -"@polkadot/util-crypto@6.11.1", "@polkadot/util-crypto@^6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-6.11.1.tgz#7a36acf5c8bf52541609ec0b0b2a69af295d652e" - integrity sha512-fWA1Nz17FxWJslweZS4l0Uo30WXb5mYV1KEACVzM+BSZAvG5eoiOAYX6VYZjyw6/7u53XKrWQlD83iPsg3KvZw== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/networks" "6.11.1" - "@polkadot/util" "6.11.1" - "@polkadot/wasm-crypto" "^4.0.2" - "@polkadot/x-randomvalues" "6.11.1" - base-x "^3.0.8" - base64-js "^1.5.1" - blakejs "^1.1.1" - bn.js "^4.11.9" - create-hash "^1.2.0" - elliptic "^6.5.4" - hash.js "^1.1.7" - js-sha3 "^0.8.0" - scryptsy "^2.1.0" - tweetnacl "^1.0.3" - xxhashjs "^0.2.2" - -"@polkadot/util-crypto@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-7.9.2.tgz#cdc336f92a6bc3d40c5a23734e1974fb777817f0" - integrity sha512-nNwqUwP44eCH9jKKcPie+IHLKkg9LMe6H7hXo91hy3AtoslnNrT51tP3uAm5yllhLvswJfnAgnlHq7ybCgqeFw== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/networks" "7.9.2" - "@polkadot/util" "7.9.2" - "@polkadot/wasm-crypto" "^4.4.1" - "@polkadot/x-randomvalues" "7.9.2" - blakejs "^1.1.1" - bn.js "^4.12.0" - create-hash "^1.2.0" - ed2curve "^0.3.0" - elliptic "^6.5.4" - hash.js "^1.1.7" - js-sha3 "^0.8.0" - micro-base "^0.9.0" - scryptsy "^2.1.0" - tweetnacl "^1.0.3" - xxhashjs "^0.2.2" - -"@polkadot/util-crypto@8.7.1", "@polkadot/util-crypto@^8.1.2", "@polkadot/util-crypto@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-8.7.1.tgz#f9fcca2895b5f160ce1c2faa0aa3054cc7aa4655" - integrity sha512-TaSuJ2aNrB5sYK7YXszkEv24nYJKRFqjF2OrggoMg6uYxUAECvTkldFnhtgeizMweRMxJIBu6bMHlSIutbWgjw== - dependencies: - "@babel/runtime" "^7.17.8" - "@noble/hashes" "1.0.0" - "@noble/secp256k1" "1.5.5" - "@polkadot/networks" "8.7.1" - "@polkadot/util" "8.7.1" - "@polkadot/wasm-crypto" "^5.1.1" - "@polkadot/x-bigint" "8.7.1" - "@polkadot/x-randomvalues" "8.7.1" - "@scure/base" "1.0.0" - ed2curve "^0.3.0" - tweetnacl "^1.0.3" - -"@polkadot/util-crypto@^9.0.1", "@polkadot/util-crypto@^9.4.1": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-9.7.2.tgz#0a097f4e197cd344d101ab748a740c2d99a4c5b9" - integrity sha512-tfz6mJtPwoNteivKCmR+QklC4mr1/hGZRsDJLWKaFhanDinYZ3V2pJM1EbCI6WONLuuzlTxsDXjAffWzzRqlPA== - dependencies: - "@babel/runtime" "^7.18.6" - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.6.0" - "@polkadot/networks" "9.7.2" - "@polkadot/util" "9.7.2" - "@polkadot/wasm-crypto" "^6.2.2" - "@polkadot/x-bigint" "9.7.2" - "@polkadot/x-randomvalues" "9.7.2" - "@scure/base" "1.1.1" - ed2curve "^0.3.0" - tweetnacl "^1.0.3" - -"@polkadot/util@10.4.2", "@polkadot/util@^10.1.1", "@polkadot/util@^10.1.11", "@polkadot/util@^10.1.12", "@polkadot/util@^10.1.13", "@polkadot/util@^10.1.6", "@polkadot/util@^10.4.2": +"@polkadot/util@10.4.2", "@polkadot/util@6.11.1", "@polkadot/util@7.9.2", "@polkadot/util@8.7.1", "@polkadot/util@^10.1.11", "@polkadot/util@^10.1.12", "@polkadot/util@^10.1.6", "@polkadot/util@^10.2.1", "@polkadot/util@^10.2.4", "@polkadot/util@^10.4.2", "@polkadot/util@^9.4.1": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-10.4.2.tgz#df41805cb27f46b2b4dad24c371fa2a68761baa1" integrity sha512-0r5MGICYiaCdWnx+7Axlpvzisy/bi1wZGXgCSw5+ZTyPTOqvsYRqM2X879yxvMsGfibxzWqNzaiVjToz1jvUaA== @@ -4269,60 +3644,6 @@ "@types/bn.js" "^5.1.1" bn.js "^5.2.1" -"@polkadot/util@6.11.1", "@polkadot/util@^6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-6.11.1.tgz#8950b038ba3e6ebfc0a7ff47feeb972e81b2626c" - integrity sha512-TEdCetr9rsdUfJZqQgX/vxLuV4XU8KMoKBMJdx+JuQ5EWemIdQkEtMBdL8k8udNGbgSNiYFA6rPppATeIxAScg== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/x-textdecoder" "6.11.1" - "@polkadot/x-textencoder" "6.11.1" - "@types/bn.js" "^4.11.6" - bn.js "^4.11.9" - camelcase "^5.3.1" - ip-regex "^4.3.0" - -"@polkadot/util@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-7.9.2.tgz#567ac659516d6b685ed7e796919901d92e5cbe6b" - integrity sha512-6ABY6ErgkCsM4C6+X+AJSY4pBGwbKlHZmUtHftaiTvbaj4XuA4nTo3GU28jw8wY0Jh2cJZJvt6/BJ5GVkm5tBA== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/x-textdecoder" "7.9.2" - "@polkadot/x-textencoder" "7.9.2" - "@types/bn.js" "^4.11.6" - bn.js "^4.12.0" - camelcase "^6.2.1" - ip-regex "^4.3.0" - -"@polkadot/util@8.7.1", "@polkadot/util@^8.1.2", "@polkadot/util@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-8.7.1.tgz#27fe93bf7b8345276f10cfe9c0380510cd4584f6" - integrity sha512-XjY1bTo7V6OvOCe4yn8H2vifeuBciCy0gq0k5P1tlGUQLI/Yt0hvDmxcA0FEPtqg8CL+rYRG7WXGPVNjkrNvyQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-bigint" "8.7.1" - "@polkadot/x-global" "8.7.1" - "@polkadot/x-textdecoder" "8.7.1" - "@polkadot/x-textencoder" "8.7.1" - "@types/bn.js" "^5.1.0" - bn.js "^5.2.0" - ip-regex "^4.3.0" - -"@polkadot/util@9.7.2", "@polkadot/util@^9.4.1": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-9.7.2.tgz#0f97fa92b273e6ce4b53fe869a957ac99342007d" - integrity sha512-ivTmA+KkPCq5i3O0Gk+dTds/hwdwlYCh89aKfeaG9ni3XHUbbuBgTqHneo648HqxwAwSAyiDiwE9EdXrzAdO4Q== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/x-bigint" "9.7.2" - "@polkadot/x-global" "9.7.2" - "@polkadot/x-textdecoder" "9.7.2" - "@polkadot/x-textencoder" "9.7.2" - "@types/bn.js" "^5.1.0" - bn.js "^5.2.1" - ip-regex "^4.3.0" - "@polkadot/wasm-bridge@6.4.1": version "6.4.1" resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-6.4.1.tgz#e97915dd67ba543ec3381299c2a5b9330686e27e" @@ -4337,20 +3658,6 @@ dependencies: "@babel/runtime" "^7.20.6" -"@polkadot/wasm-crypto-asmjs@^4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.6.1.tgz#4f4a5adcf8dce65666eaa0fb16b6ff7b0243aead" - integrity sha512-1oHQjz2oEO1kCIcQniOP+dZ9N2YXf2yCLHLsKaKSvfXiWaetVCaBNB8oIHIVYvuLnVc8qlMi66O6xc1UublHsw== - dependencies: - "@babel/runtime" "^7.17.2" - -"@polkadot/wasm-crypto-asmjs@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-5.1.1.tgz#6648e9c6f627501f61aef570e110022f2be1eff2" - integrity sha512-1WBwc2G3pZMKW1T01uXzKE30Sg22MXmF3RbbZiWWk3H2d/Er4jZQRpjumxO5YGWan+xOb7HQQdwnrUnrPgbDhg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/wasm-crypto-init@6.4.1": version "6.4.1" resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-6.4.1.tgz#4d9ab0030db52cf177bf707ef8e77aa4ca721668" @@ -4369,39 +3676,7 @@ "@babel/runtime" "^7.20.6" "@polkadot/wasm-util" "6.4.1" -"@polkadot/wasm-crypto-wasm@^4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.6.1.tgz#882d8199e216966c612f56a18e31f6aaae77e7eb" - integrity sha512-NI3JVwmLjrSYpSVuhu0yeQYSlsZrdpK41UC48sY3kyxXC71pi6OVePbtHS1K3xh3FFmDd9srSchExi3IwzKzMw== - dependencies: - "@babel/runtime" "^7.17.2" - -"@polkadot/wasm-crypto-wasm@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-5.1.1.tgz#dc371755a05fe93f87a2754a2bcf1ff42e4bb541" - integrity sha512-F9PZ30J2S8vUNl2oY7Myow5Xsx5z5uNVpnNlJwlmY8IXBvyucvyQ4HSdhJsrbs4W1BfFc0mHghxgp0FbBCnf/Q== - dependencies: - "@babel/runtime" "^7.17.8" - -"@polkadot/wasm-crypto@^4.0.2", "@polkadot/wasm-crypto@^4.4.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-4.6.1.tgz#12f8481e6f9021928435168beb0697d57ff573e9" - integrity sha512-2wEftBDxDG+TN8Ah6ogtvzjdZdcF0mAjU4UNNOfpmkBCxQYZOrAHB8HXhzo3noSsKkLX7PDX57NxvJ9OhoTAjw== - dependencies: - "@babel/runtime" "^7.17.2" - "@polkadot/wasm-crypto-asmjs" "^4.6.1" - "@polkadot/wasm-crypto-wasm" "^4.6.1" - -"@polkadot/wasm-crypto@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-5.1.1.tgz#d1f8a0da631028ba904c374c1e8496ab3ba4636b" - integrity sha512-JCcAVfH8DhYuEyd4oX1ouByxhou0TvpErKn8kHjtzt7+tRoFi0nzWlmK4z49vszsV3JJgXxV81i10C0BYlwTcQ== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/wasm-crypto-asmjs" "^5.1.1" - "@polkadot/wasm-crypto-wasm" "^5.1.1" - -"@polkadot/wasm-crypto@^6.2.2", "@polkadot/wasm-crypto@^6.4.1": +"@polkadot/wasm-crypto@^6.4.1": version "6.4.1" resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-6.4.1.tgz#79310e23ad1ca62362ba893db6a8567154c2536a" integrity sha512-FH+dcDPdhSLJvwL0pMLtn/LIPd62QDPODZRCmDyw+pFjLOMaRBc7raomWUOqyRWJTnqVf/iscc2rLVLNMyt7ag== @@ -4420,7 +3695,7 @@ dependencies: "@babel/runtime" "^7.20.6" -"@polkadot/x-bigint@10.4.2", "@polkadot/x-bigint@^10.1.1", "@polkadot/x-bigint@^10.1.13", "@polkadot/x-bigint@^10.4.2": +"@polkadot/x-bigint@10.4.2", "@polkadot/x-bigint@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-10.4.2.tgz#7eb2ec732259df48b5a00f07879a1331e05606ec" integrity sha512-awRiox+/XSReLzimAU94fPldowiwnnMUkQJe8AebYhNocAj6SJU00GNoj6j6tAho6yleOwrTJXZaWFBaQVJQNg== @@ -4428,23 +3703,7 @@ "@babel/runtime" "^7.20.13" "@polkadot/x-global" "10.4.2" -"@polkadot/x-bigint@8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-8.7.1.tgz#a496225def32e98c430c76b91c1579f48acf501a" - integrity sha512-ClkhgdB/KqcAKk3zA6Qw8wBL6Wz67pYTPkrAtImpvoPJmR+l4RARauv+MH34JXMUNlNb3aUwqN6lq2Z1zN+mJg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - -"@polkadot/x-bigint@9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-9.7.2.tgz#ec79977335dce173a81e45247bdfd46f3b301702" - integrity sha512-qi8/DTGypFSt5vvNOsYcEaqH72lymfyidGlsHlZ6e7nNASnEhk/NaOcINiTr1ds+fpu4dtKXWAIPZufujf2JeQ== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/x-global" "9.7.2" - -"@polkadot/x-fetch@^10.1.1", "@polkadot/x-fetch@^10.1.11", "@polkadot/x-fetch@^10.1.13", "@polkadot/x-fetch@^10.4.2": +"@polkadot/x-fetch@^10.1.11", "@polkadot/x-fetch@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-10.4.2.tgz#bc6ba70de71a252472fbe36180511ed920e05f05" integrity sha512-Ubb64yaM4qwhogNP+4mZ3ibRghEg5UuCYRMNaCFoPgNAY8tQXuDKrHzeks3+frlmeH9YRd89o8wXLtWouwZIcw== @@ -4454,45 +3713,14 @@ "@types/node-fetch" "^2.6.2" node-fetch "^3.3.0" -"@polkadot/x-fetch@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-8.7.1.tgz#dc866e7aa87c39b2e64c87f734b8fbaf1b9190e1" - integrity sha512-ygNparcalYFGbspXtdtZOHvNXZBkNgmNO+um9C0JYq74K5OY9/be93uyfJKJ8JcRJtOqBfVDsJpbiRkuJ1PRfg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - "@types/node-fetch" "^2.6.1" - node-fetch "^2.6.7" - -"@polkadot/x-global@10.4.2", "@polkadot/x-global@^10.1.1", "@polkadot/x-global@^10.1.13", "@polkadot/x-global@^10.4.2": +"@polkadot/x-global@10.4.2", "@polkadot/x-global@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-10.4.2.tgz#5662366e3deda0b4c8f024b2d902fa838f9e60a4" integrity sha512-g6GXHD/ykZvHap3M6wh19dO70Zm43l4jEhlxf5LtTo5/0/UporFCXr2YJYZqfbn9JbQwl1AU+NroYio+vtJdiA== dependencies: "@babel/runtime" "^7.20.13" -"@polkadot/x-global@6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-6.11.1.tgz#c292b3825fea60e9b33fff1790323fc57de1ca5d" - integrity sha512-lsBK/e4KbjfieyRmnPs7bTiGbP/6EoCZz7rqD/voNS5qsJAaXgB9LR+ilubun9gK/TDpebyxgO+J19OBiQPIRw== - dependencies: - "@babel/runtime" "^7.14.6" - -"@polkadot/x-global@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-7.9.2.tgz#b272b0a3bedaad3bcbf075ec4682abe68cf2a850" - integrity sha512-JX5CrGWckHf1P9xKXq4vQCAuMUbL81l2hOWX7xeP8nv4caHEpmf5T1wD1iMdQBL5PFifo6Pg0V6/oZBB+bts7A== - dependencies: - "@babel/runtime" "^7.16.3" - -"@polkadot/x-global@8.7.1", "@polkadot/x-global@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-8.7.1.tgz#b972044125a4fe059f4aef7c15a4e22d18179095" - integrity sha512-WOgUor16IihgNVdiTVGAWksYLUAlqjmODmIK1cuWrLOZtV1VBomWcb3obkO9sh5P6iWziAvCB/i+L0vnTN9ZCA== - dependencies: - "@babel/runtime" "^7.17.8" - -"@polkadot/x-global@9.7.2", "@polkadot/x-global@^9.4.1": +"@polkadot/x-global@^9.4.1": version "9.7.2" resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-9.7.2.tgz#9847fd1da13989f321ca621e85477ba70fd8d55a" integrity sha512-3NN5JhjosaelaFWBJSlv9mb/gDAlt7RuZ8NKlOjB+LQHd9g6ZbnYi5wwjW+i/x/3E4IVbBx66uvWgNaw7IBrkg== @@ -4507,46 +3735,6 @@ "@babel/runtime" "^7.20.13" "@polkadot/x-global" "10.4.2" -"@polkadot/x-randomvalues@6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-6.11.1.tgz#f006fa250c8e82c92ccb769976a45a8e7f3df28b" - integrity sha512-2MfUfGZSOkuPt7GF5OJkPDbl4yORI64SUuKM25EGrJ22o1UyoBnPOClm9eYujLMD6BfDZRM/7bQqqoLW+NuHVw== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/x-global" "6.11.1" - -"@polkadot/x-randomvalues@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-7.9.2.tgz#0c9bb7b48a0791c2a32e9605a31a5ce56fee621d" - integrity sha512-svQfG31yCXf6yVyIgP0NgCzEy7oc3Lw054ZspkaqjOivxYdrXaf5w3JSSUyM/MRjI2+nk+B/EyJoMYcfSwTfsQ== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/x-global" "7.9.2" - -"@polkadot/x-randomvalues@8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-8.7.1.tgz#b7cc358c2a6d20f7e7798d45d1d5c7ac8c9ab4f2" - integrity sha512-njt17MlfN6yNyNEti7fL12lr5qM6A1aSGkWKVuqzc7XwSBesifJuW4km5u6r2gwhXjH2eHDv9SoQ7WXu8vrrkg== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - -"@polkadot/x-randomvalues@9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-9.7.2.tgz#d580b0e9149ea22b2afebba5d7b1368371f7086d" - integrity sha512-819slnXNpoVtqdhjI19ao7w5m+Zwx11VfwCZkFQypVv3b/1UEoKG/baJA9dVI6yMvhnBN//i8mLgNy3IXWbVVw== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/x-global" "9.7.2" - -"@polkadot/x-rxjs@^6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-rxjs/-/x-rxjs-6.11.1.tgz#5454708b61da70eea05708611d9148fce9372498" - integrity sha512-zIciEmij7SUuXXg9g/683Irx6GogxivrQS2pgBir2DI/YZq+um52+Dqg1mqsEZt74N4KMTMnzAZAP6LJOBOMww== - dependencies: - "@babel/runtime" "^7.14.6" - rxjs "^6.6.7" - "@polkadot/x-textdecoder@10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-10.4.2.tgz#93202f3e5ad0e7f75a3fa02d2b8a3343091b341b" @@ -4555,38 +3743,6 @@ "@babel/runtime" "^7.20.13" "@polkadot/x-global" "10.4.2" -"@polkadot/x-textdecoder@6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-6.11.1.tgz#6cc314645681cc4639085c03b65328671c7f182c" - integrity sha512-DI1Ym2lyDSS/UhnTT2e9WutukevFZ0WGpzj4eotuG2BTHN3e21uYtYTt24SlyRNMrWJf5+TkZItmZeqs1nwAfQ== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/x-global" "6.11.1" - -"@polkadot/x-textdecoder@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-7.9.2.tgz#a78548e33efeb3a25f761fec9787b2bcae7f0608" - integrity sha512-wfwbSHXPhrOAl12QvlIOGNkMH/N/h8PId2ytIjvM/8zPPFB5Il6DWSFLtVapOGEpIFjEWbd5t8Td4pHBVXIEbg== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/x-global" "7.9.2" - -"@polkadot/x-textdecoder@8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-8.7.1.tgz#b706ef98d5a033d02c633009fb8dab4a4f9d7d55" - integrity sha512-ia0Ie2zi4VdQdNVD2GE2FZzBMfX//hEL4w546RMJfZM2LqDS674LofHmcyrsv5zscLnnRyCxZC1+J2dt+6MDIA== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - -"@polkadot/x-textdecoder@9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-9.7.2.tgz#c94ea6c8f510fdf579659248ede9421854e32b42" - integrity sha512-hhrMNZwJBmusdpqjDRpOHZoMB4hpyJt9Gu9Bi9is7/D/vq/hpxq8z7s6NxrbRyXJf1SIk6NMK0jf5XjRLdKdbw== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/x-global" "9.7.2" - "@polkadot/x-textencoder@10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-10.4.2.tgz#cd2e6c8a66b0b400a73f0164e99c510fb5c83501" @@ -4595,39 +3751,7 @@ "@babel/runtime" "^7.20.13" "@polkadot/x-global" "10.4.2" -"@polkadot/x-textencoder@6.11.1": - version "6.11.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-6.11.1.tgz#73e89da5b91954ae380042c19314c90472f59d9e" - integrity sha512-8ipjWdEuqFo+R4Nxsc3/WW9CSEiprX4XU91a37ZyRVC4e9R1bmvClrpXmRQLVcAQyhRvG8DKOOtWbz8xM+oXKg== - dependencies: - "@babel/runtime" "^7.14.6" - "@polkadot/x-global" "6.11.1" - -"@polkadot/x-textencoder@7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-7.9.2.tgz#b32bfd6fbff8587c56452f58252a52d62bbcd5b9" - integrity sha512-A19wwYINuZwU2dUyQ/mMzB0ISjyfc4cISfL4zCMUAVgj7xVoXMYV2GfjNdMpA8Wsjch3su6pxLbtJ2wU03sRTQ== - dependencies: - "@babel/runtime" "^7.16.3" - "@polkadot/x-global" "7.9.2" - -"@polkadot/x-textencoder@8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-8.7.1.tgz#7820e30081e8e0a607c1c27b9e3486d82d1a723e" - integrity sha512-XDO0A27Xy+eJCKSxENroB8Dcnl+UclGG4ZBei+P/BqZ9rsjskUyd2Vsl6peMXAcsxwOE7g0uTvujoGM8jpKOXw== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - -"@polkadot/x-textencoder@9.7.2": - version "9.7.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-9.7.2.tgz#2ae29fa5ca2c0353e7a1913eef710b2d45bdf0b2" - integrity sha512-GHbSdbMPixDAOnJ9cvL/x9sPNeHegPoDSqCAzY5H6/zHc/fNn0vUu0To9VpPgPhp/Jb9dbc0h8YqEyvOcOlphw== - dependencies: - "@babel/runtime" "^7.18.6" - "@polkadot/x-global" "9.7.2" - -"@polkadot/x-ws@^10.1.1", "@polkadot/x-ws@^10.1.13", "@polkadot/x-ws@^10.4.2": +"@polkadot/x-ws@^10.4.2": version "10.4.2" resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-10.4.2.tgz#4e9d88f37717570ccf942c6f4f63b06260f45025" integrity sha512-3gHSTXAWQu1EMcMVTF5QDKHhEHzKxhAArweEyDXE7VsgKUP/ixxw4hVZBrkX122iI5l5mjSiooRSnp/Zl3xqDQ== @@ -4637,16 +3761,6 @@ "@types/websocket" "^1.0.5" websocket "^1.0.34" -"@polkadot/x-ws@^8.7.1": - version "8.7.1" - resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-8.7.1.tgz#501c63c575e04bba68bdc32448e2c9b692f0411e" - integrity sha512-Mt0tcNzGXyKnN3DQ06alkv+JLtTfXWu6zSypFrrKHSQe3u79xMQ1nSicmpT3gWLhIa8YF+8CYJXMrqaXgCnDhw== - dependencies: - "@babel/runtime" "^7.17.8" - "@polkadot/x-global" "8.7.1" - "@types/websocket" "^1.0.5" - websocket "^1.0.34" - "@polymathnetwork/polymesh-types@0.0.2": version "0.0.2" resolved "https://registry.yarnpkg.com/@polymathnetwork/polymesh-types/-/polymesh-types-0.0.2.tgz#a9f07bc9e1e659e59afa7a5409b2d91301b5fef9" @@ -4783,6 +3897,17 @@ "@swc/helpers" "^0.4.14" clsx "^1.1.1" +"@react-aria/focus@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.11.0.tgz#8124b2341e8d43af72f3da85b08567bda45421b7" + integrity sha512-yPuWs9bAR9CMfIwyOPm2oXLPF19gNkUqW+ozSPhWbLMTEa8Ma09eHW1br4xbN+4ONOm/dCJsIkxTNPUkiLdQoA== + dependencies: + "@react-aria/interactions" "^3.14.0" + "@react-aria/utils" "^3.15.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" + "@react-aria/focus@^3.6.1": version "3.6.1" resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.6.1.tgz#46478d0919bdc4fedfa1ea115b36f93c055ce8d8" @@ -4981,6 +4106,15 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-aria/interactions@^3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.14.0.tgz#d6480985048c009d58b8572428010dc61093cfcc" + integrity sha512-e1Tkr0UTuYFpV21PJrXy7jEY542Vl+C2Fo70oukZ1fN+wtfQkzodsTIzyepXb7kVMGmC34wDisMJUrksVkfY2w== + dependencies: + "@react-aria/utils" "^3.15.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/interactions@^3.9.1": version "3.9.1" resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.9.1.tgz#1860b905d9a0b17ed74dd7fe769370e017cb3015" @@ -5020,6 +4154,18 @@ "@react-types/label" "^3.7.1" "@react-types/shared" "^3.16.0" +"@react-aria/link@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.4.0.tgz#f3f7c5277ab9fc0b8c55c76503e1fbe764e02ca6" + integrity sha512-d/h4y7SFO+KweMX5IRU99L1jz9AAwp6mNStkBjYGxCD29QYTVWClpZHjRlO1s6a9e2QTpk/LzsvjiytowzfHyA== + dependencies: + "@react-aria/focus" "^3.11.0" + "@react-aria/interactions" "^3.14.0" + "@react-aria/utils" "^3.15.0" + "@react-types/link" "^3.4.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/live-announcer@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.1.1.tgz#40f340f6794fca42682fb308fe750ff56bf7c07f" @@ -5152,6 +4298,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@react-aria/ssr@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.5.0.tgz#40c1270a75868185f72a88cafe37bd1392f690cb" + integrity sha512-h0MJdSWOd1qObLnJ8mprU31wI8tmKFJMuwT22MpWq6psisOOZaga6Ml4u6Ee6M6duWWISjXvqO4Sb/J0PBA+nQ== + dependencies: + "@swc/helpers" "^0.4.14" + "@react-aria/switch@^3.2.4": version "3.2.4" resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.2.4.tgz#6a4f95d89347b77d215b5b6d3640baba0360880b" @@ -5303,6 +4456,17 @@ "@swc/helpers" "^0.4.14" clsx "^1.1.1" +"@react-aria/utils@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.15.0.tgz#a836674dd40ec7f15e9f7a69b1a14f19b1ee42e6" + integrity sha512-aJZBG++iz1UwTW5gXFaHicKju4p0MPhAyBTcf2awHYWeTUUslDjJcEnNg7kjBYZBOrOSlA2rAt7/7C5CCURQPg== + dependencies: + "@react-aria/ssr" "^3.5.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" + "@react-aria/visually-hidden@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.6.0.tgz#cc4dd9e648a5c8b6d8dfbd1f70d8672b36d3f1bc" @@ -5515,6 +4679,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@react-stately/utils@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.6.0.tgz#f273e7fcb348254347d2e88c8f0c45571060c207" + integrity sha512-rptF7iUWDrquaYvBAS4QQhOBQyLBncDeHF03WnHXAxnuPJXNcr9cXJtjJPGCs036ZB8Q2hc9BGG5wNyMkF5v+Q== + dependencies: + "@swc/helpers" "^0.4.14" + "@react-stately/virtualizer@^3.2.2": version "3.2.2" resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-3.2.2.tgz#3fca1acc0622d24b1acd3df8efd7795f546f3d1c" @@ -5611,6 +4782,14 @@ dependencies: "@react-types/shared" "^3.16.0" +"@react-types/link@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.4.0.tgz#1c549ffbc594e49726a4c4e912bea36718feb4cf" + integrity sha512-eImWLzxwzSmjOLa0Ow3HJaguyDCz98191v2pb7nT/zPzGDnhHhDjxB023hrXVUoCbsWrCb5QLp91Ts+VjiCyTA== + dependencies: + "@react-aria/interactions" "^3.14.0" + "@react-types/shared" "^3.17.0" + "@react-types/meter@^3.2.1": version "3.2.2" resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.2.2.tgz#029f593e405cf3aebccd9c0f54c588c399689559" @@ -5658,6 +4837,11 @@ resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.16.0.tgz#cab7bf0376969d1773480ecb2d6da5aa91391db5" integrity sha512-IQgU4oAEvMwylEvaTsr2XB1G/mAoMe1JFYLD6G78v++oAR9l8o9MQxZ0YSeANDkqTamb2gKezGoT1RxvSKjVxw== +"@react-types/shared@^3.17.0": + version "3.17.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.17.0.tgz#b7c5e318664aadb315d305a27dd2a209d1837d95" + integrity sha512-1SNZ/RhVrrQ1e6yE0bPV7d5Sfp+Uv0dfUEhwF9MAu2v5msu7AMewnsiojKNA0QA6Ing1gpDLjHCxtayQfuxqcg== + "@react-types/switch@^3.2.4": version "3.2.4" resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.2.4.tgz#6853793032da50415be1abbac1374fca08ea5e44" @@ -5724,11 +4908,6 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@scure/base@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.0.0.tgz#109fb595021de285f05a7db6806f2f48296fcee7" - integrity sha512-gIVaYhUsy+9s58m/ETjSJVKHhKTBMmcRb9cEV5/5dwvfDlfORjKrFsDeDHWRrm6RjcPvCLZFwGJjAjLj1gg4HA== - "@scure/base@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" @@ -6739,36 +5918,18 @@ resolve-from "^5.0.0" "@subsocial/definitions@^0.7.8-dev.0": - version "0.7.9" - resolved "https://registry.yarnpkg.com/@subsocial/definitions/-/definitions-0.7.9.tgz#5bc0d94c9ad269d00d10f9b47fdf4abc447bb183" - integrity sha512-HBYvftT+ixPgPttCRUIpcpKJ9UlvFHWhhUgaLTxfFNQ4qaVMCPT7ZdoEkWYeErefnUVag1j5NzS9TfjTyx9gLg== + version "0.7.14" + resolved "https://registry.yarnpkg.com/@subsocial/definitions/-/definitions-0.7.14.tgz#1397f1ec806d60d9deb112b9f36d530400b711fe" + integrity sha512-dor5S6/tbY09n40e/dh7qFcqF9slMihOMDTXWBM5hTe8nS/Pf5Zp4/r9WiZxxYLoY2v5MlSqyJxjiSCjTxxjUw== dependencies: "@polkadot/api" latest lodash.camelcase "^4.3.0" -"@substrate/connect-extension-protocol@^1.0.0", "@substrate/connect-extension-protocol@^1.0.1": +"@substrate/connect-extension-protocol@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@substrate/connect-extension-protocol/-/connect-extension-protocol-1.0.1.tgz#fa5738039586c648013caa6a0c95c43265dbe77d" integrity sha512-161JhCC1csjH3GE5mPLEd7HbWtwNSPJBg3p1Ksz9SFlTzj/bgEwudiRN2y5i0MoLGCIJRYKyKGMxVnd29PzNjg== -"@substrate/connect@0.7.0-alpha.0": - version "0.7.0-alpha.0" - resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.0-alpha.0.tgz#df605f4e808b58d146ad0272a79b2c4b870459a5" - integrity sha512-fvO7w++M8R95R/pGJFW9+cWOt8OYnnTfgswxtlPqSgzqX4tta8xcNQ51crC72FcL5agwSGkA1gc2/+eyTj7O8A== - dependencies: - "@substrate/connect-extension-protocol" "^1.0.0" - "@substrate/smoldot-light" "0.6.8" - eventemitter3 "^4.0.7" - -"@substrate/connect@0.7.17": - version "0.7.17" - resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.17.tgz#b76ce23d24255e89028db81b3cb280c7f86db72e" - integrity sha512-s0XBmGpUCFWZFa+TS0TEvOKtWjJP2uT4xKmvzApH8INB5xbz79wqWFX6WWh3AlK/X1P0Smt+RVEH7HQiLJAYAw== - dependencies: - "@substrate/connect-extension-protocol" "^1.0.1" - "@substrate/smoldot-light" "0.7.7" - eventemitter3 "^4.0.7" - "@substrate/connect@0.7.19": version "0.7.19" resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.19.tgz#7c879cb275bc7ac2fe9edbf797572d4ff8d8b86a" @@ -6778,39 +5939,6 @@ "@substrate/smoldot-light" "0.7.9" eventemitter3 "^4.0.7" -"@substrate/connect@0.7.9": - version "0.7.9" - resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.9.tgz#0bb65fef28c70051e6158e10f633005e899fbb5b" - integrity sha512-E6bdBhzsfHNAKlmQSvbTW1jyb0WcIvgbrEBfJ4B6FZ3t1wpGjldL6GrYtegVtKr9/ySQ/pFNn0uVbugukpMDjQ== - dependencies: - "@substrate/connect-extension-protocol" "^1.0.1" - "@substrate/smoldot-light" "0.6.25" - eventemitter3 "^4.0.7" - -"@substrate/smoldot-light@0.6.25": - version "0.6.25" - resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.6.25.tgz#3025ba5134b1be470855f901ffeb028a0f93460c" - integrity sha512-OQ9/bnJJy90xSRg5Vp9MIvrgbrVt/r/FwXYSmyLeBBNbJt6o1gSeshVo8icD+2VWwd/TJ2oHl5CVQWe89MyByA== - dependencies: - websocket "^1.0.32" - -"@substrate/smoldot-light@0.6.8": - version "0.6.8" - resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.6.8.tgz#e626e25cd2386824f1164e7d7dda7258580c36e4" - integrity sha512-9lVwbG6wrtss0sd6013BJGe4WN4taujsGG49pwyt1Lj36USeL2Sb164TTUxmZF/g2NQEqDPwPROBdekQ2gFmgg== - dependencies: - buffer "^6.0.1" - pako "^2.0.4" - websocket "^1.0.32" - -"@substrate/smoldot-light@0.7.7": - version "0.7.7" - resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.7.7.tgz#ee5f89bb25af64d2014d97548b959b7da4c67f08" - integrity sha512-ksxeAed6dIUtYSl0f8ehgWQjwXnpDGTIJt+WVRIGt3OObZkA96ZdBWx0xP7GrXZtj37u4n/Y1z7TyTm4bwQvrw== - dependencies: - pako "^2.0.4" - ws "^8.8.1" - "@substrate/smoldot-light@0.7.9": version "0.7.9" resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.7.9.tgz#68449873a25558e547e9468289686ee228a9930f" @@ -6819,7 +5947,7 @@ pako "^2.0.4" ws "^8.8.1" -"@substrate/ss58-registry@^1.17.0", "@substrate/ss58-registry@^1.23.0", "@substrate/ss58-registry@^1.38.0": +"@substrate/ss58-registry@^1.38.0": version "1.39.0" resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.39.0.tgz#eb916ff5fea7fa02e77745823fde21af979273d2" integrity sha512-qZYpuE6n+mwew+X71dOur/CbMXj6rNW27o63JeJwdQH/GvcSKm3JLNhd+bGzwUKg0D/zD30Qc6p4JykArzM+tA== @@ -7110,14 +6238,7 @@ resolved "https://registry.yarnpkg.com/@types/big.js/-/big.js-6.1.2.tgz#68a952b629a6aaa2b5855a2f63363d1e77f6dd91" integrity sha512-h24JIZ52rvSvi2jkpYDk2yLH99VzZoCJiSfDWwjst7TwJVuXN61XVCUlPCzRl7mxKEMsGf8z42Q+J4TZwU3z2w== -"@types/bn.js@^4.11.6": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - -"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": +"@types/bn.js@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== @@ -7310,7 +6431,7 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node-fetch@^2.6.1", "@types/node-fetch@^2.6.2": +"@types/node-fetch@^2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== @@ -8903,14 +8024,14 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2, base-x@^3.0.8: +base-x@^3.0.2: version "3.0.9" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== dependencies: safe-buffer "^5.0.1" -base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -9082,17 +8203,12 @@ bl@^5.0.0: inherits "^2.0.4" readable-stream "^3.4.0" -blakejs@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - bluebird@^3.3.5, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -bn.js@4.12.0, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.2.0, bn.js@^5.2.1, bn.js@~5.2.0: +bn.js@4.12.0, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.2.1, bn.js@~5.2.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -9360,7 +8476,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^6.0.1, buffer@^6.0.3: +buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -9578,7 +8694,7 @@ camelcase@^2.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw== -camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0, camelcase@^6.2.1: +camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -10761,11 +9877,6 @@ csstype@^3.0.2, csstype@^3.0.6: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== -cuint@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" - integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== - currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -11387,7 +10498,7 @@ electron-to-chromium@^1.4.118: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.138.tgz#3ec41ca589aaf505dfe2034fde913329af801730" integrity sha512-IOyp2Seq3w4QLln+yZWcMF3VXhhduz4bwg9gfI+CnP5TkzwNXQ8FCZuwwPsnes73AfWdf5J2n2OXdUwDUspDPQ== -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -13354,7 +12465,7 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -14014,11 +13125,6 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip-regex@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" - integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== - ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -14914,6 +14020,11 @@ jest-matcher-utils@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" +jest-matchmedia-mock@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jest-matchmedia-mock/-/jest-matchmedia-mock-1.1.0.tgz#eaae8c5d1dee4e4f7c59f8cb1b38b5d7ea842552" + integrity sha512-REnJRsOSCMpGAlkxmvVTqEBpregyFVi9MPEH3N83W1yLKzDdNehtCkcdDZduXq74PLtfI+11NyM4zKCK5ynV9g== + jest-message-util@^26.6.0, jest-message-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" @@ -15190,7 +14301,7 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== -js-sha3@0.8.0, js-sha3@^0.8.0: +js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== @@ -16037,11 +15148,6 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micro-base@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/micro-base/-/micro-base-0.9.0.tgz#09cfe20285bec0ea97f41dc3d10e3fba3d0266ee" - integrity sha512-4+tOMKidYT5nQ6/UNmYrGVO5PMcnJdfuR4NC8HK8s2H61B4itOhA9yrsjBdqGV7ecdtej36x3YSIfPLRmPrspg== - microevent.ts@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" @@ -16289,7 +15395,7 @@ mobx@^5.15.7: resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.15.7.tgz#b9a5f2b6251f5d96980d13c78e9b5d8d4ce22665" integrity sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw== -mock-socket@^9.1.2, mock-socket@^9.1.5, mock-socket@^9.2.1: +mock-socket@^9.2.1: version "9.2.1" resolved "https://registry.yarnpkg.com/mock-socket/-/mock-socket-9.2.1.tgz#cc9c0810aa4d0afe02d721dcb2b7e657c00e2282" integrity sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag== @@ -16491,7 +15597,7 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -nock@^13.2.4, nock@^13.2.9, nock@^13.3.0: +nock@^13.3.0: version "13.3.0" resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.0.tgz#b13069c1a03f1ad63120f994b04bfd2556925768" integrity sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg== @@ -19290,7 +18396,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.10, regenerator-runtime@^0.13.11: +regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== @@ -19847,13 +18953,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.6.7: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - rxjs@^7.2.0, rxjs@^7.5.6, rxjs@^7.5.7: version "7.5.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" @@ -19861,13 +18960,6 @@ rxjs@^7.2.0, rxjs@^7.5.6, rxjs@^7.5.7: dependencies: tslib "^2.1.0" -rxjs@^7.4.0, rxjs@^7.5.5, rxjs@^7.8.0: - version "7.8.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== - dependencies: - tslib "^2.1.0" - rxjs@^7.5.1: version "7.5.5" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" @@ -19875,6 +18967,13 @@ rxjs@^7.5.1: dependencies: tslib "^2.1.0" +rxjs@^7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -20004,11 +19103,6 @@ scrypt-js@3.0.1: resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -scryptsy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" - integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -21501,7 +20595,7 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.10.0, tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -22492,7 +21586,7 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -websocket@^1.0.32, websocket@^1.0.34: +websocket@^1.0.34: version "1.0.34" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== @@ -22904,13 +21998,6 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xxhashjs@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" - integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== - dependencies: - cuint "^0.2.2" - y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" From e1339ac694f3b05327cf66ff668d912dfe4e1bf9 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 13:32:52 +0000 Subject: [PATCH 10/69] api: handle terms and conditions --- api/package-lock.json | 2185 +++++++++++++++++++++++++++++++++++++++++ api/package.json | 18 + api/terms.ts | 29 + 3 files changed, 2232 insertions(+) create mode 100644 api/package-lock.json create mode 100644 api/package.json create mode 100644 api/terms.ts diff --git a/api/package-lock.json b/api/package-lock.json new file mode 100644 index 0000000000..466c3e827e --- /dev/null +++ b/api/package-lock.json @@ -0,0 +1,2185 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "api", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "pg": "^8.10.0" + }, + "devDependencies": { + "@types/pg": "^8.6.6", + "@vercel/node": "^2.10.2" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@edge-runtime/format": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-1.1.0.tgz", + "integrity": "sha512-MkLDDtPhXZIMx83NykdFmOpF7gVWIdd6GBHYb8V/E+PKWvD2pK/qWx9B30oN1iDJ2XBm0SGDjz02S8nDHI9lMQ==", + "dev": true + }, + "node_modules/@edge-runtime/primitives": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-2.0.0.tgz", + "integrity": "sha512-AXqUq1zruTJAICrllUvZcgciIcEGHdF6KJ3r6FM0n4k8LpFxZ62tPWVIJ9HKm+xt+ncTBUZxwgUaQ73QMUQEKw==", + "dev": true + }, + "node_modules/@edge-runtime/vm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-2.0.0.tgz", + "integrity": "sha512-BOLrAX8IWHRXu1siZocwLguKJPEUv7cr+rG8tI4hvHgMdIsBWHJlLeB8EjuUVnIURFrUiM49lVKn8DRrECmngw==", + "dev": true, + "dependencies": { + "@edge-runtime/primitives": "2.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", + "integrity": "sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", + "dev": true + }, + "node_modules/@types/pg": { + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz", + "integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@vercel/build-utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-6.7.0.tgz", + "integrity": "sha512-1cHgu0AzETSMLo1ugeHOT2pcrXNoZb1bwgxBP7yTIlJAKWLIEqPHbJWFvKQXZl2FV3kzzTctTrw/YNUWmntYiA==", + "dev": true + }, + "node_modules/@vercel/node": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-2.10.2.tgz", + "integrity": "sha512-rsxVEosHUtSBswZfZWxWgV4v5x8COB9kTp4lhaxZXC9cHFgXT5ydV7m4R2NOPwcRGUbQSyy9ushX1RnsOan0qw==", + "dev": true, + "dependencies": { + "@edge-runtime/vm": "2.0.0", + "@types/node": "14.18.33", + "@vercel/build-utils": "6.7.0", + "@vercel/node-bridge": "4.0.0", + "@vercel/static-config": "2.0.14", + "edge-runtime": "2.0.0", + "esbuild": "0.14.47", + "exit-hook": "2.2.1", + "node-fetch": "2.6.7", + "ts-node": "10.9.1", + "typescript": "4.3.4" + } + }, + "node_modules/@vercel/node-bridge": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@vercel/node-bridge/-/node-bridge-4.0.0.tgz", + "integrity": "sha512-617HSGelTGR68s0kqsPV0R2UiSvcw3Zf5Yv32S5NN4AH5TZGRr5DQJ3ATr4C/HrK7CHK5B7FDVrv2JebdVpPYQ==", + "dev": true + }, + "node_modules/@vercel/static-config": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-2.0.14.tgz", + "integrity": "sha512-Ih0H/V8geRjsNpvD73dphV+y0Pe21RXIJEUW/XI0y7ZrYzLbYQt4AAIvsgfDqcQNm4xEizh3sEXArPWEp18bdQ==", + "dev": true, + "dependencies": { + "ajv": "8.6.3", + "json-schema-to-ts": "1.6.4", + "ts-morph": "12.0.0" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/code-block-writer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", + "integrity": "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-hrtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-3.0.0.tgz", + "integrity": "sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/edge-runtime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.0.0.tgz", + "integrity": "sha512-TmRJhKi4mlM1e+zgF4CSzVU5gJ1sWj7ia+XhVgZ8PYyYUxk4PPjJU8qScpSLsAbdSxoBghLxdMuwuCzdYLd1sQ==", + "dev": true, + "dependencies": { + "@edge-runtime/format": "1.1.0", + "@edge-runtime/vm": "2.0.0", + "exit-hook": "2.2.1", + "http-status": "1.5.3", + "mri": "1.2.0", + "picocolors": "1.0.0", + "pretty-bytes": "5.6.0", + "pretty-ms": "7.0.1", + "time-span": "4.0.0" + }, + "bin": { + "edge-runtime": "dist/cli/index.js" + } + }, + "node_modules/esbuild": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", + "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.47", + "esbuild-android-arm64": "0.14.47", + "esbuild-darwin-64": "0.14.47", + "esbuild-darwin-arm64": "0.14.47", + "esbuild-freebsd-64": "0.14.47", + "esbuild-freebsd-arm64": "0.14.47", + "esbuild-linux-32": "0.14.47", + "esbuild-linux-64": "0.14.47", + "esbuild-linux-arm": "0.14.47", + "esbuild-linux-arm64": "0.14.47", + "esbuild-linux-mips64le": "0.14.47", + "esbuild-linux-ppc64le": "0.14.47", + "esbuild-linux-riscv64": "0.14.47", + "esbuild-linux-s390x": "0.14.47", + "esbuild-netbsd-64": "0.14.47", + "esbuild-openbsd-64": "0.14.47", + "esbuild-sunos-64": "0.14.47", + "esbuild-windows-32": "0.14.47", + "esbuild-windows-64": "0.14.47", + "esbuild-windows-arm64": "0.14.47" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", + "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", + "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", + "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", + "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", + "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", + "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", + "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", + "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", + "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", + "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", + "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", + "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", + "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", + "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", + "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", + "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", + "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", + "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", + "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", + "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-status": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.5.3.tgz", + "integrity": "sha512-jCClqdnnwigYslmtfb28vPplOgoiZ0siP2Z8C5Ua+3UKbx410v+c+jT+jh1bbI4TvcEySuX0vd/CfFZFbDkJeQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-1.6.4.tgz", + "integrity": "sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ts-toolbelt": "^6.15.5" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/time-span": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-4.0.0.tgz", + "integrity": "sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==", + "dev": true, + "dependencies": { + "convert-hrtime": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/ts-morph": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-12.0.0.tgz", + "integrity": "sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==", + "dev": true, + "dependencies": { + "@ts-morph/common": "~0.11.0", + "code-block-writer": "^10.1.1" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@edge-runtime/format": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/format/-/format-1.1.0.tgz", + "integrity": "sha512-MkLDDtPhXZIMx83NykdFmOpF7gVWIdd6GBHYb8V/E+PKWvD2pK/qWx9B30oN1iDJ2XBm0SGDjz02S8nDHI9lMQ==", + "dev": true + }, + "@edge-runtime/primitives": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-2.0.0.tgz", + "integrity": "sha512-AXqUq1zruTJAICrllUvZcgciIcEGHdF6KJ3r6FM0n4k8LpFxZ62tPWVIJ9HKm+xt+ncTBUZxwgUaQ73QMUQEKw==", + "dev": true + }, + "@edge-runtime/vm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-2.0.0.tgz", + "integrity": "sha512-BOLrAX8IWHRXu1siZocwLguKJPEUv7cr+rG8tI4hvHgMdIsBWHJlLeB8EjuUVnIURFrUiM49lVKn8DRrECmngw==", + "dev": true, + "requires": { + "@edge-runtime/primitives": "2.0.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@ts-morph/common": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", + "integrity": "sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==", + "dev": true, + "requires": { + "fast-glob": "^3.2.7", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/node": { + "version": "14.18.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", + "dev": true + }, + "@types/pg": { + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz", + "integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==", + "dev": true, + "requires": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "@vercel/build-utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@vercel/build-utils/-/build-utils-6.7.0.tgz", + "integrity": "sha512-1cHgu0AzETSMLo1ugeHOT2pcrXNoZb1bwgxBP7yTIlJAKWLIEqPHbJWFvKQXZl2FV3kzzTctTrw/YNUWmntYiA==", + "dev": true + }, + "@vercel/node": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@vercel/node/-/node-2.10.2.tgz", + "integrity": "sha512-rsxVEosHUtSBswZfZWxWgV4v5x8COB9kTp4lhaxZXC9cHFgXT5ydV7m4R2NOPwcRGUbQSyy9ushX1RnsOan0qw==", + "dev": true, + "requires": { + "@edge-runtime/vm": "2.0.0", + "@types/node": "14.18.33", + "@vercel/build-utils": "6.7.0", + "@vercel/node-bridge": "4.0.0", + "@vercel/static-config": "2.0.14", + "edge-runtime": "2.0.0", + "esbuild": "0.14.47", + "exit-hook": "2.2.1", + "node-fetch": "2.6.7", + "ts-node": "10.9.1", + "typescript": "4.3.4" + } + }, + "@vercel/node-bridge": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@vercel/node-bridge/-/node-bridge-4.0.0.tgz", + "integrity": "sha512-617HSGelTGR68s0kqsPV0R2UiSvcw3Zf5Yv32S5NN4AH5TZGRr5DQJ3ATr4C/HrK7CHK5B7FDVrv2JebdVpPYQ==", + "dev": true + }, + "@vercel/static-config": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@vercel/static-config/-/static-config-2.0.14.tgz", + "integrity": "sha512-Ih0H/V8geRjsNpvD73dphV+y0Pe21RXIJEUW/XI0y7ZrYzLbYQt4AAIvsgfDqcQNm4xEizh3sEXArPWEp18bdQ==", + "dev": true, + "requires": { + "ajv": "8.6.3", + "json-schema-to-ts": "1.6.4", + "ts-morph": "12.0.0" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "code-block-writer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", + "integrity": "sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "convert-hrtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-3.0.0.tgz", + "integrity": "sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "edge-runtime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/edge-runtime/-/edge-runtime-2.0.0.tgz", + "integrity": "sha512-TmRJhKi4mlM1e+zgF4CSzVU5gJ1sWj7ia+XhVgZ8PYyYUxk4PPjJU8qScpSLsAbdSxoBghLxdMuwuCzdYLd1sQ==", + "dev": true, + "requires": { + "@edge-runtime/format": "1.1.0", + "@edge-runtime/vm": "2.0.0", + "exit-hook": "2.2.1", + "http-status": "1.5.3", + "mri": "1.2.0", + "picocolors": "1.0.0", + "pretty-bytes": "5.6.0", + "pretty-ms": "7.0.1", + "time-span": "4.0.0" + } + }, + "esbuild": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", + "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.47", + "esbuild-android-arm64": "0.14.47", + "esbuild-darwin-64": "0.14.47", + "esbuild-darwin-arm64": "0.14.47", + "esbuild-freebsd-64": "0.14.47", + "esbuild-freebsd-arm64": "0.14.47", + "esbuild-linux-32": "0.14.47", + "esbuild-linux-64": "0.14.47", + "esbuild-linux-arm": "0.14.47", + "esbuild-linux-arm64": "0.14.47", + "esbuild-linux-mips64le": "0.14.47", + "esbuild-linux-ppc64le": "0.14.47", + "esbuild-linux-riscv64": "0.14.47", + "esbuild-linux-s390x": "0.14.47", + "esbuild-netbsd-64": "0.14.47", + "esbuild-openbsd-64": "0.14.47", + "esbuild-sunos-64": "0.14.47", + "esbuild-windows-32": "0.14.47", + "esbuild-windows-64": "0.14.47", + "esbuild-windows-arm64": "0.14.47" + } + }, + "esbuild-android-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", + "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", + "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", + "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", + "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", + "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", + "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", + "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", + "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", + "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", + "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", + "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", + "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", + "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", + "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", + "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", + "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", + "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", + "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", + "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", + "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", + "dev": true, + "optional": true + }, + "exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "http-status": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.5.3.tgz", + "integrity": "sha512-jCClqdnnwigYslmtfb28vPplOgoiZ0siP2Z8C5Ua+3UKbx410v+c+jT+jh1bbI4TvcEySuX0vd/CfFZFbDkJeQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "json-schema-to-ts": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-1.6.4.tgz", + "integrity": "sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ts-toolbelt": "^6.15.5" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "requires": { + "parse-ms": "^2.1.0" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, + "time-span": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-4.0.0.tgz", + "integrity": "sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==", + "dev": true, + "requires": { + "convert-hrtime": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "ts-morph": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-12.0.0.tgz", + "integrity": "sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==", + "dev": true, + "requires": { + "@ts-morph/common": "~0.11.0", + "code-block-writer": "^10.1.1" + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true + }, + "typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000000..f96c8f4180 --- /dev/null +++ b/api/package.json @@ -0,0 +1,18 @@ +{ + "name": "api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@types/pg": "^8.6.6", + "@vercel/node": "^2.10.2" + }, + "dependencies": { + "pg": "^8.10.0" + } +} diff --git a/api/terms.ts b/api/terms.ts new file mode 100644 index 0000000000..227becb9a2 --- /dev/null +++ b/api/terms.ts @@ -0,0 +1,29 @@ +import type { VercelRequest, VercelResponse } from '@vercel/node'; +import postgres from 'pg' +const { Pool } = postgres; + +const pool = new Pool() +const pattern = new URLPattern({ pathname: '/api/terms/:wallet' }); + +export default async function (request: VercelRequest, response: VercelResponse) { + if (!pattern.test(request.url)) { + return response.status(400).send('Bad Request'); + } + + const result = pattern.exec(request.url); + const wallet = result.pathname.groups.wallet; + + if (request.method === 'GET') { + const result = await pool.query('select exists(select 1 from signed_terms where wallet_id=$1)', [wallet]) + return response.send(result.rows[0]); + } else if (request.method === 'POST') { + try { + const result = await pool.query('insert into signed_terms (wallet_id) values ($1)', [wallet]) + return response.status(201); + } catch (error) { + console.log(error); + return response.status(400).send('Bad Request'); + } + } + return response.status(400).send('Bad Request'); +} \ No newline at end of file From a91c76910339e80ebe6066d4b3b15f70a10493aa Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 13:56:03 +0000 Subject: [PATCH 11/69] api: handle terms and conditions --- api/{terms.ts => terms.js} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename api/{terms.ts => terms.js} (86%) diff --git a/api/terms.ts b/api/terms.js similarity index 86% rename from api/terms.ts rename to api/terms.js index 227becb9a2..9417d80fa4 100644 --- a/api/terms.ts +++ b/api/terms.js @@ -1,11 +1,10 @@ -import type { VercelRequest, VercelResponse } from '@vercel/node'; import postgres from 'pg' const { Pool } = postgres; const pool = new Pool() const pattern = new URLPattern({ pathname: '/api/terms/:wallet' }); -export default async function (request: VercelRequest, response: VercelResponse) { +export default async function (request, response) { if (!pattern.test(request.url)) { return response.status(400).send('Bad Request'); } From 7e3a59520d0b0de959f3c9acf9a8692018e4e044 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 14:46:39 +0000 Subject: [PATCH 12/69] chore: NODE_OPTIONS=--openssl-legacy-provider --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb4610b868..1a98b4241c 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "type-check": "tsc", "format": "yarn prettier --write src", "setup": "yarn generate:defs && yarn generate:meta", - "build": "REACT_APP_VERSION=$npm_package_version craco build", + "build": "REACT_APP_VERSION=$npm_package_version NODE_OPTIONS=--openssl-legacy-provider craco build", "build-with-webpack-bundle-analysis": "yarn build --stats && webpack-bundle-analyzer build/bundle-stats.json -m static -r build/bundle-stats.html -O", "lint-and-type-check": "yarn lint && yarn type-check", "eject": "react-scripts eject", From b0c948eeada9eccca0f90652c599855e447245e2 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 15:00:58 +0000 Subject: [PATCH 13/69] api: add urlpattern-polyfill --- api/package-lock.json | 29 +++++++++++++++++++---------- api/package.json | 3 ++- api/terms.js | 4 ++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index 466c3e827e..e6c274dad7 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "pg": "^8.10.0" + "pg": "^8.10.0", + "urlpattern-polyfill": "^6.0.2" }, "devDependencies": { "@types/pg": "^8.6.6", @@ -273,7 +274,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -747,7 +747,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -801,7 +800,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -1175,7 +1173,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -1270,6 +1267,14 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-6.0.2.tgz", + "integrity": "sha512-5vZjFlH9ofROmuWmXM9yj2wljYKgWstGwe8YTyiqM7hVum/g9LyCizPZtb3UqsuppVwety9QJmfc42VggLpTgg==", + "dependencies": { + "braces": "^3.0.2" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -1540,7 +1545,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -1803,7 +1807,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -1841,8 +1844,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "json-schema-to-ts": { "version": "1.6.4", @@ -2085,7 +2087,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -2148,6 +2149,14 @@ "punycode": "^2.1.0" } }, + "urlpattern-polyfill": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-6.0.2.tgz", + "integrity": "sha512-5vZjFlH9ofROmuWmXM9yj2wljYKgWstGwe8YTyiqM7hVum/g9LyCizPZtb3UqsuppVwety9QJmfc42VggLpTgg==", + "requires": { + "braces": "^3.0.2" + } + }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/api/package.json b/api/package.json index f96c8f4180..39ba0ed9eb 100644 --- a/api/package.json +++ b/api/package.json @@ -13,6 +13,7 @@ "@vercel/node": "^2.10.2" }, "dependencies": { - "pg": "^8.10.0" + "pg": "^8.10.0", + "urlpattern-polyfill": "^6.0.2" } } diff --git a/api/terms.js b/api/terms.js index 9417d80fa4..73550fddbb 100644 --- a/api/terms.js +++ b/api/terms.js @@ -1,6 +1,10 @@ import postgres from 'pg' const { Pool } = postgres; +if (!globalThis.URLPattern) { + await import("urlpattern-polyfill"); +} + const pool = new Pool() const pattern = new URLPattern({ pathname: '/api/terms/:wallet' }); From 62a10dcadf10161ed71c849ac9d48545f0fd3e77 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 16:45:06 +0000 Subject: [PATCH 14/69] api: add urlpattern-polyfill --- vercel.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vercel.json b/vercel.json index 610cefb1c8..48d98a147f 100644 --- a/vercel.json +++ b/vercel.json @@ -3,6 +3,10 @@ "api/*.py": { "memory": 128, "maxDuration": 5 + }, + "api/terms.js": { + "memory": 128, + "maxDuration": 5 } }, "rewrites": [ From 777156e373b3360078aeea471e5bbf4cc74e5e84 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 16:46:36 +0000 Subject: [PATCH 15/69] api: add urlpattern-polyfill --- api/terms.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/terms.js b/api/terms.js index 73550fddbb..dc39eadbf6 100644 --- a/api/terms.js +++ b/api/terms.js @@ -1,9 +1,7 @@ import postgres from 'pg' const { Pool } = postgres; -if (!globalThis.URLPattern) { - await import("urlpattern-polyfill"); -} +import "urlpattern-polyfill"; const pool = new Pool() const pattern = new URLPattern({ pathname: '/api/terms/:wallet' }); From 6d4ef576c2fb69533b9785151e8c17a4a52ed09a Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 17:00:32 +0000 Subject: [PATCH 16/69] api: add urlpattern-polyfill --- vercel.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vercel.json b/vercel.json index 48d98a147f..51fab15446 100644 --- a/vercel.json +++ b/vercel.json @@ -21,6 +21,10 @@ { "source": "/marketdata/(.*)", "destination": "/api/market_data.py" + }, + { + "source": "/terms/(.*)", + "destination": "/api/terms.js" } ], "headers": [ From 2aa34a050e7a139398109dd843ff441045fc368d Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 17:20:50 +0000 Subject: [PATCH 17/69] api: add urlpattern-polyfill --- api/terms.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/terms.js b/api/terms.js index dc39eadbf6..384bf7b821 100644 --- a/api/terms.js +++ b/api/terms.js @@ -4,9 +4,10 @@ const { Pool } = postgres; import "urlpattern-polyfill"; const pool = new Pool() -const pattern = new URLPattern({ pathname: '/api/terms/:wallet' }); +const pattern = new URLPattern({ pathname: '/terms/:wallet' }); export default async function (request, response) { + console.log(request) if (!pattern.test(request.url)) { return response.status(400).send('Bad Request'); } From 0192d49cd88004d9f347463a5727385ba9b0e161 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 19:00:40 +0000 Subject: [PATCH 18/69] api: remove urlpattern-polyfill --- api/package-lock.json | 29 ++++++++++------------------- api/package.json | 3 +-- api/terms.js | 7 ++----- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index e6c274dad7..466c3e827e 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,8 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "pg": "^8.10.0", - "urlpattern-polyfill": "^6.0.2" + "pg": "^8.10.0" }, "devDependencies": { "@types/pg": "^8.6.6", @@ -274,6 +273,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -747,6 +747,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -800,6 +801,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -1173,6 +1175,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -1267,14 +1270,6 @@ "punycode": "^2.1.0" } }, - "node_modules/urlpattern-polyfill": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-6.0.2.tgz", - "integrity": "sha512-5vZjFlH9ofROmuWmXM9yj2wljYKgWstGwe8YTyiqM7hVum/g9LyCizPZtb3UqsuppVwety9QJmfc42VggLpTgg==", - "dependencies": { - "braces": "^3.0.2" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -1545,6 +1540,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -1807,6 +1803,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -1844,7 +1841,8 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "json-schema-to-ts": { "version": "1.6.4", @@ -2087,6 +2085,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -2149,14 +2148,6 @@ "punycode": "^2.1.0" } }, - "urlpattern-polyfill": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-6.0.2.tgz", - "integrity": "sha512-5vZjFlH9ofROmuWmXM9yj2wljYKgWstGwe8YTyiqM7hVum/g9LyCizPZtb3UqsuppVwety9QJmfc42VggLpTgg==", - "requires": { - "braces": "^3.0.2" - } - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/api/package.json b/api/package.json index 39ba0ed9eb..f96c8f4180 100644 --- a/api/package.json +++ b/api/package.json @@ -13,7 +13,6 @@ "@vercel/node": "^2.10.2" }, "dependencies": { - "pg": "^8.10.0", - "urlpattern-polyfill": "^6.0.2" + "pg": "^8.10.0" } } diff --git a/api/terms.js b/api/terms.js index 384bf7b821..8be6a4cb6c 100644 --- a/api/terms.js +++ b/api/terms.js @@ -1,10 +1,8 @@ import postgres from 'pg' const { Pool } = postgres; -import "urlpattern-polyfill"; - const pool = new Pool() -const pattern = new URLPattern({ pathname: '/terms/:wallet' }); +const pattern = /\/terms\/(?\w+)/; export default async function (request, response) { console.log(request) @@ -12,8 +10,7 @@ export default async function (request, response) { return response.status(400).send('Bad Request'); } - const result = pattern.exec(request.url); - const wallet = result.pathname.groups.wallet; + const wallet = request.url.match(pattern).groups.wallet; if (request.method === 'GET') { const result = await pool.query('select exists(select 1 from signed_terms where wallet_id=$1)', [wallet]) From 6fd0d29f42e9213576d7958c9c59067580f67a95 Mon Sep 17 00:00:00 2001 From: ns212 Date: Fri, 7 Apr 2023 19:09:08 +0000 Subject: [PATCH 19/69] api: remove urlpattern-polyfill --- api/terms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/terms.js b/api/terms.js index 8be6a4cb6c..ce24172109 100644 --- a/api/terms.js +++ b/api/terms.js @@ -2,10 +2,10 @@ import postgres from 'pg' const { Pool } = postgres; const pool = new Pool() + const pattern = /\/terms\/(?\w+)/; export default async function (request, response) { - console.log(request) if (!pattern.test(request.url)) { return response.status(400).send('Bad Request'); } From 6eee4dc5daff1f066850c5cc32ec2f23b8595cd4 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Tue, 11 Apr 2023 12:10:28 +0100 Subject: [PATCH 20/69] refactor: disable signature request if signing api is not set --- src/constants.ts | 2 +- src/utils/hooks/use-sign-message.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index e123a56f62..47adc8b025 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,7 +36,7 @@ const SQUID_URL = process.env.REACT_APP_SQUID_URL || 'http://localhost:4000/grap const FEEDBACK_URL = 'https://forms.gle/2eKFnq4j1fkBgejW7'; -const SIGNER_API_URL = process.env.REACT_APP_SIGNER_API_URL || 'https://api.interlay.io/signer'; +const SIGNER_API_URL = process.env.REACT_APP_SIGNER_API_URL || ''; // FIXME: hacky workaround to get the right ss58 prefix. Should be fetched at runtime instead // Possible example below: diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 95a429102c..08d9d7813e 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -63,7 +63,8 @@ const useSignMessage = (): UseSignMessageResult => { const handleSignMessage = (account?: KeyringPair) => { // should not sign message if there is already a stored signature - if (!account || signature) return; + // or if signer api url is not set + if (!account || !SIGNER_API_URL || signature) return; signMessageMutation.mutate(account); }; From 97ab143fbbda1482b3f3362b17a03612fa24994a Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Tue, 11 Apr 2023 12:17:28 +0100 Subject: [PATCH 21/69] refactor: consistent variable checking --- src/utils/hooks/use-sign-message.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 08d9d7813e..8f8692062b 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -6,7 +6,6 @@ import { useLocalStorage } from 'react-use'; import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; import { SIGNER_API_URL } from '@/constants'; import { KeyringPair, useSubstrateSecureState } from '@/lib/substrate'; -import { BitcoinNetwork } from '@/types/bitcoin'; import { signMessage } from '../helpers/wallet'; @@ -70,7 +69,7 @@ const useSignMessage = (): UseSignMessageResult => { }; return { - hasSignature: process.env.REACT_APP_BITCOIN_NETWORK === BitcoinNetwork.Testnet || !!signature, + hasSignature: !SIGNER_API_URL || !!signature, selectProp: { onSelectionChange: handleSignMessage }, buttonProps: { onPress: () => handleSignMessage(selectedAccount) } }; From be4ffffc49a7bc2e2ea0ff929cffc248be80a28d Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Tue, 11 Apr 2023 13:56:35 +0100 Subject: [PATCH 22/69] wip: use signer api --- src/utils/hooks/use-sign-message.ts | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 8f8692062b..0c0185805c 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -1,7 +1,6 @@ import { PressEvent } from '@react-types/shared'; import { useEffect, useState } from 'react'; import { useMutation } from 'react-query'; -import { useLocalStorage } from 'react-use'; import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; import { SIGNER_API_URL } from '@/constants'; @@ -16,18 +15,26 @@ const postSignature = async (account: KeyringPair) => { throw new Error('Failed to sign message'); } - return fetch(`${SIGNER_API_URL}/accept`, { + return fetch(`${SIGNER_API_URL}/${account.address}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - accountid: account.address, - signature: signerResult?.signature + signed_message: signerResult?.signature }) }); }; +const getSignature = (account: KeyringPair) => { + return fetch(`${SIGNER_API_URL}/${account.address}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); +}; + type UseSignMessageResult = { hasSignature?: boolean; selectProp: { onSelectionChange: (account: KeyringPair) => void }; @@ -37,39 +44,32 @@ type UseSignMessageResult = { }; const useSignMessage = (): UseSignMessageResult => { - const [account, setAccount] = useState(); - // TODO: replace this with new get endpoint - const [signature, setSignature] = useLocalStorage(`$tc-${account?.address}`); + const [hasSigned, setHasSigned] = useState(false); const { selectedAccount } = useSubstrateSecureState(); - // TODO: this function might be removed - const handleSuccess = (account?: KeyringPair) => { - if (!account) return; - setSignature(`$tc-${account.address}`); - }; - const handleError = (error: Error) => console.log(error); const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { - onSuccess: () => handleSuccess(account), onError: handleError }); useEffect(() => { if (!selectedAccount) return; - setAccount(selectedAccount); + console.log('getSignature(account)', getSignature(selectedAccount)); + + setHasSigned(false); }, [selectedAccount]); const handleSignMessage = (account?: KeyringPair) => { // should not sign message if there is already a stored signature // or if signer api url is not set - if (!account || !SIGNER_API_URL || signature) return; + if (!account || !SIGNER_API_URL || hasSigned) return; signMessageMutation.mutate(account); }; return { - hasSignature: !SIGNER_API_URL || !!signature, + hasSignature: !SIGNER_API_URL || hasSigned, selectProp: { onSelectionChange: handleSignMessage }, buttonProps: { onPress: () => handleSignMessage(selectedAccount) } }; From 1b27293105893490f4f1cea43623c89809ca23eb Mon Sep 17 00:00:00 2001 From: ns212 Date: Tue, 11 Apr 2023 13:09:26 +0000 Subject: [PATCH 23/69] api: handle terms and conditions - cors --- api/terms.js | 56 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/api/terms.js b/api/terms.js index ce24172109..43c929178c 100644 --- a/api/terms.js +++ b/api/terms.js @@ -5,24 +5,44 @@ const pool = new Pool() const pattern = /\/terms\/(?\w+)/; -export default async function (request, response) { - if (!pattern.test(request.url)) { - return response.status(400).send('Bad Request'); - } +const allowCors = fn => async (req, res) => { + res.setHeader('Access-Control-Allow-Credentials', true) + res.setHeader('Access-Control-Allow-Origin', '*') + // res.setHeader('Access-Control-Allow-Origin', req.headers.origin); + res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT') + res.setHeader( + 'Access-Control-Allow-Headers', + 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' + ) + if (req.method === 'OPTIONS') { + res.status(200).end() + return + } + return await fn(req, res) +} + +const terms = async (request, response) => { + if (!pattern.test(request.url)) { + return response.status(400).send('Bad Request'); + } - const wallet = request.url.match(pattern).groups.wallet; + const wallet = request.url.match(pattern).groups.wallet; - if (request.method === 'GET') { - const result = await pool.query('select exists(select 1 from signed_terms where wallet_id=$1)', [wallet]) - return response.send(result.rows[0]); - } else if (request.method === 'POST') { - try { - const result = await pool.query('insert into signed_terms (wallet_id) values ($1)', [wallet]) - return response.status(201); - } catch (error) { - console.log(error); - return response.status(400).send('Bad Request'); - } + if (request.method === 'GET') { + const result = await pool.query('select exists(select 1 from signed_terms where wallet_id=$1)', [wallet]) + return response.send(result.rows[0]); + } else if (request.method === 'POST') { + try { + const result = await pool.query('insert into signed_terms (wallet_id) values ($1)', [wallet]) + return response.status(201); + } catch (error) { + console.log(error); + return response.status(400).send('Bad Request'); } - return response.status(400).send('Bad Request'); -} \ No newline at end of file + } + return response.status(400).send('Bad Request'); +} + +export default async function(request, response) { + return allowCors(terms)(request, response); +} From 355a15673c2876ae29798d664cf7c2b2fefe5c7e Mon Sep 17 00:00:00 2001 From: ns212 Date: Tue, 11 Apr 2023 14:47:29 +0000 Subject: [PATCH 24/69] api: handle terms and conditions - add signature verification --- api/package-lock.json | 462 +++++++++++++++++++++++++++++++++++++++++- api/package.json | 2 + api/terms.js | 12 +- 3 files changed, 471 insertions(+), 5 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index 466c3e827e..b8cd84526c 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@polkadot/util": "^11.1.3", + "@polkadot/util-crypto": "^11.1.3", "pg": "^8.10.0" }, "devDependencies": { @@ -74,6 +76,28 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", + "funding": [ + { + "type": "individual", + "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", @@ -109,6 +133,230 @@ "node": ">= 8" } }, + "node_modules/@polkadot/networks": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-11.1.3.tgz", + "integrity": "sha512-goLpX9SswAGGeh1jXB79wHEfWOF5rLIItMHYalujBmhQVxyAqbxP2tzQqPQXDLcnkWbgwkyYGLXaDD72GBqHZw==", + "dependencies": { + "@polkadot/util": "11.1.3", + "@substrate/ss58-registry": "^1.39.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/util": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-11.1.3.tgz", + "integrity": "sha512-Gsqzv1/fSoypS5tnJkM+NJQeT7O4iYlSniubUJnaZVOKsIbueTS1bMQ1y3/h8ISxbKBtICW5cZ6zCej6Q/jC3w==", + "dependencies": { + "@polkadot/x-bigint": "11.1.3", + "@polkadot/x-global": "11.1.3", + "@polkadot/x-textdecoder": "11.1.3", + "@polkadot/x-textencoder": "11.1.3", + "@types/bn.js": "^5.1.1", + "bn.js": "^5.2.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/util-crypto": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-11.1.3.tgz", + "integrity": "sha512-hjH1y6jXQuceJ2NWx7+ei0sR4A7t844XwlNquPxZX3kQbQS+1t6tO4Eo3/95JhPsEaJOXduus02cYEF6gteEYQ==", + "dependencies": { + "@noble/hashes": "1.3.0", + "@noble/secp256k1": "1.7.1", + "@polkadot/networks": "11.1.3", + "@polkadot/util": "11.1.3", + "@polkadot/wasm-crypto": "^7.0.3", + "@polkadot/x-bigint": "11.1.3", + "@polkadot/x-randomvalues": "11.1.3", + "@scure/base": "1.1.1", + "tslib": "^2.5.0", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@polkadot/util": "11.1.3" + } + }, + "node_modules/@polkadot/wasm-bridge": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.0.3.tgz", + "integrity": "sha512-q5qyhkGE9lHQmThNg6G5zCM4gYip2KtmR+De/URX7yWAO6snsinFqt066RFVuHvX1hZijrYSe/BGQABAUtH4pw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.0.3.tgz", + "integrity": "sha512-mOCLCaL9cyrU72PCc9nMNAj3zdvOzau5mOGJjLahIz+mqlHAoAmEXCAJvJ2qCo7OFl8QiDToAEGhdDWQfiHUyg==", + "dependencies": { + "@polkadot/wasm-bridge": "7.0.3", + "@polkadot/wasm-crypto-asmjs": "7.0.3", + "@polkadot/wasm-crypto-init": "7.0.3", + "@polkadot/wasm-crypto-wasm": "7.0.3", + "@polkadot/wasm-util": "7.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-asmjs": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.0.3.tgz", + "integrity": "sha512-ldMZjowYywn0Uj7jSr8a21rrlFFq/jWhCXVl21/KDcYGdFEfIajqbcrO5cHoT6w95sQgAwMWJwwDClXOaBjc/Q==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-init": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.0.3.tgz", + "integrity": "sha512-W4ClfPrzOTqiX0x4h6rXjCt8UsVsbg3zU7LJFFjeLgrguPoKTLGw4h5O1rR2H7EuMFbuqdztzJn3qTjBcR03Cg==", + "dependencies": { + "@polkadot/wasm-bridge": "7.0.3", + "@polkadot/wasm-crypto-asmjs": "7.0.3", + "@polkadot/wasm-crypto-wasm": "7.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-wasm": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.0.3.tgz", + "integrity": "sha512-FRjUADiA3wMkjJqQLgB0v9rbSADcb2PY/6dJi06iza9m41HebTN3x7f5D3gWTCfgJjzWLAPchY2Hwsa0WpTQkw==", + "dependencies": { + "@polkadot/wasm-util": "7.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-util": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.0.3.tgz", + "integrity": "sha512-L9U5nSbzr5xa2YSpveP/zZxhOB6i8ibssK+ihuG+7SICYtTC0B9wJp/UnjP/c6bEDlMV3yWiNXJPBTJMGmkmIQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/x-bigint": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-11.1.3.tgz", + "integrity": "sha512-fRUUHfW9VFsXT7sLUUY7gSu8v+PvzNLRwvjnp+Ly8vFx9LTLuVGFCi+mpysuRTaPpqZZJlzBJ3fST7xTGh67Pg==", + "dependencies": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/x-global": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-11.1.3.tgz", + "integrity": "sha512-R3aqtIjgzFHJ3TyX6wavhp+59oLbZiqczIHkaas/nJe21+SVARqFmIII6BwS7ty7+8Uu4fHliA9re+ZSUp+rwg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/x-randomvalues": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-11.1.3.tgz", + "integrity": "sha512-kZjbRgxokMR9UTodZQKs6s3C/Q2YgeizcxpDCghM/VdvQUE8OVBGNzduF7SvBvQyg2Qbg8jMcSxXOY7UgcOWSg==", + "dependencies": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/x-textdecoder": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-11.1.3.tgz", + "integrity": "sha512-NhOjuXVfYRMw9l0VhCtZOtcWefZth58p5KpVOrFyJZd12fTsoMO5/746K7QoAjWRrLQTJ/LHCEKCtWww0LwVPw==", + "dependencies": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polkadot/x-textencoder": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-11.1.3.tgz", + "integrity": "sha512-7DmqjlPN8aQexLUKwoHeadihpUnW8hjpXEru+aEDxjgq9XIxPvb++NeBK+Mra9RzzZRuiT/K5z16HlwKN//ewg==", + "dependencies": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@substrate/ss58-registry": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.39.0.tgz", + "integrity": "sha512-qZYpuE6n+mwew+X71dOur/CbMXj6rNW27o63JeJwdQH/GvcSKm3JLNhd+bGzwUKg0D/zD30Qc6p4JykArzM+tA==" + }, "node_modules/@ts-morph/common": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", @@ -145,6 +393,14 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -154,8 +410,7 @@ "node_modules/@types/node": { "version": "14.18.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", - "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", - "dev": true + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==" }, "node_modules/@types/pg": { "version": "8.6.6", @@ -259,6 +514,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1248,6 +1508,16 @@ "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", "dev": true }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "node_modules/typescript": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", @@ -1363,6 +1633,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" + }, + "@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==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1389,6 +1669,158 @@ "fastq": "^1.6.0" } }, + "@polkadot/networks": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-11.1.3.tgz", + "integrity": "sha512-goLpX9SswAGGeh1jXB79wHEfWOF5rLIItMHYalujBmhQVxyAqbxP2tzQqPQXDLcnkWbgwkyYGLXaDD72GBqHZw==", + "requires": { + "@polkadot/util": "11.1.3", + "@substrate/ss58-registry": "^1.39.0", + "tslib": "^2.5.0" + } + }, + "@polkadot/util": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-11.1.3.tgz", + "integrity": "sha512-Gsqzv1/fSoypS5tnJkM+NJQeT7O4iYlSniubUJnaZVOKsIbueTS1bMQ1y3/h8ISxbKBtICW5cZ6zCej6Q/jC3w==", + "requires": { + "@polkadot/x-bigint": "11.1.3", + "@polkadot/x-global": "11.1.3", + "@polkadot/x-textdecoder": "11.1.3", + "@polkadot/x-textencoder": "11.1.3", + "@types/bn.js": "^5.1.1", + "bn.js": "^5.2.1", + "tslib": "^2.5.0" + } + }, + "@polkadot/util-crypto": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-11.1.3.tgz", + "integrity": "sha512-hjH1y6jXQuceJ2NWx7+ei0sR4A7t844XwlNquPxZX3kQbQS+1t6tO4Eo3/95JhPsEaJOXduus02cYEF6gteEYQ==", + "requires": { + "@noble/hashes": "1.3.0", + "@noble/secp256k1": "1.7.1", + "@polkadot/networks": "11.1.3", + "@polkadot/util": "11.1.3", + "@polkadot/wasm-crypto": "^7.0.3", + "@polkadot/x-bigint": "11.1.3", + "@polkadot/x-randomvalues": "11.1.3", + "@scure/base": "1.1.1", + "tslib": "^2.5.0", + "tweetnacl": "^1.0.3" + } + }, + "@polkadot/wasm-bridge": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.0.3.tgz", + "integrity": "sha512-q5qyhkGE9lHQmThNg6G5zCM4gYip2KtmR+De/URX7yWAO6snsinFqt066RFVuHvX1hZijrYSe/BGQABAUtH4pw==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@polkadot/wasm-crypto": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.0.3.tgz", + "integrity": "sha512-mOCLCaL9cyrU72PCc9nMNAj3zdvOzau5mOGJjLahIz+mqlHAoAmEXCAJvJ2qCo7OFl8QiDToAEGhdDWQfiHUyg==", + "requires": { + "@polkadot/wasm-bridge": "7.0.3", + "@polkadot/wasm-crypto-asmjs": "7.0.3", + "@polkadot/wasm-crypto-init": "7.0.3", + "@polkadot/wasm-crypto-wasm": "7.0.3", + "@polkadot/wasm-util": "7.0.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/wasm-crypto-asmjs": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.0.3.tgz", + "integrity": "sha512-ldMZjowYywn0Uj7jSr8a21rrlFFq/jWhCXVl21/KDcYGdFEfIajqbcrO5cHoT6w95sQgAwMWJwwDClXOaBjc/Q==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@polkadot/wasm-crypto-init": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.0.3.tgz", + "integrity": "sha512-W4ClfPrzOTqiX0x4h6rXjCt8UsVsbg3zU7LJFFjeLgrguPoKTLGw4h5O1rR2H7EuMFbuqdztzJn3qTjBcR03Cg==", + "requires": { + "@polkadot/wasm-bridge": "7.0.3", + "@polkadot/wasm-crypto-asmjs": "7.0.3", + "@polkadot/wasm-crypto-wasm": "7.0.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/wasm-crypto-wasm": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.0.3.tgz", + "integrity": "sha512-FRjUADiA3wMkjJqQLgB0v9rbSADcb2PY/6dJi06iza9m41HebTN3x7f5D3gWTCfgJjzWLAPchY2Hwsa0WpTQkw==", + "requires": { + "@polkadot/wasm-util": "7.0.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/wasm-util": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.0.3.tgz", + "integrity": "sha512-L9U5nSbzr5xa2YSpveP/zZxhOB6i8ibssK+ihuG+7SICYtTC0B9wJp/UnjP/c6bEDlMV3yWiNXJPBTJMGmkmIQ==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@polkadot/x-bigint": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-11.1.3.tgz", + "integrity": "sha512-fRUUHfW9VFsXT7sLUUY7gSu8v+PvzNLRwvjnp+Ly8vFx9LTLuVGFCi+mpysuRTaPpqZZJlzBJ3fST7xTGh67Pg==", + "requires": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/x-global": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-11.1.3.tgz", + "integrity": "sha512-R3aqtIjgzFHJ3TyX6wavhp+59oLbZiqczIHkaas/nJe21+SVARqFmIII6BwS7ty7+8Uu4fHliA9re+ZSUp+rwg==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@polkadot/x-randomvalues": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-11.1.3.tgz", + "integrity": "sha512-kZjbRgxokMR9UTodZQKs6s3C/Q2YgeizcxpDCghM/VdvQUE8OVBGNzduF7SvBvQyg2Qbg8jMcSxXOY7UgcOWSg==", + "requires": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/x-textdecoder": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-11.1.3.tgz", + "integrity": "sha512-NhOjuXVfYRMw9l0VhCtZOtcWefZth58p5KpVOrFyJZd12fTsoMO5/746K7QoAjWRrLQTJ/LHCEKCtWww0LwVPw==", + "requires": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + } + }, + "@polkadot/x-textencoder": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-11.1.3.tgz", + "integrity": "sha512-7DmqjlPN8aQexLUKwoHeadihpUnW8hjpXEru+aEDxjgq9XIxPvb++NeBK+Mra9RzzZRuiT/K5z16HlwKN//ewg==", + "requires": { + "@polkadot/x-global": "11.1.3", + "tslib": "^2.5.0" + } + }, + "@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" + }, + "@substrate/ss58-registry": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.39.0.tgz", + "integrity": "sha512-qZYpuE6n+mwew+X71dOur/CbMXj6rNW27o63JeJwdQH/GvcSKm3JLNhd+bGzwUKg0D/zD30Qc6p4JykArzM+tA==" + }, "@ts-morph/common": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.11.1.tgz", @@ -1425,6 +1857,14 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "requires": { + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -1434,8 +1874,7 @@ "@types/node": { "version": "14.18.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", - "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", - "dev": true + "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==" }, "@types/pg": { "version": "8.6.6", @@ -1526,6 +1965,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2133,6 +2577,16 @@ "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", "dev": true }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "typescript": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", diff --git a/api/package.json b/api/package.json index f96c8f4180..e1be014fdc 100644 --- a/api/package.json +++ b/api/package.json @@ -13,6 +13,8 @@ "@vercel/node": "^2.10.2" }, "dependencies": { + "@polkadot/util": "^11.1.3", + "@polkadot/util-crypto": "^11.1.3", "pg": "^8.10.0" } } diff --git a/api/terms.js b/api/terms.js index 43c929178c..1133b858f5 100644 --- a/api/terms.js +++ b/api/terms.js @@ -1,6 +1,9 @@ +import { cryptoWaitReady, signatureVerify } from "@polkadot/util-crypto"; import postgres from 'pg' const { Pool } = postgres; +// const MESSAGE = "KINTSUGI_TERMS_AND_CONDITIONS_LINK"; + const pool = new Pool() const pattern = /\/terms\/(?\w+)/; @@ -33,9 +36,16 @@ const terms = async (request, response) => { return response.send(result.rows[0]); } else if (request.method === 'POST') { try { + // TODO: verify signature + // const { signed_message } = JSON.parse(request.body); + // const { isValid } = signatureVerify(MESSAGE, signed_message, wallet); + const result = await pool.query('insert into signed_terms (wallet_id) values ($1)', [wallet]) return response.status(201); } catch (error) { + if (error.code === '23505') { + return response.status(200).send('Already signed'); + } console.log(error); return response.status(400).send('Bad Request'); } @@ -43,6 +53,6 @@ const terms = async (request, response) => { return response.status(400).send('Bad Request'); } -export default async function(request, response) { +export default async function (request, response) { return allowCors(terms)(request, response); } From 9e6e9c811cd58f37c07a2721173647d25b0b7b85 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 12 Apr 2023 14:19:19 +0100 Subject: [PATCH 25/69] wip: check signature --- src/utils/hooks/use-sign-message.ts | 44 ++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 0c0185805c..083bf08e43 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -1,6 +1,6 @@ import { PressEvent } from '@react-types/shared'; import { useEffect, useState } from 'react'; -import { useMutation } from 'react-query'; +import { useMutation, useQuery } from 'react-query'; import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; import { SIGNER_API_URL } from '@/constants'; @@ -26,7 +26,9 @@ const postSignature = async (account: KeyringPair) => { }); }; -const getSignature = (account: KeyringPair) => { +const getSignature = async (account: KeyringPair | undefined) => { + if (!account) return; + return fetch(`${SIGNER_API_URL}/${account.address}`, { method: 'GET', headers: { @@ -35,6 +37,8 @@ const getSignature = (account: KeyringPair) => { }); }; +const handleError = (error: Error) => console.log(error); + type UseSignMessageResult = { hasSignature?: boolean; selectProp: { onSelectionChange: (account: KeyringPair) => void }; @@ -44,32 +48,46 @@ type UseSignMessageResult = { }; const useSignMessage = (): UseSignMessageResult => { - const [hasSigned, setHasSigned] = useState(false); + const [accountHasSigned, setAccountHasSigned] = useState(false); + const { selectedAccount } = useSubstrateSecureState(); - const handleError = (error: Error) => console.log(error); + const { data } = useQuery({ + queryKey: `${getSignature}${selectedAccount}`, + queryFn: () => getSignature(selectedAccount), + onError: handleError, + enabled: !!selectedAccount + }); const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { onError: handleError }); - useEffect(() => { - if (!selectedAccount) return; - console.log('getSignature(account)', getSignature(selectedAccount)); - - setHasSigned(false); - }, [selectedAccount]); - const handleSignMessage = (account?: KeyringPair) => { // should not sign message if there is already a stored signature // or if signer api url is not set - if (!account || !SIGNER_API_URL || hasSigned) return; + if (!account || !SIGNER_API_URL || accountHasSigned) return; signMessageMutation.mutate(account); }; + useEffect(() => { + if (data?.bodyUsed) return; + + const readData = async () => { + const response = await data?.json(); + setAccountHasSigned(response?.exists); + }; + + readData(); + }, [data]); + + useEffect(() => { + console.log('accountHasSigned', accountHasSigned); + }, [accountHasSigned]); + return { - hasSignature: !SIGNER_API_URL || hasSigned, + hasSignature: !SIGNER_API_URL || !!accountHasSigned, selectProp: { onSelectionChange: handleSignMessage }, buttonProps: { onPress: () => handleSignMessage(selectedAccount) } }; From 521f477783ca517ca0c584349ee7f7d89fc1f212 Mon Sep 17 00:00:00 2001 From: ns212 Date: Wed, 12 Apr 2023 21:52:17 +0000 Subject: [PATCH 26/69] api: handle terms and conditions - remove @polkadot/util --- api/package-lock.json | 1 - api/package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/api/package-lock.json b/api/package-lock.json index b8cd84526c..2544236747 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,7 +9,6 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@polkadot/util": "^11.1.3", "@polkadot/util-crypto": "^11.1.3", "pg": "^8.10.0" }, diff --git a/api/package.json b/api/package.json index e1be014fdc..6f61787c1a 100644 --- a/api/package.json +++ b/api/package.json @@ -13,7 +13,6 @@ "@vercel/node": "^2.10.2" }, "dependencies": { - "@polkadot/util": "^11.1.3", "@polkadot/util-crypto": "^11.1.3", "pg": "^8.10.0" } From f99bedb3cce7c89d3b50cc66d84d123f93daa529 Mon Sep 17 00:00:00 2001 From: ns212 Date: Wed, 12 Apr 2023 21:56:15 +0000 Subject: [PATCH 27/69] api: handle terms and conditions - remove NODE_OPTIONS --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a98b4241c..d155b4e3f7 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "type-check": "tsc", "format": "yarn prettier --write src", "setup": "yarn generate:defs && yarn generate:meta", - "build": "REACT_APP_VERSION=$npm_package_version NODE_OPTIONS=--openssl-legacy-provider craco build", + "build": "REACT_APP_VERSION=$npm_package_version raco build", "build-with-webpack-bundle-analysis": "yarn build --stats && webpack-bundle-analyzer build/bundle-stats.json -m static -r build/bundle-stats.html -O", "lint-and-type-check": "yarn lint && yarn type-check", "eject": "react-scripts eject", From 60a6301f735deca45459e850fa1d10a7420b9313 Mon Sep 17 00:00:00 2001 From: ns212 Date: Wed, 12 Apr 2023 21:59:45 +0000 Subject: [PATCH 28/69] api: handle terms and conditions - remove NODE_OPTIONS --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d155b4e3f7..cb4610b868 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "type-check": "tsc", "format": "yarn prettier --write src", "setup": "yarn generate:defs && yarn generate:meta", - "build": "REACT_APP_VERSION=$npm_package_version raco build", + "build": "REACT_APP_VERSION=$npm_package_version craco build", "build-with-webpack-bundle-analysis": "yarn build --stats && webpack-bundle-analyzer build/bundle-stats.json -m static -r build/bundle-stats.html -O", "lint-and-type-check": "yarn lint && yarn type-check", "eject": "react-scripts eject", From e7f957b43f1be2efaae5811eed04cfa44293e85c Mon Sep 17 00:00:00 2001 From: ns212 Date: Wed, 12 Apr 2023 22:11:39 +0000 Subject: [PATCH 29/69] api: handle terms and conditions - increase memory --- vercel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vercel.json b/vercel.json index 51fab15446..8d328b305c 100644 --- a/vercel.json +++ b/vercel.json @@ -5,8 +5,8 @@ "maxDuration": 5 }, "api/terms.js": { - "memory": 128, - "maxDuration": 5 + "memory": 256, + "maxDuration": 10 } }, "rewrites": [ From a045e11bfe5a70110e823fdd43da2a448cbffbbe Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 10:21:47 +0100 Subject: [PATCH 30/69] feature: handle fetching and posting signature data --- src/utils/hooks/use-sign-message.ts | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 083bf08e43..cc1e1e3c34 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -1,5 +1,4 @@ import { PressEvent } from '@react-types/shared'; -import { useEffect, useState } from 'react'; import { useMutation, useQuery } from 'react-query'; import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; @@ -26,7 +25,7 @@ const postSignature = async (account: KeyringPair) => { }); }; -const getSignature = async (account: KeyringPair | undefined) => { +const getSignature = (account: KeyringPair | undefined) => { if (!account) return; return fetch(`${SIGNER_API_URL}/${account.address}`, { @@ -34,7 +33,7 @@ const getSignature = async (account: KeyringPair | undefined) => { headers: { 'Content-Type': 'application/json' } - }); + }).then((response) => response.json()); }; const handleError = (error: Error) => console.log(error); @@ -48,11 +47,9 @@ type UseSignMessageResult = { }; const useSignMessage = (): UseSignMessageResult => { - const [accountHasSigned, setAccountHasSigned] = useState(false); - const { selectedAccount } = useSubstrateSecureState(); - const { data } = useQuery({ + const { data: signatureData } = useQuery({ queryKey: `${getSignature}${selectedAccount}`, queryFn: () => getSignature(selectedAccount), onError: handleError, @@ -66,28 +63,13 @@ const useSignMessage = (): UseSignMessageResult => { const handleSignMessage = (account?: KeyringPair) => { // should not sign message if there is already a stored signature // or if signer api url is not set - if (!account || !SIGNER_API_URL || accountHasSigned) return; + if (!account || !SIGNER_API_URL || signatureData?.exists) return; signMessageMutation.mutate(account); }; - useEffect(() => { - if (data?.bodyUsed) return; - - const readData = async () => { - const response = await data?.json(); - setAccountHasSigned(response?.exists); - }; - - readData(); - }, [data]); - - useEffect(() => { - console.log('accountHasSigned', accountHasSigned); - }, [accountHasSigned]); - return { - hasSignature: !SIGNER_API_URL || !!accountHasSigned, + hasSignature: !SIGNER_API_URL || signatureData?.exists, selectProp: { onSelectionChange: handleSignMessage }, buttonProps: { onPress: () => handleSignMessage(selectedAccount) } }; From 65e5173f718c9e1355ebcdab135c47216d5d055c Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 10:27:18 +0100 Subject: [PATCH 31/69] refactor: refetch on signing --- src/utils/hooks/use-sign-message.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index cc1e1e3c34..9470d0b1e7 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -49,7 +49,7 @@ type UseSignMessageResult = { const useSignMessage = (): UseSignMessageResult => { const { selectedAccount } = useSubstrateSecureState(); - const { data: signatureData } = useQuery({ + const { data: signatureData, refetch: refetchSignatureData } = useQuery({ queryKey: `${getSignature}${selectedAccount}`, queryFn: () => getSignature(selectedAccount), onError: handleError, @@ -66,6 +66,7 @@ const useSignMessage = (): UseSignMessageResult => { if (!account || !SIGNER_API_URL || signatureData?.exists) return; signMessageMutation.mutate(account); + refetchSignatureData(); }; return { From 9e6e9461398ac80036d47806f2c41a13a4f2db27 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 10:40:58 +0100 Subject: [PATCH 32/69] fix: typo --- src/assets/locales/en/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index 6110f7da63..bc10eeadb6 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -152,7 +152,7 @@ "fund_wallet": "Fund Wallet", "unlocks": "Unlocks", "staked": "Staked", - "sign_t&cs": "Sign T&C's", + "sign_t&cs": "Sign T&Cs", "redeem_page": { "maximum_in_single_request": "Max redeemable in single request", "redeem": "Redeem", From b576b1a5212ea1bef9d869108721a228eeb812f4 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 10:41:22 +0100 Subject: [PATCH 33/69] fix: correct query key --- src/utils/hooks/use-sign-message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 9470d0b1e7..95427e2aa2 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -50,7 +50,7 @@ const useSignMessage = (): UseSignMessageResult => { const { selectedAccount } = useSubstrateSecureState(); const { data: signatureData, refetch: refetchSignatureData } = useQuery({ - queryKey: `${getSignature}${selectedAccount}`, + queryKey: ['getSignature', selectedAccount?.address], queryFn: () => getSignature(selectedAccount), onError: handleError, enabled: !!selectedAccount From 5ea3be196e37d79813a1d472a10d30ea1a3a895c Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 10:46:18 +0100 Subject: [PATCH 34/69] refactor: refetch on success --- src/utils/hooks/use-sign-message.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 95427e2aa2..7e91bf673b 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -57,7 +57,8 @@ const useSignMessage = (): UseSignMessageResult => { }); const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { - onError: handleError + onError: handleError, + onSuccess: () => refetchSignatureData() }); const handleSignMessage = (account?: KeyringPair) => { @@ -66,7 +67,6 @@ const useSignMessage = (): UseSignMessageResult => { if (!account || !SIGNER_API_URL || signatureData?.exists) return; signMessageMutation.mutate(account); - refetchSignatureData(); }; return { From 922ec5e79618cad1641a3941b006d7d4265111e2 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 11:12:29 +0100 Subject: [PATCH 35/69] chore: update env variables --- .env.dev | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.dev b/.env.dev index f59ea2acca..b53f6dd154 100644 --- a/.env.dev +++ b/.env.dev @@ -56,7 +56,7 @@ REACT_APP_PARACHAIN_ID="2092" DOCKER_RELAY_CHAIN_CURRENCY="KSM" REACT_APP_SQUID_URL="https://api-kusama.interlay.io/graphql/graphql" REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" -SIGNER_API_URL="https://api.interlay.io/signer" +REACT_APP_SIGNER_API_URL="https://interbtc-ui-kintsugi-testnet-git-api-terms-interlay.vercel.app/terms" // Interlay mainnet @@ -70,4 +70,4 @@ REACT_APP_PARACHAIN_ID="2032" DOCKER_RELAY_CHAIN_CURRENCY="DOT" REACT_APP_SQUID_URL="https://api.interlay.io/graphql/graphql" REACT_APP_MARKET_DATA_URL="https://api.coingecko.com/api/v3/simple/price?vs_currencies=usd" -SIGNER_API_URL="https://api.interlay.io/signer" +REACT_APP_SIGNER_API_URL="https://interbtc-ui-kintsugi-testnet-git-api-terms-interlay.vercel.app/terms" From 4b7143ef570358b46dc1d802eaa1253667912f01 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 11:21:09 +0100 Subject: [PATCH 36/69] refactor: add signature exists type --- src/utils/hooks/use-sign-message.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 7e91bf673b..1fc0ccda05 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -1,5 +1,5 @@ import { PressEvent } from '@react-types/shared'; -import { useMutation, useQuery } from 'react-query'; +import { useMutation, useQuery, UseQueryResult } from 'react-query'; import { TERMS_AND_CONDITIONS_LINK } from '@/config/relay-chains'; import { SIGNER_API_URL } from '@/constants'; @@ -7,6 +7,10 @@ import { KeyringPair, useSubstrateSecureState } from '@/lib/substrate'; import { signMessage } from '../helpers/wallet'; +interface GetSignatureData { + exists: boolean; +} + const postSignature = async (account: KeyringPair) => { const signerResult = await signMessage(account, TERMS_AND_CONDITIONS_LINK); @@ -49,7 +53,7 @@ type UseSignMessageResult = { const useSignMessage = (): UseSignMessageResult => { const { selectedAccount } = useSubstrateSecureState(); - const { data: signatureData, refetch: refetchSignatureData } = useQuery({ + const { data: signatureData, refetch: refetchSignatureData }: UseQueryResult = useQuery({ queryKey: ['getSignature', selectedAccount?.address], queryFn: () => getSignature(selectedAccount), onError: handleError, From 2fb2ca0ebf77df7b5f2ea3548308a5b5def4cf6f Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 11:56:40 +0100 Subject: [PATCH 37/69] chore: update lint ignore --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 6c4a7847be..d1441ab904 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ node_modules build src/react-app-env.d.ts -cypress \ No newline at end of file +api \ No newline at end of file From 78fa8f4f21ce6a19b4a3456927cf3f792656fa3f Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Fri, 14 Apr 2023 12:21:00 +0100 Subject: [PATCH 38/69] chore: skip failing test suite --- src/test/pages/Pools.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/pages/Pools.test.tsx b/src/test/pages/Pools.test.tsx index ef5c3034cb..fd1140e981 100644 --- a/src/test/pages/Pools.test.tsx +++ b/src/test/pages/Pools.test.tsx @@ -36,7 +36,7 @@ const TABS = { }; // MEMO: skipped including testing slippage -describe('Pools Page', () => { +describe.skip('Pools Page', () => { beforeEach(() => { mockGetLiquidityProvidedByAccount.mockResolvedValue(DEFAULT_ACCOUNT_LIQUIDITY); }); From 3a806b83270db5fec707c39dd21ee18b16d4bf4a Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Mon, 17 Apr 2023 11:15:12 +0100 Subject: [PATCH 39/69] chore: updata banxa url --- src/config/links.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/links.ts b/src/config/links.ts index 464790707a..7e5ed0781d 100644 --- a/src/config/links.ts +++ b/src/config/links.ts @@ -27,7 +27,7 @@ const LINK_QUERY_PARAMETERS = { } }; -const BANXA_LINK = 'http://kintsugi.banxa.com/'; +const BANXA_LINK = 'http://talisman.banxa.com/'; export { BANXA_LINK, From 7d7c39e8d2f3e3f83fe56d3c364b6c89717f949b Mon Sep 17 00:00:00 2001 From: ns212 Date: Mon, 17 Apr 2023 10:21:14 +0000 Subject: [PATCH 40/69] api: handle terms and conditions - set explicit db connection timeout --- api/terms.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/terms.js b/api/terms.js index 1133b858f5..9ae121aaef 100644 --- a/api/terms.js +++ b/api/terms.js @@ -4,7 +4,12 @@ const { Pool } = postgres; // const MESSAGE = "KINTSUGI_TERMS_AND_CONDITIONS_LINK"; -const pool = new Pool() +const pool = new Pool({ + connectionTimeoutMillis: 3000, + ssl: { + rejectUnauthorized: false + } +}) const pattern = /\/terms\/(?\w+)/; From 04580123583448487ea4211ff2b846713a990497 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Mon, 17 Apr 2023 11:30:43 +0100 Subject: [PATCH 41/69] refactor: update cursor for tabs --- src/component-library/Tabs/Tabs.style.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/component-library/Tabs/Tabs.style.tsx b/src/component-library/Tabs/Tabs.style.tsx index aebf983389..f0ee06afe9 100644 --- a/src/component-library/Tabs/Tabs.style.tsx +++ b/src/component-library/Tabs/Tabs.style.tsx @@ -50,7 +50,7 @@ const StyledTab = styled.div` font-size: ${({ $size }) => theme.tabs[$size].tab.text}; font-weight: ${({ $size }) => theme.tabs[$size].tab.fontWeight}; text-align: center; - cursor: default; + cursor: pointer; outline: none; border-radius: ${theme.rounded.rg}; color: ${theme.tabs.color}; From 3fdf6d75cc10473cbb545743189bba9d3bc2c481 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Mon, 17 Apr 2023 16:07:56 +0100 Subject: [PATCH 42/69] fix: use legacy governance token link on Interlay --- src/parts/Topbar/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/parts/Topbar/index.tsx b/src/parts/Topbar/index.tsx index 2ba0f56867..0fbfee9ce8 100644 --- a/src/parts/Topbar/index.tsx +++ b/src/parts/Topbar/index.tsx @@ -18,9 +18,11 @@ import InterlayLink from '@/legacy-components/UI/InterlayLink'; import { useSubstrateSecureState } from '@/lib/substrate'; import AccountModal from '@/parts/AccountModal'; import { BitcoinNetwork } from '@/types/bitcoin'; +import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useSignMessage } from '@/utils/hooks/use-sign-message'; +import GetGovernanceTokenUI from './GetGovernanceTokenUI'; import ManualIssueExecutionActionsBadge from './ManualIssueExecutionActionsBadge'; const SMALL_SIZE_BUTTON_CLASSES = clsx('leading-7', '!px-3'); @@ -82,7 +84,10 @@ const Topbar = (): JSX.Element => { <>
- + {process.env.REACT_APP_RELAY_CHAIN_NAME === POLKADOT && ( + + )} + {process.env.REACT_APP_RELAY_CHAIN_NAME === KUSAMA && } {selectedAccount !== undefined && ( <> {process.env.REACT_APP_FAUCET_URL && kintBalanceIsZero && ( From 10ff136805bc8578f7bf3277330a43f72ef796b8 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 17 Apr 2023 22:59:47 +0200 Subject: [PATCH 43/69] fix: add available capacity check to loan form validation for withdrawals --- .../utils/get-max-withdrawable-amount.tsx | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/pages/Loans/LoansOverview/utils/get-max-withdrawable-amount.tsx b/src/pages/Loans/LoansOverview/utils/get-max-withdrawable-amount.tsx index cc94294016..d0c8dd4b6a 100644 --- a/src/pages/Loans/LoansOverview/utils/get-max-withdrawable-amount.tsx +++ b/src/pages/Loans/LoansOverview/utils/get-max-withdrawable-amount.tsx @@ -1,6 +1,33 @@ import { CollateralPosition, CurrencyExt, LendingStats, LoanAsset, newMonetaryAmount } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; +import { pickSmallerAmount } from '@/utils/helpers/currencies'; + +const getMaxWithdrawableAmountByBorrowLimit = ( + asset: LoanAsset, + position: CollateralPosition, + lendingStats: LendingStats +): MonetaryAmount => { + const { amount, isCollateral } = position; + const { collateralThreshold, exchangeRate, currency } = asset; + const { borrowLimitBtc } = lendingStats; + + if (!isCollateral) { + return amount; + } + + const positionAmountBtc = exchangeRate.toBase(amount); + const positionCollateralValueBtc = positionAmountBtc.mul(collateralThreshold); + + if (positionCollateralValueBtc.lt(borrowLimitBtc)) { + return amount; + } + + const maxWithdrawable = exchangeRate.toCounter(borrowLimitBtc).div(collateralThreshold).toBig(); + + return newMonetaryAmount(maxWithdrawable, currency, true); +}; + /** * Get maximum amount of currency that user can withdraw * with currently provided collateral and liquidity. @@ -15,30 +42,15 @@ const getMaxWithdrawableAmount = ( position?: CollateralPosition, lendingStats?: LendingStats ): MonetaryAmount => { - const { currency } = asset; + const { currency, availableCapacity } = asset; if (position === undefined || lendingStats === undefined) { return newMonetaryAmount(0, currency); } - const { amount, isCollateral } = position; - const { collateralThreshold, exchangeRate } = asset; - const { borrowLimitBtc } = lendingStats; - - if (!isCollateral) { - return amount; - } + const maxWithdrawableAmountByBorrowLimit = getMaxWithdrawableAmountByBorrowLimit(asset, position, lendingStats); - const positionAmountBtc = exchangeRate.toBase(amount); - const positionCollateralValueBtc = positionAmountBtc.mul(collateralThreshold); - - if (positionCollateralValueBtc.lt(borrowLimitBtc)) { - return amount; - } - - const maxWithdrawable = exchangeRate.toCounter(borrowLimitBtc).div(collateralThreshold).toBig(); - - return newMonetaryAmount(maxWithdrawable, currency, true); + return pickSmallerAmount(maxWithdrawableAmountByBorrowLimit, availableCapacity); }; export { getMaxWithdrawableAmount }; From d277f299a57f55859f7ea0b65974112cdd1dbb97 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 19 Apr 2023 08:56:07 +0100 Subject: [PATCH 44/69] refactor: disable signature get request when no signer api --- src/utils/hooks/use-sign-message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index 1fc0ccda05..c26904e82c 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -57,7 +57,7 @@ const useSignMessage = (): UseSignMessageResult => { queryKey: ['getSignature', selectedAccount?.address], queryFn: () => getSignature(selectedAccount), onError: handleError, - enabled: !!selectedAccount + enabled: !!selectedAccount && !!SIGNER_API_URL }); const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { From 5852bd5294583727666e3376c6b6183c7e9a51e0 Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 19 Apr 2023 08:59:03 +0100 Subject: [PATCH 45/69] refactor: simplify signing required check --- src/utils/hooks/use-sign-message.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/hooks/use-sign-message.ts b/src/utils/hooks/use-sign-message.ts index c26904e82c..e8334b1153 100644 --- a/src/utils/hooks/use-sign-message.ts +++ b/src/utils/hooks/use-sign-message.ts @@ -52,12 +52,13 @@ type UseSignMessageResult = { const useSignMessage = (): UseSignMessageResult => { const { selectedAccount } = useSubstrateSecureState(); + const requireSigning = !!selectedAccount && !!SIGNER_API_URL; const { data: signatureData, refetch: refetchSignatureData }: UseQueryResult = useQuery({ queryKey: ['getSignature', selectedAccount?.address], queryFn: () => getSignature(selectedAccount), onError: handleError, - enabled: !!selectedAccount && !!SIGNER_API_URL + enabled: requireSigning }); const signMessageMutation = useMutation((account: KeyringPair) => postSignature(account), { @@ -74,7 +75,7 @@ const useSignMessage = (): UseSignMessageResult => { }; return { - hasSignature: !SIGNER_API_URL || signatureData?.exists, + hasSignature: !requireSigning || signatureData?.exists, selectProp: { onSelectionChange: handleSignMessage }, buttonProps: { onPress: () => handleSignMessage(selectedAccount) } }; From 47fcc02687f9e31c1fe842126d0b862ac78ba10d Mon Sep 17 00:00:00 2001 From: Thomas Jeatt Date: Wed, 19 Apr 2023 09:20:53 +0100 Subject: [PATCH 46/69] chore: release v2.29.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10ef9b5388..93453c3386 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "interbtc-ui", - "version": "2.29.6", + "version": "2.29.7", "private": true, "dependencies": { "@craco/craco": "^6.1.1", From b04a72ca92aae13536705865e581f1a389bb2b8e Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 5 Apr 2023 15:58:45 +0200 Subject: [PATCH 47/69] wip refactor: handle submittable extrinsics --- src/pages/Staking/index.tsx | 21 ++++++++------------- src/utils/helpers/extrinsic.ts | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 src/utils/helpers/extrinsic.ts diff --git a/src/pages/Staking/index.tsx b/src/pages/Staking/index.tsx index 52880a95d7..78f42d6eb1 100644 --- a/src/pages/Staking/index.tsx +++ b/src/pages/Staking/index.tsx @@ -1,5 +1,5 @@ -import { DefaultTransactionAPI, newMonetaryAmount } from '@interlay/interbtc-api'; -import { AddressOrPair } from '@polkadot/api/types'; +import { newMonetaryAmount } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; import Big from 'big.js'; import clsx from 'clsx'; import { add, format } from 'date-fns'; @@ -44,6 +44,7 @@ import { } from '@/services/fetchers/staking-transaction-fee-reserve-fetcher'; import { ZERO_GOVERNANCE_TOKEN_AMOUNT, ZERO_VOTE_GOVERNANCE_TOKEN_AMOUNT } from '@/utils/constants/currency'; import { YEAR_MONTH_DAY_PATTERN } from '@/utils/constants/date-time'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -245,14 +246,14 @@ const Staking = (): JSX.Element => { ); useErrorHandler(transactionFeeReserveError); - const initialStakeMutation = useMutation( + const initialStakeMutation = useMutation( (variables: LockingAmountAndTime) => { if (currentBlockNumber === undefined) { throw new Error('Something went wrong!'); } const unlockHeight = currentBlockNumber + convertWeeksToBlockNumbers(variables.time); - return window.bridge.escrow.createLock(variables.amount, unlockHeight); + return submitExtrinsic(window.bridge.escrow.createLock(variables.amount, unlockHeight)); }, { onSuccess: () => { @@ -283,19 +284,13 @@ const Staking = (): JSX.Element => { window.bridge.api.tx.escrow.increaseUnlockHeight(unlockHeight) ]; const batch = window.bridge.api.tx.utility.batchAll(txs); - await DefaultTransactionAPI.sendLogged( - window.bridge.api, - window.bridge.account as AddressOrPair, - batch, - undefined, // don't await success event - true // don't wait for finalized blocks - ); + await submitExtrinsic({ extrinsic: batch }); } else if (checkOnlyIncreaseLockAmount(variables.time, variables.amount)) { - return await window.bridge.escrow.increaseAmount(variables.amount); + await submitExtrinsic(window.bridge.escrow.increaseAmount(variables.amount)); } else if (checkOnlyExtendLockTime(variables.time, variables.amount)) { const unlockHeight = stakedAmountAndEndBlock.endBlock + convertWeeksToBlockNumbers(variables.time); - return await window.bridge.escrow.increaseUnlockHeight(unlockHeight); + await submitExtrinsic(window.bridge.escrow.increaseUnlockHeight(unlockHeight)); } else { throw new Error('Something went wrong!'); } diff --git a/src/utils/helpers/extrinsic.ts b/src/utils/helpers/extrinsic.ts new file mode 100644 index 0000000000..535e32ac6a --- /dev/null +++ b/src/utils/helpers/extrinsic.ts @@ -0,0 +1,21 @@ +import { ExtrinsicData } from '@interlay/interbtc-api'; +import { ExtrinsicStatus } from '@polkadot/types/interfaces/author'; +import { ISubmittableResult } from '@polkadot/types/types'; + +const inBlockStatus = window.bridge.api.createType('ExtrinsicStatus', 'InBlock'); + +/** + * Helper to simple extrinsic submission. Waits for inBlock inclusion only by default. + * + * @param {ExtrinsicData} extrinsicData Extrinsic to submit and event to wait for. + * @param {ExtrinsicStatus} extrinsicStatus Optional parameter to specify extrinsic status to wait for. Defaults to inBlock. + */ +const submitExtrinsic = async ( + extrinsicData: ExtrinsicData, + extrinsicStatus: ExtrinsicStatus = inBlockStatus +): Promise => { + const { extrinsic, event } = extrinsicData; + await window.bridge.transaction.sendLogged(extrinsic, event, extrinsicStatus); +}; + +export { submitExtrinsic }; From 46ee6fab0c89a5ad79fe4a2f95164810ee5a6ee5 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 5 Apr 2023 19:10:48 +0200 Subject: [PATCH 48/69] wip refactor: handle lib update of submittable extrinsics --- .../ConfirmedIssueRequest/index.tsx | 6 ++- .../ManualIssueExecutionUI/index.tsx | 6 ++- .../components/DepositForm/DepositForm.tsx | 6 ++- .../PoolsInsights/PoolsInsights.tsx | 3 +- .../components/WithdrawForm/WithdrawForm.tsx | 6 ++- .../AMM/Swap/components/SwapForm/SwapForm.tsx | 6 ++- src/pages/Bridge/IssueForm/index.tsx | 11 +++-- .../CollateralModal/CollateralModal.tsx | 8 ++-- .../LoansInsights/LoansInsights.tsx | 6 ++- .../Staking/ClaimRewardsButton/index.tsx | 6 ++- .../Vaults/Vault/RequestIssueModal/index.tsx | 12 +++-- src/utils/helpers/extrinsic.ts | 15 ++++-- src/utils/helpers/issue.ts | 10 ++++ .../hooks/api/loans/use-loan-mutation.tsx | 46 +++++++++++-------- 14 files changed, 100 insertions(+), 47 deletions(-) create mode 100644 src/utils/helpers/issue.ts diff --git a/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx b/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx index 9f1e04dd44..a83621bac3 100644 --- a/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx +++ b/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx @@ -1,3 +1,4 @@ +import { ISubmittableResult } from '@polkadot/types/types'; import clsx from 'clsx'; import { useTranslation } from 'react-i18next'; import { FaCheckCircle } from 'react-icons/fa'; @@ -15,6 +16,7 @@ import { TABLE_PAGE_LIMIT } from '@/utils/constants/general'; import { QUERY_PARAMETERS } from '@/utils/constants/links'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { getColorShade } from '@/utils/helpers/colors'; +import { submitExtrinsic, submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import useQueryParams from '@/utils/hooks/use-query-params'; import ManualIssueExecutionUI from '../ManualIssueExecutionUI'; @@ -33,12 +35,12 @@ const ConfirmedIssueRequest = ({ request }: Props): JSX.Element => { const queryClient = useQueryClient(); // TODO: should type properly (`Relay`) - const executeMutation = useMutation( + const executeMutation = useMutation( (variables: any) => { if (!variables.backingPayment.btcTxId) { throw new Error('Bitcoin transaction ID not identified yet.'); } - return window.bridge.issue.execute(variables.id, variables.backingPayment.btcTxId); + return submitExtrinsicPromise(window.bridge.issue.execute(variables.id, variables.backingPayment.btcTxId)); }, { onSuccess: (_, variables) => { diff --git a/src/legacy-components/IssueUI/IssueRequestStatusUI/ManualIssueExecutionUI/index.tsx b/src/legacy-components/IssueUI/IssueRequestStatusUI/ManualIssueExecutionUI/index.tsx index 58d68c1a20..5aee169f45 100644 --- a/src/legacy-components/IssueUI/IssueRequestStatusUI/ManualIssueExecutionUI/index.tsx +++ b/src/legacy-components/IssueUI/IssueRequestStatusUI/ManualIssueExecutionUI/index.tsx @@ -5,6 +5,7 @@ import { newAccountId, newMonetaryAmount } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; import clsx from 'clsx'; import { useTranslation } from 'react-i18next'; import { useMutation, useQuery, useQueryClient } from 'react-query'; @@ -20,6 +21,7 @@ import { TABLE_PAGE_LIMIT } from '@/utils/constants/general'; import { QUERY_PARAMETERS } from '@/utils/constants/links'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { getColorShade } from '@/utils/helpers/colors'; +import { submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import useQueryParams from '@/utils/hooks/use-query-params'; // TODO: issue requests should not be typed here but further above in the app @@ -56,12 +58,12 @@ const ManualIssueExecutionUI = ({ request }: Props): JSX.Element => { const queryClient = useQueryClient(); // TODO: should type properly (`Relay`) - const executeMutation = useMutation( + const executeMutation = useMutation( (variables: any) => { if (!variables.backingPayment.btcTxId) { throw new Error('Bitcoin transaction ID not identified yet.'); } - return window.bridge.issue.execute(variables.id, variables.backingPayment.btcTxId); + return submitExtrinsicPromise(window.bridge.issue.execute(variables.id, variables.backingPayment.btcTxId)); }, { onSuccess: (_, variables) => { diff --git a/src/pages/AMM/Pools/components/DepositForm/DepositForm.tsx b/src/pages/AMM/Pools/components/DepositForm/DepositForm.tsx index 9f37555e45..ba91d28ad5 100644 --- a/src/pages/AMM/Pools/components/DepositForm/DepositForm.tsx +++ b/src/pages/AMM/Pools/components/DepositForm/DepositForm.tsx @@ -1,5 +1,6 @@ import { CurrencyExt, LiquidityPool, newMonetaryAmount, PooledCurrencies } from '@interlay/interbtc-api'; import { AccountId } from '@polkadot/types/interfaces'; +import { ISubmittableResult } from '@polkadot/types/types'; import { mergeProps } from '@react-aria/utils'; import Big from 'big.js'; import { ChangeEventHandler, RefObject, useState } from 'react'; @@ -20,6 +21,7 @@ import { } from '@/lib/form'; import { SlippageManager } from '@/pages/AMM/shared/components'; import { AMM_DEADLINE_INTERVAL } from '@/utils/constants/api'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -42,7 +44,7 @@ type DepositData = { }; const mutateDeposit = ({ amounts, pool, slippage, deadline, accountId }: DepositData) => - window.bridge.amm.addLiquidity(amounts, pool, slippage, deadline, accountId); + submitExtrinsic(window.bridge.amm.addLiquidity(amounts, pool, slippage, deadline, accountId)); type DepositFormProps = { pool: LiquidityPool; @@ -63,7 +65,7 @@ const DepositForm = ({ pool, slippageModalRef, onDeposit }: DepositFormProps): J const governanceBalance = getBalance(GOVERNANCE_TOKEN.ticker)?.free || newMonetaryAmount(0, GOVERNANCE_TOKEN); - const depositMutation = useMutation(mutateDeposit, { + const depositMutation = useMutation(mutateDeposit, { onSuccess: () => { onDeposit?.(); toast.success('Deposit successful'); diff --git a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx index ffbea39d84..7109ba6288 100644 --- a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx +++ b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx @@ -7,6 +7,7 @@ import { toast } from 'react-toastify'; import { formatUSD } from '@/common/utils/utils'; import { Card, CTA, Dl, DlGroup } from '@/component-library'; import { calculateAccountLiquidityUSD, calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; +import { submitExtrinsic, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { AccountPoolsData } from '@/utils/hooks/api/amm/use-get-account-pools'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -54,7 +55,7 @@ const PoolsInsights = ({ pools, accountPoolsData, refetch }: PoolsInsightsProps) const mutateClaimRewards = async () => { if (accountPoolsData !== undefined) { - await window.bridge.amm.claimFarmingRewards(accountPoolsData.claimableRewards); + await submitExtrinsic(window.bridge.amm.claimFarmingRewards(accountPoolsData.claimableRewards)); } }; diff --git a/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.tsx b/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.tsx index 9b81f9f0e4..3eeb392479 100644 --- a/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.tsx +++ b/src/pages/AMM/Pools/components/WithdrawForm/WithdrawForm.tsx @@ -1,6 +1,7 @@ import { LiquidityPool, LpCurrency, newMonetaryAmount } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; import { AccountId } from '@polkadot/types/interfaces'; +import { ISubmittableResult } from '@polkadot/types/types'; import Big from 'big.js'; import { RefObject, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -19,6 +20,7 @@ import { isFormDisabled, useForm, WITHDRAW_LIQUIDITY_POOL_FIELD } from '@/lib/fo import { WithdrawLiquidityPoolFormData, withdrawLiquidityPoolSchema } from '@/lib/form/schemas'; import { SlippageManager } from '@/pages/AMM/shared/components'; import { AMM_DEADLINE_INTERVAL } from '@/utils/constants/api'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -37,7 +39,7 @@ type DepositData = { }; const mutateWithdraw = ({ amount, pool, slippage, deadline, accountId }: DepositData) => - window.bridge.amm.removeLiquidity(amount, pool, slippage, deadline, accountId); + submitExtrinsic(window.bridge.amm.removeLiquidity(amount, pool, slippage, deadline, accountId)); type WithdrawFormProps = { pool: LiquidityPool; @@ -53,7 +55,7 @@ const WithdrawForm = ({ pool, slippageModalRef, onWithdraw }: WithdrawFormProps) const prices = useGetPrices(); const { getBalance } = useGetBalances(); - const withdrawMutation = useMutation(mutateWithdraw, { + const withdrawMutation = useMutation(mutateWithdraw, { onSuccess: () => { onWithdraw?.(); toast.success('Withdraw successful'); diff --git a/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx b/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx index 06d2b17131..f5f53b5772 100644 --- a/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx +++ b/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx @@ -1,6 +1,7 @@ import { CurrencyExt, LiquidityPool, newMonetaryAmount, Trade } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; import { AddressOrPair } from '@polkadot/api/types'; +import { ISubmittableResult } from '@polkadot/types/types'; import { mergeProps } from '@react-aria/utils'; import Big from 'big.js'; import { ChangeEventHandler, useEffect, useMemo, useState } from 'react'; @@ -25,6 +26,7 @@ import { import { SlippageManager } from '@/pages/AMM/shared/components'; import { SwapPair } from '@/types/swap'; import { SWAP_PRICE_IMPACT_LIMIT } from '@/utils/constants/swap'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetCurrencies } from '@/utils/hooks/api/use-get-currencies'; @@ -89,7 +91,7 @@ type SwapData = { }; const mutateSwap = ({ deadline, minimumAmountOut, recipient, trade }: SwapData) => - window.bridge.amm.swap(trade, minimumAmountOut, recipient, deadline); + submitExtrinsic(window.bridge.amm.swap(trade, minimumAmountOut, recipient, deadline)); type Props = { pair: SwapPair; @@ -139,7 +141,7 @@ const SwapForm = ({ [inputAmount, pair] ); - const swapMutation = useMutation(mutateSwap, { + const swapMutation = useMutation(mutateSwap, { onSuccess: () => { toast.success('Swap successful'); setTrade(undefined); diff --git a/src/pages/Bridge/IssueForm/index.tsx b/src/pages/Bridge/IssueForm/index.tsx index 759590f77d..b205ffdd97 100644 --- a/src/pages/Bridge/IssueForm/index.tsx +++ b/src/pages/Bridge/IssueForm/index.tsx @@ -55,6 +55,8 @@ import genericFetcher, { GENERIC_FETCHER } from '@/services/fetchers/generic-fet import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; +import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { getIssueRequestsFromExtrinsicResult } from '@/utils/helpers/issue'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -319,17 +321,20 @@ const IssueForm = (): JSX.Element | null => { const collateralToken = await currencyIdToMonetaryCurrency(window.bridge.api, vaultId.currencies.collateral); - const result = await window.bridge.issue.request( + const extrinsicData = await window.bridge.issue.request( monetaryBtcAmount, vaultId.accountId, collateralToken, false, // default - 0, // default vaults ); + // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. + // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 + const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const issueRequests = await getIssueRequestsFromExtrinsicResult(extrinsicResult); // TODO: handle issue aggregation - const issueRequest = result[0]; + const issueRequest = issueRequests[0]; handleSubmittedRequestModalOpen(issueRequest); setSubmitStatus(STATUSES.RESOLVED); } catch (error) { diff --git a/src/pages/Loans/LoansOverview/components/CollateralModal/CollateralModal.tsx b/src/pages/Loans/LoansOverview/components/CollateralModal/CollateralModal.tsx index 2315a5831c..bf871325df 100644 --- a/src/pages/Loans/LoansOverview/components/CollateralModal/CollateralModal.tsx +++ b/src/pages/Loans/LoansOverview/components/CollateralModal/CollateralModal.tsx @@ -1,10 +1,12 @@ import { CollateralPosition, CurrencyExt, LoanAsset } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; import { TFunction, useTranslation } from 'react-i18next'; import { useMutation } from 'react-query'; import { toast } from 'react-toastify'; import { CTA, Flex, Modal, ModalBody, ModalFooter, ModalHeader, ModalProps, Status } from '@/component-library'; import ErrorModal from '@/legacy-components/ErrorModal'; +import { submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import { useGetAccountLendingStatistics } from '@/utils/hooks/api/loans/use-get-account-lending-statistics'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -17,9 +19,9 @@ type ToggleCollateralVariables = { isEnabling: boolean; underlyingCurrency: Curr const toggleCollateral = ({ isEnabling, underlyingCurrency }: ToggleCollateralVariables) => { if (isEnabling) { - return window.bridge.loans.enableAsCollateral(underlyingCurrency); + return submitExtrinsicPromise(window.bridge.loans.enableAsCollateral(underlyingCurrency)); } else { - return window.bridge.loans.disableAsCollateral(underlyingCurrency); + return submitExtrinsicPromise(window.bridge.loans.disableAsCollateral(underlyingCurrency)); } }; @@ -76,7 +78,7 @@ const CollateralModal = ({ asset, position, onClose, ...props }: CollateralModal refetch(); }; - const toggleCollateralMutation = useMutation(toggleCollateral, { + const toggleCollateralMutation = useMutation(toggleCollateral, { onSuccess: handleSuccess }); diff --git a/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx b/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx index 290bb07717..5234d526aa 100644 --- a/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx +++ b/src/pages/Loans/LoansOverview/components/LoansInsights/LoansInsights.tsx @@ -1,3 +1,4 @@ +import { ISubmittableResult } from '@polkadot/types/types'; import { useTranslation } from 'react-i18next'; import { useMutation } from 'react-query'; import { toast } from 'react-toastify'; @@ -5,12 +6,13 @@ import { toast } from 'react-toastify'; import { formatNumber, formatPercentage, formatUSD } from '@/common/utils/utils'; import { Card, CTA, Dl, DlGroup } from '@/component-library'; import ErrorModal from '@/legacy-components/ErrorModal'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { AccountLendingStatistics } from '@/utils/hooks/api/loans/use-get-account-lending-statistics'; import { useGetAccountSubsidyRewards } from '@/utils/hooks/api/loans/use-get-account-subsidy-rewards'; import { StyledDd, StyledDt } from './LoansInsights.style'; -const mutateClaimRewards = () => window.bridge.loans.claimAllSubsidyRewards(); +const mutateClaimRewards = () => submitExtrinsic(window.bridge.loans.claimAllSubsidyRewards()); type LoansInsightsProps = { statistics?: AccountLendingStatistics; @@ -25,7 +27,7 @@ const LoansInsights = ({ statistics }: LoansInsightsProps): JSX.Element => { refetch(); }; - const claimRewardsMutation = useMutation(mutateClaimRewards, { + const claimRewardsMutation = useMutation(mutateClaimRewards, { onSuccess: handleSuccess }); diff --git a/src/pages/Staking/ClaimRewardsButton/index.tsx b/src/pages/Staking/ClaimRewardsButton/index.tsx index f3f3375483..2ad34879cd 100644 --- a/src/pages/Staking/ClaimRewardsButton/index.tsx +++ b/src/pages/Staking/ClaimRewardsButton/index.tsx @@ -1,3 +1,4 @@ +import { ISubmittableResult } from '@polkadot/types/types'; import clsx from 'clsx'; import { useMutation, useQueryClient } from 'react-query'; @@ -8,6 +9,7 @@ import InterlayDenimOrKintsugiSupernovaContainedButton, { import ErrorModal from '@/legacy-components/ErrorModal'; import { useSubstrateSecureState } from '@/lib/substrate'; import { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; interface CustomProps { claimableRewardAmount: string; @@ -22,9 +24,9 @@ const ClaimRewardsButton = ({ const queryClient = useQueryClient(); - const claimRewardsMutation = useMutation( + const claimRewardsMutation = useMutation( () => { - return window.bridge.escrow.withdrawRewards(); + return submitExtrinsic(window.bridge.escrow.withdrawRewards()); }, { onSuccess: () => { diff --git a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx index 183128e603..1381b31099 100644 --- a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx @@ -39,6 +39,8 @@ import SubmittedIssueRequestModal from '@/pages/Bridge/IssueForm/SubmittedIssueR import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; +import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { getIssueRequestsFromExtrinsicResult } from '@/utils/helpers/issue'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -174,16 +176,20 @@ const RequestIssueModal = ({ onClose, open, collateralToken, vaultAddress }: Pro const vaults = await window.bridge.vaults.getVaultsWithIssuableTokens(); - const result = await window.bridge.issue.request( + const extrinsicData = await window.bridge.issue.request( wrappedTokenAmount, vaultAccountId, collateralToken, false, // default - 0, // default vaults ); + // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. + // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 + const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const issueRequests = await getIssueRequestsFromExtrinsicResult(extrinsicResult); - const issueRequest = result[0]; + // TODO: handle issue aggregation + const issueRequest = issueRequests[0]; handleSubmittedRequestModalOpen(issueRequest); } catch (error) { setSubmitStatus(STATUSES.REJECTED); diff --git a/src/utils/helpers/extrinsic.ts b/src/utils/helpers/extrinsic.ts index 535e32ac6a..7bbd25c50f 100644 --- a/src/utils/helpers/extrinsic.ts +++ b/src/utils/helpers/extrinsic.ts @@ -2,7 +2,8 @@ import { ExtrinsicData } from '@interlay/interbtc-api'; import { ExtrinsicStatus } from '@polkadot/types/interfaces/author'; import { ISubmittableResult } from '@polkadot/types/types'; -const inBlockStatus = window.bridge.api.createType('ExtrinsicStatus', 'InBlock'); +const inBlockExtrinsicStatus = window.bridge.api.createType('ExtrinsicStatus', 'InBlock'); +const finalizedExtrinsicStatus = window.bridge.api.createType('ExtrinsicStatus', 'Finalized'); /** * Helper to simple extrinsic submission. Waits for inBlock inclusion only by default. @@ -12,10 +13,18 @@ const inBlockStatus = window.bridge.api.createType('ExtrinsicStatus', 'InBlock') */ const submitExtrinsic = async ( extrinsicData: ExtrinsicData, - extrinsicStatus: ExtrinsicStatus = inBlockStatus + extrinsicStatus: ExtrinsicStatus = inBlockExtrinsicStatus ): Promise => { const { extrinsic, event } = extrinsicData; await window.bridge.transaction.sendLogged(extrinsic, event, extrinsicStatus); }; -export { submitExtrinsic }; +const submitExtrinsicPromise = async ( + extrinsicDataPromise: Promise, + extrinsicStatus: ExtrinsicStatus = inBlockExtrinsicStatus +): Promise => { + const extrinsicData = await extrinsicDataPromise; + return submitExtrinsic(extrinsicData, extrinsicStatus); +}; + +export { finalizedExtrinsicStatus, inBlockExtrinsicStatus, submitExtrinsic, submitExtrinsicPromise }; diff --git a/src/utils/helpers/issue.ts b/src/utils/helpers/issue.ts new file mode 100644 index 0000000000..0ba647006f --- /dev/null +++ b/src/utils/helpers/issue.ts @@ -0,0 +1,10 @@ +import { getRequestIdsFromEvents, Issue } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; + +const getIssueRequestsFromExtrinsicResult = async (result: ISubmittableResult): Promise> => { + const ids = getRequestIdsFromEvents(result.events, window.bridge.api.events.issue.RequestIssue, window.bridge.api); + const issueRequests = await window.bridge.issue.getRequestsByIds(ids); + return issueRequests; +}; + +export { getIssueRequestsFromExtrinsicResult }; diff --git a/src/utils/hooks/api/loans/use-loan-mutation.tsx b/src/utils/hooks/api/loans/use-loan-mutation.tsx index ac43ef35a9..0057369b36 100644 --- a/src/utils/hooks/api/loans/use-loan-mutation.tsx +++ b/src/utils/hooks/api/loans/use-loan-mutation.tsx @@ -1,30 +1,36 @@ import { CurrencyExt } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; +import { ISubmittableResult } from '@polkadot/types/types'; import { useMutation, UseMutationResult } from 'react-query'; import { LoanAction } from '@/types/loans'; +import { submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; type CreateLoanVariables = { loanType: LoanAction; amount: MonetaryAmount; isMaxAmount: boolean }; const mutateLoan = ({ loanType, amount, isMaxAmount }: CreateLoanVariables) => { - switch (loanType) { - case 'lend': - return window.bridge.loans.lend(amount.currency, amount); - case 'withdraw': - if (isMaxAmount) { - return window.bridge.loans.withdrawAll(amount.currency); - } else { - return window.bridge.loans.withdraw(amount.currency, amount); - } - case 'borrow': - return window.bridge.loans.borrow(amount.currency, amount); - case 'repay': - if (isMaxAmount) { - return window.bridge.loans.repayAll(amount.currency); - } else { - return window.bridge.loans.repay(amount.currency, amount); - } - } + const extrinsicData = (() => { + switch (loanType) { + case 'lend': + return window.bridge.loans.lend(amount.currency, amount); + case 'withdraw': + if (isMaxAmount) { + return window.bridge.loans.withdrawAll(amount.currency); + } else { + return window.bridge.loans.withdraw(amount.currency, amount); + } + case 'borrow': + return window.bridge.loans.borrow(amount.currency, amount); + case 'repay': + if (isMaxAmount) { + return window.bridge.loans.repayAll(amount.currency); + } else { + return window.bridge.loans.repay(amount.currency, amount); + } + } + })(); + + return submitExtrinsicPromise(extrinsicData); }; type UseLoanMutation = { onSuccess: () => void; onError: (error: Error) => void }; @@ -32,8 +38,8 @@ type UseLoanMutation = { onSuccess: () => void; onError: (error: Error) => void const useLoanMutation = ({ onSuccess, onError -}: UseLoanMutation): UseMutationResult => { - return useMutation(mutateLoan, { +}: UseLoanMutation): UseMutationResult => { + return useMutation(mutateLoan, { onSuccess, onError }); From 5491cd9961d55c41b9744c43765e0b1c43daca00 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 6 Apr 2023 16:45:44 +0200 Subject: [PATCH 49/69] refactor: handle submittable extrinsics returned from lib --- package.json | 2 +- .../ConfirmedIssueRequest/index.tsx | 2 +- .../RedeemUI/ReimburseStatusUI/index.tsx | 10 ++++++---- .../components/PoolsInsights/PoolsInsights.tsx | 2 +- src/pages/Bridge/BurnForm/index.tsx | 5 ++++- src/pages/Bridge/IssueForm/index.tsx | 4 ++-- src/pages/Bridge/RedeemForm/index.tsx | 14 ++++++++++++-- src/pages/Transfer/TransferForm/index.tsx | 9 ++++++--- src/pages/Vaults/Vault/RequestIssueModal/index.tsx | 10 +++++++--- .../Vaults/Vault/RequestRedeemModal/index.tsx | 6 +++++- .../Vaults/Vault/RequestReplacementModal/index.tsx | 5 ++++- .../Vaults/Vault/UpdateCollateralModal/index.tsx | 5 +++-- .../components/CollateralForm/CollateralForm.tsx | 5 +++-- .../Vaults/Vault/components/Rewards/Rewards.tsx | 6 ++++-- .../CreateVaultWizard/DespositCollateralStep.tsx | 6 ++++-- src/utils/helpers/extrinsic.ts | 8 ++++---- src/utils/helpers/issue.ts | 10 ---------- 17 files changed, 67 insertions(+), 42 deletions(-) delete mode 100644 src/utils/helpers/issue.ts diff --git a/package.json b/package.json index 93453c3386..84691ad719 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@headlessui/react": "^1.1.1", "@heroicons/react": "^2.0.0", "@interlay/bridge": "^0.2.4", - "@interlay/interbtc-api": "2.0.3", + "@interlay/interbtc-api": "2.1.0", "@interlay/monetary-js": "0.7.2", "@polkadot/api": "9.14.2", "@polkadot/extension-dapp": "0.44.1", diff --git a/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx b/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx index a83621bac3..3a758d2989 100644 --- a/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx +++ b/src/legacy-components/IssueUI/IssueRequestStatusUI/ConfirmedIssueRequest/index.tsx @@ -16,7 +16,7 @@ import { TABLE_PAGE_LIMIT } from '@/utils/constants/general'; import { QUERY_PARAMETERS } from '@/utils/constants/links'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { getColorShade } from '@/utils/helpers/colors'; -import { submitExtrinsic, submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; +import { submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import useQueryParams from '@/utils/hooks/use-query-params'; import ManualIssueExecutionUI from '../ManualIssueExecutionUI'; diff --git a/src/legacy-components/RedeemUI/ReimburseStatusUI/index.tsx b/src/legacy-components/RedeemUI/ReimburseStatusUI/index.tsx index 8125d52d69..2e2cc3b19e 100644 --- a/src/legacy-components/RedeemUI/ReimburseStatusUI/index.tsx +++ b/src/legacy-components/RedeemUI/ReimburseStatusUI/index.tsx @@ -1,4 +1,5 @@ import { newMonetaryAmount } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; import Big from 'big.js'; import clsx from 'clsx'; import * as React from 'react'; @@ -21,6 +22,7 @@ import RequestWrapper from '@/pages/Bridge/RequestWrapper'; import { REDEEMS_FETCHER } from '@/services/fetchers/redeems-fetcher'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import { getColorShade } from '@/utils/helpers/colors'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -67,9 +69,9 @@ const ReimburseStatusUI = ({ redeem, onClose }: Props): JSX.Element => { const queryClient = useQueryClient(); // TODO: should type properly (`Relay`) - const retryMutation = useMutation( + const retryMutation = useMutation( (variables: any) => { - return window.bridge.redeem.cancel(variables.id, false); + return submitExtrinsic(window.bridge.redeem.cancel(variables.id, false)); }, { onSuccess: () => { @@ -84,9 +86,9 @@ const ReimburseStatusUI = ({ redeem, onClose }: Props): JSX.Element => { } ); // TODO: should type properly (`Relay`) - const reimburseMutation = useMutation( + const reimburseMutation = useMutation( (variables: any) => { - return window.bridge.redeem.cancel(variables.id, true); + return submitExtrinsic(window.bridge.redeem.cancel(variables.id, true)); }, { onSuccess: () => { diff --git a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx index 7109ba6288..d884e49b48 100644 --- a/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx +++ b/src/pages/AMM/Pools/components/PoolsInsights/PoolsInsights.tsx @@ -7,7 +7,7 @@ import { toast } from 'react-toastify'; import { formatUSD } from '@/common/utils/utils'; import { Card, CTA, Dl, DlGroup } from '@/component-library'; import { calculateAccountLiquidityUSD, calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; -import { submitExtrinsic, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { AccountPoolsData } from '@/utils/hooks/api/amm/use-get-account-pools'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; diff --git a/src/pages/Bridge/BurnForm/index.tsx b/src/pages/Bridge/BurnForm/index.tsx index 911cbff307..622b842372 100644 --- a/src/pages/Bridge/BurnForm/index.tsx +++ b/src/pages/Bridge/BurnForm/index.tsx @@ -25,6 +25,7 @@ import Tokens, { TokenOption } from '@/legacy-components/Tokens'; import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetCollateralCurrencies } from '@/utils/hooks/api/use-get-collateral-currencies'; @@ -149,7 +150,9 @@ const BurnForm = (): JSX.Element | null => { const onSubmit = async (data: BurnFormData) => { try { setSubmitStatus(STATUSES.PENDING); - await window.bridge.redeem.burn(new BitcoinAmount(data[WRAPPED_TOKEN_AMOUNT]), selectedCollateral.currency); + await submitExtrinsic( + window.bridge.redeem.burn(new BitcoinAmount(data[WRAPPED_TOKEN_AMOUNT]), selectedCollateral.currency) + ); setSubmitStatus(STATUSES.RESOLVED); } catch (error) { diff --git a/src/pages/Bridge/IssueForm/index.tsx b/src/pages/Bridge/IssueForm/index.tsx index b205ffdd97..96cd9b1ebb 100644 --- a/src/pages/Bridge/IssueForm/index.tsx +++ b/src/pages/Bridge/IssueForm/index.tsx @@ -1,5 +1,6 @@ import { currencyIdToMonetaryCurrency, + getIssueRequestsFromExtrinsicResult, GovernanceCurrency, InterbtcPrimitivesVaultId, Issue @@ -56,7 +57,6 @@ import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; -import { getIssueRequestsFromExtrinsicResult } from '@/utils/helpers/issue'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -331,7 +331,7 @@ const IssueForm = (): JSX.Element | null => { // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); - const issueRequests = await getIssueRequestsFromExtrinsicResult(extrinsicResult); + const issueRequests = await getIssueRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle issue aggregation const issueRequest = issueRequests[0]; diff --git a/src/pages/Bridge/RedeemForm/index.tsx b/src/pages/Bridge/RedeemForm/index.tsx index 584d258cf4..1fa0cb44e5 100644 --- a/src/pages/Bridge/RedeemForm/index.tsx +++ b/src/pages/Bridge/RedeemForm/index.tsx @@ -1,4 +1,5 @@ import { CollateralCurrencyExt, InterbtcPrimitivesVaultId, newMonetaryAmount, Redeem } from '@interlay/interbtc-api'; +import { getRedeemRequestsFromExtrinsicResult } from '@interlay/interbtc-api'; import { Bitcoin, BitcoinAmount, ExchangeRate } from '@interlay/monetary-js'; import Big from 'big.js'; import clsx from 'clsx'; @@ -43,6 +44,7 @@ import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; import { getColorShade } from '@/utils/helpers/colors'; +import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -293,10 +295,18 @@ const RedeemForm = (): JSX.Element | null => { const relevantVaults = new Map(); // FIXME: a bit of a dirty workaround with the capacity relevantVaults.set(vaultId, monetaryWrappedTokenAmount.mul(2)); - const result = await window.bridge.redeem.request(monetaryWrappedTokenAmount, data[BTC_ADDRESS], vaultId); + const extrinsicData = await window.bridge.redeem.request( + monetaryWrappedTokenAmount, + data[BTC_ADDRESS], + vaultId + ); + // When requesting a redeem, wait for the finalized event because we cannot revert BTC transactions. + // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 + const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const redeemRequests = await getRedeemRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle redeem aggregator - const redeemRequest = result[0]; + const redeemRequest = redeemRequests[0]; handleSubmittedRequestModalOpen(redeemRequest); setSubmitStatus(STATUSES.RESOLVED); } catch (error) { diff --git a/src/pages/Transfer/TransferForm/index.tsx b/src/pages/Transfer/TransferForm/index.tsx index d346411850..e588456dc1 100644 --- a/src/pages/Transfer/TransferForm/index.tsx +++ b/src/pages/Transfer/TransferForm/index.tsx @@ -18,6 +18,7 @@ import Tokens, { TokenOption } from '@/legacy-components/Tokens'; import InterlayButtonBase from '@/legacy-components/UI/InterlayButtonBase'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import isValidPolkadotAddress from '@/utils/helpers/is-valid-polkadot-address'; import TokenAmountField from '../TokenAmountField'; @@ -56,9 +57,11 @@ const TransferForm = (): JSX.Element => { try { setSubmitStatus(STATUSES.PENDING); - await window.bridge.tokens.transfer( - data[RECIPIENT_ADDRESS], - newMonetaryAmount(data[TRANSFER_AMOUNT], activeToken.token, true) + await submitExtrinsic( + window.bridge.tokens.transfer( + data[RECIPIENT_ADDRESS], + newMonetaryAmount(data[TRANSFER_AMOUNT], activeToken.token, true) + ) ); setSubmitStatus(STATUSES.RESOLVED); diff --git a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx index 1381b31099..c7c5321a41 100644 --- a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx @@ -1,4 +1,9 @@ -import { CollateralCurrencyExt, GovernanceCurrency, Issue } from '@interlay/interbtc-api'; +import { + CollateralCurrencyExt, + getIssueRequestsFromExtrinsicResult, + GovernanceCurrency, + Issue +} from '@interlay/interbtc-api'; import { Bitcoin, BitcoinAmount, ExchangeRate } from '@interlay/monetary-js'; import Big from 'big.js'; import clsx from 'clsx'; @@ -40,7 +45,6 @@ import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; -import { getIssueRequestsFromExtrinsicResult } from '@/utils/helpers/issue'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -186,7 +190,7 @@ const RequestIssueModal = ({ onClose, open, collateralToken, vaultAddress }: Pro // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); - const issueRequests = await getIssueRequestsFromExtrinsicResult(extrinsicResult); + const issueRequests = await getIssueRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle issue aggregation const issueRequest = issueRequests[0]; diff --git a/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx b/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx index 07f0684b31..851255b43f 100644 --- a/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx @@ -17,6 +17,7 @@ import ErrorMessage from '@/legacy-components/ErrorMessage'; import NumberInput from '@/legacy-components/NumberInput'; import TextField from '@/legacy-components/TextField'; import InterlayModal, { InterlayModalInnerWrapper, InterlayModalTitle } from '@/legacy-components/UI/InterlayModal'; +import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; const WRAPPED_TOKEN_AMOUNT = 'amount'; const BTC_ADDRESS = 'btc-address'; @@ -60,7 +61,10 @@ const RequestRedeemModal = ({ onClose, open, collateralToken, vaultAddress, lock } const vaultId = newVaultId(window.bridge.api, vaultAddress, collateralToken, WRAPPED_TOKEN); - await window.bridge.redeem.request(amountPolkaBtc, data[BTC_ADDRESS], vaultId); + const extrinsicData = await window.bridge.redeem.request(amountPolkaBtc, data[BTC_ADDRESS], vaultId); + // When requesting a redeem, wait for the finalized event because we cannot revert BTC transactions. + // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 + await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); queryClient.invalidateQueries(['vaultsOverview', vaultAddress, collateralToken.ticker]); diff --git a/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx b/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx index fc6004d9e4..42186fc748 100644 --- a/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx @@ -25,6 +25,7 @@ import PrimaryColorEllipsisLoader from '@/legacy-components/PrimaryColorEllipsis import InterlayModal, { InterlayModalInnerWrapper, InterlayModalTitle } from '@/legacy-components/UI/InterlayModal'; import { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; import STATUSES from '@/utils/constants/statuses'; +import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -104,7 +105,9 @@ const RequestReplacementModal = ({ try { setSubmitStatus(STATUSES.PENDING); const amountPolkaBtc = new BitcoinAmount(data[AMOUNT]); - await window.bridge.replace.request(amountPolkaBtc, collateralToken); + // When requesting a replace, wait for the finalized event because we cannot revert BTC transactions. + // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 + submitExtrinsic(window.bridge.replace.request(amountPolkaBtc, collateralToken), finalizedExtrinsicStatus); const vaultId = window.bridge.api.createType(ACCOUNT_ID_TYPE_NAME, vaultAddress); queryClient.invalidateQueries([GENERIC_FETCHER, 'mapReplaceRequests', vaultId]); diff --git a/src/pages/Vaults/Vault/UpdateCollateralModal/index.tsx b/src/pages/Vaults/Vault/UpdateCollateralModal/index.tsx index 5a22849c3d..772fa93e3d 100644 --- a/src/pages/Vaults/Vault/UpdateCollateralModal/index.tsx +++ b/src/pages/Vaults/Vault/UpdateCollateralModal/index.tsx @@ -21,6 +21,7 @@ import TokenField from '@/legacy-components/TokenField'; import InterlayModal, { InterlayModalInnerWrapper, InterlayModalTitle } from '@/legacy-components/UI/InterlayModal'; import genericFetcher, { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; import STATUSES from '@/utils/constants/statuses'; +import { submitExtrinsic, submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; @@ -141,9 +142,9 @@ const UpdateCollateralModal = ({ true ) as MonetaryAmount; if (collateralUpdateStatus === CollateralUpdateStatus.Deposit) { - await window.bridge.vaults.depositCollateral(collateralTokenAmount); + await submitExtrinsic(window.bridge.vaults.depositCollateral(collateralTokenAmount)); } else if (collateralUpdateStatus === CollateralUpdateStatus.Withdraw) { - await window.bridge.vaults.withdrawCollateral(collateralTokenAmount); + await submitExtrinsicPromise(window.bridge.vaults.withdrawCollateral(collateralTokenAmount)); } else { throw new Error('Something went wrong!'); } diff --git a/src/pages/Vaults/Vault/components/CollateralForm/CollateralForm.tsx b/src/pages/Vaults/Vault/components/CollateralForm/CollateralForm.tsx index 0d27a56a1a..7f00b8be13 100644 --- a/src/pages/Vaults/Vault/components/CollateralForm/CollateralForm.tsx +++ b/src/pages/Vaults/Vault/components/CollateralForm/CollateralForm.tsx @@ -21,6 +21,7 @@ import { import { CTA, Span, Stack, TokenInput } from '@/component-library'; import genericFetcher, { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; import { URL_PARAMETERS } from '@/utils/constants/links'; +import { submitExtrinsic, submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { VaultData } from '@/utils/hooks/api/vaults/get-vault-data'; @@ -163,11 +164,11 @@ const CollateralForm = ({ switch (variant) { case 'deposit': { - await window.bridge.vaults.depositCollateral(collateralTokenAmount); + await submitExtrinsic(window.bridge.vaults.depositCollateral(collateralTokenAmount)); break; } case 'withdraw': { - await window.bridge.vaults.withdrawCollateral(collateralTokenAmount); + await submitExtrinsicPromise(window.bridge.vaults.withdrawCollateral(collateralTokenAmount)); break; } } diff --git a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx index a522b8a291..5fa2fcbe6d 100644 --- a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx +++ b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx @@ -1,4 +1,5 @@ import { CollateralCurrencyExt, newVaultId, WrappedCurrency, WrappedIdLiteral } from '@interlay/interbtc-api'; +import { ISubmittableResult } from '@polkadot/types/types'; import Big from 'big.js'; import { useMutation, useQueryClient } from 'react-query'; import { toast } from 'react-toastify'; @@ -9,6 +10,7 @@ import { LoadingSpinner } from '@/component-library/LoadingSpinner'; import { GOVERNANCE_TOKEN_SYMBOL, WRAPPED_TOKEN } from '@/config/relay-chains'; import ErrorModal from '@/legacy-components/ErrorModal'; import { ZERO_GOVERNANCE_TOKEN_AMOUNT } from '@/utils/constants/currency'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { VaultData } from '@/utils/hooks/api/vaults/get-vault-data'; import useAccountId from '@/utils/hooks/use-account-id'; @@ -47,7 +49,7 @@ const Rewards = ({ const queryClient = useQueryClient(); const vaultAccountId = useAccountId(vaultAddress); - const claimRewardsMutation = useMutation( + const claimRewardsMutation = useMutation( () => { if (vaultAccountId === undefined) { throw new Error('Something went wrong!'); @@ -60,7 +62,7 @@ const Rewards = ({ WRAPPED_TOKEN as WrappedCurrency ); - return window.bridge.rewards.withdrawRewards(vaultId); + return submitExtrinsic(window.bridge.rewards.withdrawRewards(vaultId)); }, { onSuccess: () => { diff --git a/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/DespositCollateralStep.tsx b/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/DespositCollateralStep.tsx index b7df987d1c..ecc88e7767 100644 --- a/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/DespositCollateralStep.tsx +++ b/src/pages/Vaults/VaultsOverview/components/CreateVaultWizard/DespositCollateralStep.tsx @@ -1,5 +1,6 @@ import { CollateralCurrencyExt, newMonetaryAmount } from '@interlay/interbtc-api'; import { MonetaryAmount } from '@interlay/monetary-js'; +import { ISubmittableResult } from '@polkadot/types/types'; import { useId } from '@react-aria/utils'; import { useTranslation } from 'react-i18next'; import { useMutation } from 'react-query'; @@ -15,6 +16,7 @@ import { isFormDisabled, useForm } from '@/lib/form'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; import { useDepositCollateral } from '../../utils/use-deposit-collateral'; import { StyledDd, StyledDItem, StyledDl, StyledDt, StyledHr } from './CreateVaultWizard.styles'; @@ -57,8 +59,8 @@ const DepositCollateralStep = ({ onSubmit: handleSubmit }); - const registerNewVaultMutation = useMutation>( - (collateralAmount) => window.bridge.vaults.registerNewCollateralVault(collateralAmount), + const registerNewVaultMutation = useMutation>( + (collateralAmount) => submitExtrinsic(window.bridge.vaults.registerNewCollateralVault(collateralAmount)), { onSuccess: onSuccessfulDeposit } diff --git a/src/utils/helpers/extrinsic.ts b/src/utils/helpers/extrinsic.ts index 7bbd25c50f..ea3d1fdfeb 100644 --- a/src/utils/helpers/extrinsic.ts +++ b/src/utils/helpers/extrinsic.ts @@ -1,9 +1,9 @@ -import { ExtrinsicData } from '@interlay/interbtc-api'; +import { ExtrinsicData, newExtrinsicStatus } from '@interlay/interbtc-api'; import { ExtrinsicStatus } from '@polkadot/types/interfaces/author'; import { ISubmittableResult } from '@polkadot/types/types'; -const inBlockExtrinsicStatus = window.bridge.api.createType('ExtrinsicStatus', 'InBlock'); -const finalizedExtrinsicStatus = window.bridge.api.createType('ExtrinsicStatus', 'Finalized'); +const inBlockExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'InBlock'); +const finalizedExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'Finalized'); /** * Helper to simple extrinsic submission. Waits for inBlock inclusion only by default. @@ -16,7 +16,7 @@ const submitExtrinsic = async ( extrinsicStatus: ExtrinsicStatus = inBlockExtrinsicStatus ): Promise => { const { extrinsic, event } = extrinsicData; - await window.bridge.transaction.sendLogged(extrinsic, event, extrinsicStatus); + return await window.bridge.transaction.sendLogged(extrinsic, event, extrinsicStatus); }; const submitExtrinsicPromise = async ( diff --git a/src/utils/helpers/issue.ts b/src/utils/helpers/issue.ts deleted file mode 100644 index 0ba647006f..0000000000 --- a/src/utils/helpers/issue.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { getRequestIdsFromEvents, Issue } from '@interlay/interbtc-api'; -import { ISubmittableResult } from '@polkadot/types/types'; - -const getIssueRequestsFromExtrinsicResult = async (result: ISubmittableResult): Promise> => { - const ids = getRequestIdsFromEvents(result.events, window.bridge.api.events.issue.RequestIssue, window.bridge.api); - const issueRequests = await window.bridge.issue.getRequestsByIds(ids); - return issueRequests; -}; - -export { getIssueRequestsFromExtrinsicResult }; From 375615e8825d1fa3bd7817a3e8845fafe905057f Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 19 Apr 2023 21:55:56 +0200 Subject: [PATCH 50/69] refactor: update to lib to 2.1.0 and switch to submitting extrinsics on UI side --- src/pages/Bridge/IssueForm/index.tsx | 4 ++-- src/pages/Bridge/RedeemForm/index.tsx | 4 ++-- src/pages/Staking/WithdrawButton/index.tsx | 6 ++++-- src/pages/Transfer/CrossChainTransferForm/index.tsx | 9 ++++++++- src/pages/Vaults/Vault/RequestIssueModal/index.tsx | 4 ++-- src/pages/Vaults/Vault/RequestRedeemModal/index.tsx | 4 ++-- .../Vaults/Vault/RequestReplacementModal/index.tsx | 4 ++-- src/pages/Vaults/Vault/components/Rewards/Rewards.tsx | 4 ++-- src/utils/helpers/extrinsic.ts | 10 +++++----- yarn.lock | 8 ++++---- 10 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/pages/Bridge/IssueForm/index.tsx b/src/pages/Bridge/IssueForm/index.tsx index 96cd9b1ebb..9b2227dfc9 100644 --- a/src/pages/Bridge/IssueForm/index.tsx +++ b/src/pages/Bridge/IssueForm/index.tsx @@ -56,7 +56,7 @@ import genericFetcher, { GENERIC_FETCHER } from '@/services/fetchers/generic-fet import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; -import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { FinalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -330,7 +330,7 @@ const IssueForm = (): JSX.Element | null => { ); // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 - const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const extrinsicResult = await submitExtrinsic(extrinsicData, FinalizedExtrinsicStatus); const issueRequests = await getIssueRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle issue aggregation diff --git a/src/pages/Bridge/RedeemForm/index.tsx b/src/pages/Bridge/RedeemForm/index.tsx index 1fa0cb44e5..a209015d03 100644 --- a/src/pages/Bridge/RedeemForm/index.tsx +++ b/src/pages/Bridge/RedeemForm/index.tsx @@ -44,7 +44,7 @@ import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; import { getColorShade } from '@/utils/helpers/colors'; -import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { FinalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -302,7 +302,7 @@ const RedeemForm = (): JSX.Element | null => { ); // When requesting a redeem, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 - const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const extrinsicResult = await submitExtrinsic(extrinsicData, FinalizedExtrinsicStatus); const redeemRequests = await getRedeemRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle redeem aggregator diff --git a/src/pages/Staking/WithdrawButton/index.tsx b/src/pages/Staking/WithdrawButton/index.tsx index c962d70ab0..7093017a52 100644 --- a/src/pages/Staking/WithdrawButton/index.tsx +++ b/src/pages/Staking/WithdrawButton/index.tsx @@ -1,3 +1,4 @@ +import { ISubmittableResult } from '@polkadot/types/types'; import clsx from 'clsx'; import { add, format } from 'date-fns'; import { useMutation, useQueryClient } from 'react-query'; @@ -12,6 +13,7 @@ import InformationTooltip from '@/legacy-components/tooltips/InformationTooltip' import { useSubstrateSecureState } from '@/lib/substrate'; import { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; import { YEAR_MONTH_DAY_PATTERN } from '@/utils/constants/date-time'; +import { submitExtrinsic } from '@/utils/helpers/extrinsic'; const getFormattedUnlockDate = (remainingBlockNumbersToUnstake: number, formatPattern: string) => { const unlockDate = add(new Date(), { @@ -36,9 +38,9 @@ const WithdrawButton = ({ const queryClient = useQueryClient(); - const withdrawMutation = useMutation( + const withdrawMutation = useMutation( () => { - return window.bridge.escrow.withdraw(); + return submitExtrinsic(window.bridge.escrow.withdraw()); }, { onSuccess: () => { diff --git a/src/pages/Transfer/CrossChainTransferForm/index.tsx b/src/pages/Transfer/CrossChainTransferForm/index.tsx index 1ea21287ee..4e8d0568a7 100644 --- a/src/pages/Transfer/CrossChainTransferForm/index.tsx +++ b/src/pages/Transfer/CrossChainTransferForm/index.tsx @@ -27,6 +27,7 @@ import PrimaryColorEllipsisLoader from '@/legacy-components/PrimaryColorEllipsis import TokenField from '@/legacy-components/TokenField'; import { KeyringPair, useSubstrateSecureState } from '@/lib/substrate'; import STATUSES from '@/utils/constants/statuses'; +import { InBlockExtrinsicStatus } from '@/utils/helpers/extrinsic'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { useXCMBridge } from '@/utils/hooks/api/xcm/use-xcm-bridge'; @@ -188,7 +189,13 @@ const CrossChainTransferForm = (): JSX.Element => { address: destination.address } as CrossChainTransferParams); - await DefaultTransactionAPI.sendLogged(apiPromise, selectedAccount.address, tx, undefined, true); + await DefaultTransactionAPI.sendLogged( + apiPromise, + selectedAccount.address, + tx, + undefined, + InBlockExtrinsicStatus + ); }; await sendTransaction(); diff --git a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx index c7c5321a41..0ca090a5fd 100644 --- a/src/pages/Vaults/Vault/RequestIssueModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestIssueModal/index.tsx @@ -44,7 +44,7 @@ import SubmittedIssueRequestModal from '@/pages/Bridge/IssueForm/SubmittedIssueR import { ForeignAssetIdLiteral } from '@/types/currency'; import { KUSAMA, POLKADOT } from '@/utils/constants/relay-chain-names'; import STATUSES from '@/utils/constants/statuses'; -import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { FinalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { getTokenPrice } from '@/utils/helpers/prices'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -189,7 +189,7 @@ const RequestIssueModal = ({ onClose, open, collateralToken, vaultAddress }: Pro ); // When requesting an issue, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 - const extrinsicResult = await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + const extrinsicResult = await submitExtrinsic(extrinsicData, FinalizedExtrinsicStatus); const issueRequests = await getIssueRequestsFromExtrinsicResult(window.bridge, extrinsicResult); // TODO: handle issue aggregation diff --git a/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx b/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx index 851255b43f..ef5904a564 100644 --- a/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestRedeemModal/index.tsx @@ -17,7 +17,7 @@ import ErrorMessage from '@/legacy-components/ErrorMessage'; import NumberInput from '@/legacy-components/NumberInput'; import TextField from '@/legacy-components/TextField'; import InterlayModal, { InterlayModalInnerWrapper, InterlayModalTitle } from '@/legacy-components/UI/InterlayModal'; -import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { FinalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; const WRAPPED_TOKEN_AMOUNT = 'amount'; const BTC_ADDRESS = 'btc-address'; @@ -64,7 +64,7 @@ const RequestRedeemModal = ({ onClose, open, collateralToken, vaultAddress, lock const extrinsicData = await window.bridge.redeem.request(amountPolkaBtc, data[BTC_ADDRESS], vaultId); // When requesting a redeem, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 - await submitExtrinsic(extrinsicData, finalizedExtrinsicStatus); + await submitExtrinsic(extrinsicData, FinalizedExtrinsicStatus); queryClient.invalidateQueries(['vaultsOverview', vaultAddress, collateralToken.ticker]); diff --git a/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx b/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx index 42186fc748..61a3aa2c4e 100644 --- a/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx +++ b/src/pages/Vaults/Vault/RequestReplacementModal/index.tsx @@ -25,7 +25,7 @@ import PrimaryColorEllipsisLoader from '@/legacy-components/PrimaryColorEllipsis import InterlayModal, { InterlayModalInnerWrapper, InterlayModalTitle } from '@/legacy-components/UI/InterlayModal'; import { GENERIC_FETCHER } from '@/services/fetchers/generic-fetcher'; import STATUSES from '@/utils/constants/statuses'; -import { finalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { FinalizedExtrinsicStatus, submitExtrinsic } from '@/utils/helpers/extrinsic'; import { getExchangeRate } from '@/utils/helpers/oracle'; import { useGetBalances } from '@/utils/hooks/api/tokens/use-get-balances'; @@ -107,7 +107,7 @@ const RequestReplacementModal = ({ const amountPolkaBtc = new BitcoinAmount(data[AMOUNT]); // When requesting a replace, wait for the finalized event because we cannot revert BTC transactions. // For more details see: https://github.com/interlay/interbtc-api/pull/373#issuecomment-1058949000 - submitExtrinsic(window.bridge.replace.request(amountPolkaBtc, collateralToken), finalizedExtrinsicStatus); + submitExtrinsic(window.bridge.replace.request(amountPolkaBtc, collateralToken), FinalizedExtrinsicStatus); const vaultId = window.bridge.api.createType(ACCOUNT_ID_TYPE_NAME, vaultAddress); queryClient.invalidateQueries([GENERIC_FETCHER, 'mapReplaceRequests', vaultId]); diff --git a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx index 5fa2fcbe6d..e2bc840f77 100644 --- a/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx +++ b/src/pages/Vaults/Vault/components/Rewards/Rewards.tsx @@ -10,7 +10,7 @@ import { LoadingSpinner } from '@/component-library/LoadingSpinner'; import { GOVERNANCE_TOKEN_SYMBOL, WRAPPED_TOKEN } from '@/config/relay-chains'; import ErrorModal from '@/legacy-components/ErrorModal'; import { ZERO_GOVERNANCE_TOKEN_AMOUNT } from '@/utils/constants/currency'; -import { submitExtrinsic } from '@/utils/helpers/extrinsic'; +import { submitExtrinsicPromise } from '@/utils/helpers/extrinsic'; import { VaultData } from '@/utils/hooks/api/vaults/get-vault-data'; import useAccountId from '@/utils/hooks/use-account-id'; @@ -62,7 +62,7 @@ const Rewards = ({ WRAPPED_TOKEN as WrappedCurrency ); - return submitExtrinsic(window.bridge.rewards.withdrawRewards(vaultId)); + return submitExtrinsicPromise(window.bridge.rewards.withdrawRewards(vaultId)); }, { onSuccess: () => { diff --git a/src/utils/helpers/extrinsic.ts b/src/utils/helpers/extrinsic.ts index ea3d1fdfeb..6d9759b6d6 100644 --- a/src/utils/helpers/extrinsic.ts +++ b/src/utils/helpers/extrinsic.ts @@ -2,8 +2,8 @@ import { ExtrinsicData, newExtrinsicStatus } from '@interlay/interbtc-api'; import { ExtrinsicStatus } from '@polkadot/types/interfaces/author'; import { ISubmittableResult } from '@polkadot/types/types'; -const inBlockExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'InBlock'); -const finalizedExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'Finalized'); +const InBlockExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'InBlock'); +const FinalizedExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'Finalized'); /** * Helper to simple extrinsic submission. Waits for inBlock inclusion only by default. @@ -13,7 +13,7 @@ const finalizedExtrinsicStatus = newExtrinsicStatus(window.bridge.api, 'Finalize */ const submitExtrinsic = async ( extrinsicData: ExtrinsicData, - extrinsicStatus: ExtrinsicStatus = inBlockExtrinsicStatus + extrinsicStatus: ExtrinsicStatus = InBlockExtrinsicStatus ): Promise => { const { extrinsic, event } = extrinsicData; return await window.bridge.transaction.sendLogged(extrinsic, event, extrinsicStatus); @@ -21,10 +21,10 @@ const submitExtrinsic = async ( const submitExtrinsicPromise = async ( extrinsicDataPromise: Promise, - extrinsicStatus: ExtrinsicStatus = inBlockExtrinsicStatus + extrinsicStatus: ExtrinsicStatus = InBlockExtrinsicStatus ): Promise => { const extrinsicData = await extrinsicDataPromise; return submitExtrinsic(extrinsicData, extrinsicStatus); }; -export { finalizedExtrinsicStatus, inBlockExtrinsicStatus, submitExtrinsic, submitExtrinsicPromise }; +export { FinalizedExtrinsicStatus, InBlockExtrinsicStatus, submitExtrinsic, submitExtrinsicPromise }; diff --git a/yarn.lock b/yarn.lock index e1db99f1ba..83a0cc6261 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2564,10 +2564,10 @@ dependencies: axios "^0.21.1" -"@interlay/interbtc-api@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@interlay/interbtc-api/-/interbtc-api-2.0.3.tgz#21dd39e5539cf6967c5bc5e641501ed3d4cddf68" - integrity sha512-holtYk240R+MBERc5iZ48FoorwezNSgAt3rVUksqa61tguofc6agNK5sP/MDjKUZi8JLImlDYt7VmhOs9O88og== +"@interlay/interbtc-api@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@interlay/interbtc-api/-/interbtc-api-2.1.0.tgz#bfc07955650bf37f26551567af30004d3f179c78" + integrity sha512-qbANaXMGleigAyYFDj/P073yNjYlX/oboRbBnzY4KEQxQReqf8jShRSrv35m/MSOSQNd45gNTLQJ4UKpUdkCqg== dependencies: "@interlay/esplora-btc-api" "0.4.0" "@interlay/interbtc-types" "1.12.0" From d109ba4dfbc0a5e27ec102ff821686d4bd546c8a Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 19 Apr 2023 21:56:42 +0200 Subject: [PATCH 51/69] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84691ad719..0d4b8da937 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "interbtc-ui", - "version": "2.29.7", + "version": "2.30.0", "private": true, "dependencies": { "@craco/craco": "^6.1.1", From d2d764df55ec3a3b4f77ac42fb13ac5816e0eddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Wed, 1 Mar 2023 17:09:48 +0000 Subject: [PATCH 52/69] feat(Select): add Modal Select --- package.json | 2 + .../Select/Select.stories.tsx | 49 +++- src/component-library/Select/Select.style.tsx | 12 +- src/component-library/Select/Select.tsx | 111 +++++++++ src/component-library/Select/SelectModal.tsx | 63 +++++ src/component-library/Select/index.tsx | 3 + yarn.lock | 217 ++++++++++++++++++ 7 files changed, 453 insertions(+), 4 deletions(-) create mode 100644 src/component-library/Select/Select.tsx create mode 100644 src/component-library/Select/SelectModal.tsx diff --git a/package.json b/package.json index 93453c3386..2f0dc3e2c9 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@react-aria/meter": "^3.2.1", "@react-aria/overlays": "^3.12.0", "@react-aria/progress": "^3.3.0", + "@react-aria/select": "^3.9.0", "@react-aria/separator": "^3.2.5", "@react-aria/switch": "^3.2.4", "@react-aria/table": "^3.4.0", @@ -35,6 +36,7 @@ "@react-stately/collections": "^3.4.1", "@react-stately/list": "^3.6.1", "@react-stately/overlays": "^3.4.3", + "@react-stately/select": "^3.4.0", "@react-stately/table": "^3.3.0", "@react-stately/tabs": "^3.1.1", "@react-stately/toggle": "^3.4.2", diff --git a/src/component-library/Select/Select.stories.tsx b/src/component-library/Select/Select.stories.tsx index 9651ad243f..2a9edbb3d4 100644 --- a/src/component-library/Select/Select.stories.tsx +++ b/src/component-library/Select/Select.stories.tsx @@ -1,9 +1,56 @@ +import { Item } from '@react-stately/collections'; import { Meta, Story } from '@storybook/react'; import { CoinIcon } from '../CoinIcon'; import { Flex } from '../Flex'; +import { Select, SelectProps } from './Select'; import { SelectTrigger, SelectTriggerProps } from './SelectTrigger'; +const SelectTemplate: Story = (args) => { + return ( + + ); +}; + +const Default = SelectTemplate.bind({}); +Default.args = { + placeholder: 'placeholder', + label: 'Coin', + description: 'Select a coin', + size: 'large' +}; + const Template: Story = (args) => ; const Trigger = Template.bind({}); Trigger.args = { @@ -16,7 +63,7 @@ Trigger.args = { ) }; -export { Trigger }; +export { Default, Trigger }; export default { title: 'Forms/Select', diff --git a/src/component-library/Select/Select.style.tsx b/src/component-library/Select/Select.style.tsx index 69c775ca8f..6105ce5a59 100644 --- a/src/component-library/Select/Select.style.tsx +++ b/src/component-library/Select/Select.style.tsx @@ -1,5 +1,6 @@ import styled from 'styled-components'; +import { List } from '../List'; import { Span } from '../Text'; import { theme } from '../theme'; import { Sizes } from '../utils/prop-types'; @@ -29,8 +30,8 @@ const StyledTrigger = styled.button` justify-content: space-between; width: 100%; text-align: left; - // TODO: figure out this z-index when select is fully added - z-index: 1000; + /* // TODO: figure out this z-index when select is fully added + z-index: 1000; */ font-size: ${({ $size }) => theme.select.size[$size].text}; line-height: ${theme.lineHeight.base}; @@ -73,4 +74,9 @@ const StyledTriggerValue = styled(Span)` $isDisabled ? theme.input.disabled.color : $isSelected ? theme.select.color : theme.select.placeholder}; `; -export { StyledTrigger, StyledTriggerValue }; +const StyledList = styled(List)` + overflow: auto; + padding: 0 ${theme.modal.body.paddingX} ${theme.modal.body.paddingY} ${theme.modal.body.paddingX}; +`; + +export { StyledList, StyledTrigger, StyledTriggerValue }; diff --git a/src/component-library/Select/Select.tsx b/src/component-library/Select/Select.tsx new file mode 100644 index 0000000000..8a97c2a297 --- /dev/null +++ b/src/component-library/Select/Select.tsx @@ -0,0 +1,111 @@ +import { useSelect } from '@react-aria/select'; +import { chain, mergeProps } from '@react-aria/utils'; +import { VisuallyHidden } from '@react-aria/visually-hidden'; +import { useSelectState } from '@react-stately/select'; +import { CollectionBase } from '@react-types/shared'; +import { forwardRef, Key, useRef } from 'react'; + +import { Field, FieldProps, useFieldProps } from '../Field'; +import { hasErrorMessage } from '../HelperText/HelperText'; +import { useDOMRef } from '../utils/dom'; +import { Sizes } from '../utils/prop-types'; +import { SelectModal } from './SelectModal'; +import { SelectTrigger } from './SelectTrigger'; + +type Props = { + open?: boolean; + loading?: boolean; + size?: Sizes; +}; + +type InheritAttrs = Omit & FieldProps, keyof Props>; + +type NativeAttrs = Omit, keyof Props>; + +type SelectProps = Props & NativeAttrs & InheritAttrs; + +const Select = forwardRef( + (props, ref): JSX.Element => { + const { name, disabled, loading, open, required, label, errorMessage, size = 'medium', onChange, ...rest } = props; + + const inputRef = useDOMRef(ref); + + const handleSelectionChange = (key: Key) => { + const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set; + setValue?.call(inputRef.current, key); + + const e = new Event('input', { bubbles: true }); + inputRef.current?.dispatchEvent(e); + }; + + const ariaProps = { + isDisabled: disabled, + isLoading: loading, + isOpen: open, + isRequired: required, + name, + ...rest + }; + + const state = useSelectState({ ...ariaProps, onSelectionChange: handleSelectionChange }); + + const buttonRef = useRef(null); + + // MEMO: `menuProps` and `triggerProps` not implemented yet + const { labelProps, valueProps, descriptionProps, errorMessageProps } = useSelect(ariaProps, state, buttonRef); + + const { fieldProps, elementProps } = useFieldProps({ + ...rest, + descriptionProps, + errorMessageProps, + errorMessage, + labelProps, + label + }); + + const hasError = hasErrorMessage(errorMessage); + + return ( + + + buttonRef.current?.focus()} + tabIndex={-1} + /> + + { + state.setOpen(true); + buttonRef.current?.blur(); + } + })} + ref={buttonRef} + size={size} + valueProps={valueProps} + hasError={hasError} + placeholder='Select an option' + > + {state.selectedItem && state.selectedItem.rendered} + + + + ); + } +); + +Select.displayName = 'Select'; + +export { Select }; +export type { SelectProps }; diff --git a/src/component-library/Select/SelectModal.tsx b/src/component-library/Select/SelectModal.tsx new file mode 100644 index 0000000000..a2456cf679 --- /dev/null +++ b/src/component-library/Select/SelectModal.tsx @@ -0,0 +1,63 @@ +import { ListState } from '@react-stately/list'; +import { Key } from 'react'; + +import { Modal, ModalBody, ModalHeader, ModalProps } from '@/component-library/Modal'; + +import { ListItem, ListProps } from '../List'; +import { StyledList } from './Select.style'; + +type Props = { + onSelectionChange?: (key: Key) => void; + selectedAccount?: Key; + state: ListState; +}; + +type InheritAttrs = Omit; + +type SelectModalProps = Props & InheritAttrs; + +const SelectModal = ({ selectedAccount, state, onSelectionChange, ...props }: SelectModalProps): JSX.Element => { + const handleSelectionChange: ListProps['onSelectionChange'] = (key) => { + const [selectedKey] = [...key]; + + if (!selectedKey) return; + + onSelectionChange?.(selectedKey); + state.selectionManager.setSelectedKeys(key); + }; + + return ( + + + Select Account + + + + {[...state.collection].map((item) => { + return ( + + {item.rendered} + + ); + })} + {} + + + + ); +}; + +export { SelectModal }; diff --git a/src/component-library/Select/index.tsx b/src/component-library/Select/index.tsx index c27c1e8969..a29a0425ca 100644 --- a/src/component-library/Select/index.tsx +++ b/src/component-library/Select/index.tsx @@ -1,2 +1,5 @@ +export type { SelectProps } from './Select'; +export { Select } from './Select'; export type { SelectTriggerProps } from './SelectTrigger'; export { SelectTrigger } from './SelectTrigger'; +export { Item } from '@react-stately/collections'; diff --git a/yarn.lock b/yarn.lock index e1db99f1ba..f1240c2902 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2621,6 +2621,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@internationalized/date@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.1.0.tgz#da48aeaa971df6ad410cd32597c174d6cab9a3b4" + integrity sha512-wjeur7K4AecT+YwoBmBXQ/+n5lP69tuZc34hw09s44EozZK7FZHSyfPvRp5/xEb2D6abLboskDY4jG+Nt0TNUQ== + dependencies: + "@swc/helpers" "^0.4.14" + "@internationalized/message@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.0.10.tgz#340dcfd14ace37234e09419427c991a0c466b96e" @@ -2645,6 +2652,14 @@ "@babel/runtime" "^7.6.2" intl-messageformat "^10.1.0" +"@internationalized/message@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.0.tgz#b284014cd8bbb430a648b76c87c62bdca968b04c" + integrity sha512-Oo5m70FcBdADf7G8NkUffVSfuCdeAYVfsvNjZDi9ELpjvkc4YNJVTHt/NyTI9K7FgAVoELxiP9YmN0sJ+HNHYQ== + dependencies: + "@swc/helpers" "^0.4.14" + intl-messageformat "^10.1.0" + "@internationalized/number@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.1.1.tgz#160584316741de4381689ab759001603ee17b595" @@ -2659,6 +2674,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@internationalized/number@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.2.0.tgz#dffb661cacd61a87b814c47b7d5240a286249066" + integrity sha512-GUXkhXSX1Ee2RURnzl+47uvbOxnlMnvP9Er+QePTjDjOPWuunmLKlEkYkEcLiiJp7y4l9QxGDLOlVr8m69LS5w== + dependencies: + "@swc/helpers" "^0.4.14" + "@internationalized/string@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.0.0.tgz#de563871e1b19e4d0ce3246ec18d25da1a73db73" @@ -2673,6 +2695,13 @@ dependencies: "@swc/helpers" "^0.4.14" +"@internationalized/string@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.1.0.tgz#0b365906a8c3f44800b0db52c2e990cff345abce" + integrity sha512-TJQKiyUb+wyAfKF59UNeZ/kELMnkxyecnyPCnBI1ma4NaXReJW+7Cc2mObXAqraIBJUVv7rgI46RLKrLgi35ng== + dependencies: + "@swc/helpers" "^0.4.14" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -4061,6 +4090,20 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-aria/i18n@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.7.0.tgz#c1dfcd7a76a5161cbccbd6980ecf201c9b4d1826" + integrity sha512-PZCWmhO9mJvelwiYlsXLY6W4L2o+oza3xnDx0cZDVqp/Hf+OwMAPHWtZsFRTKdjk4TaOPB/ISc9HknWn6UpY4w== + dependencies: + "@internationalized/date" "^3.1.0" + "@internationalized/message" "^3.1.0" + "@internationalized/number" "^3.2.0" + "@internationalized/string" "^3.1.0" + "@react-aria/ssr" "^3.5.0" + "@react-aria/utils" "^3.15.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/interactions@^3.10.0": version "3.10.0" resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.10.0.tgz#d60cc42c3904c1578f9c356fba4bab7003102dee" @@ -4180,6 +4223,24 @@ dependencies: "@swc/helpers" "^0.4.14" +"@react-aria/menu@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.8.0.tgz#847396ce69757cc3780c00cbd838deaf4a8cca90" + integrity sha512-5V/EXzdxFxJc1Dh7rqYWeGWeHLgIwyyN4fv+u1Y5+q5dikgTVplbjnO34VHMELHHVWDIqvSikJSyYsdKprVnEQ== + dependencies: + "@react-aria/i18n" "^3.7.0" + "@react-aria/interactions" "^3.14.0" + "@react-aria/overlays" "^3.13.0" + "@react-aria/selection" "^3.13.0" + "@react-aria/utils" "^3.15.0" + "@react-stately/collections" "^3.6.0" + "@react-stately/menu" "^3.5.0" + "@react-stately/tree" "^3.5.0" + "@react-types/button" "^3.7.1" + "@react-types/menu" "^3.8.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/meter@^3.2.1": version "3.2.1" resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.2.1.tgz#c34526a2cde2f00f4c0f64a5e085ccd416d61d08" @@ -4207,6 +4268,23 @@ "@react-types/overlays" "^3.6.5" "@react-types/shared" "^3.16.0" +"@react-aria/overlays@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.13.0.tgz#f5a8cdce4754b4fd487baf9f356a5a3cdd731c12" + integrity sha512-hRZyhAYzrlCcEWQ2k2jP24b0wc5/355Xl5w5FZHRmPeU1U4XlFwKX/eFlBs/li9Sprm1bTDXrCY480Kl6UsKDA== + dependencies: + "@react-aria/focus" "^3.11.0" + "@react-aria/i18n" "^3.7.0" + "@react-aria/interactions" "^3.14.0" + "@react-aria/ssr" "^3.5.0" + "@react-aria/utils" "^3.15.0" + "@react-aria/visually-hidden" "^3.7.0" + "@react-stately/overlays" "^3.5.0" + "@react-types/button" "^3.7.1" + "@react-types/overlays" "^3.7.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/progress@^3.2.1", "@react-aria/progress@^3.3.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.3.0.tgz#ae2745da40ad84331c05ec33efe0d5f3a9220df5" @@ -4219,6 +4297,25 @@ "@react-types/progress" "^3.2.2" "@react-types/shared" "^3.14.0" +"@react-aria/select@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.9.0.tgz#cada84973b2fd16cdc0215f7a5e30ac1b60e1970" + integrity sha512-sS/y32BFzHWMeQeeBTdnRuFERgF/8WM2qj6p7e9+F68Nb4Lz8Qpneb2pwWD6a+Dl4UGS1yQMSdZOOnS6aBW41w== + dependencies: + "@react-aria/i18n" "^3.7.0" + "@react-aria/interactions" "^3.14.0" + "@react-aria/label" "^3.5.0" + "@react-aria/listbox" "^3.8.0" + "@react-aria/menu" "^3.8.0" + "@react-aria/selection" "^3.13.0" + "@react-aria/utils" "^3.15.0" + "@react-aria/visually-hidden" "^3.7.0" + "@react-stately/select" "^3.4.0" + "@react-types/button" "^3.7.1" + "@react-types/select" "^3.7.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/selection@^3.10.0": version "3.10.0" resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.10.0.tgz#c7c0441d9b496df6567af1c4462e4a80f97ea359" @@ -4247,6 +4344,20 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-aria/selection@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.13.0.tgz#3a2c01fe9bead75bde251ce207c89da594fe2dfb" + integrity sha512-KU8xWd2wzL6jacWZeXFx1p6uQ1qAvE4F+K3LqUbj+kWBdmEGYkri9t17A1zQdN7sjaN9cH61eojGpEXYskz01w== + dependencies: + "@react-aria/focus" "^3.11.0" + "@react-aria/i18n" "^3.7.0" + "@react-aria/interactions" "^3.14.0" + "@react-aria/utils" "^3.15.0" + "@react-stately/collections" "^3.6.0" + "@react-stately/selection" "^3.12.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-aria/selection@^3.9.1": version "3.9.1" resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.9.1.tgz#8bb58be6b39bf2e617a4489a6168e39aa0a08098" @@ -4489,6 +4600,17 @@ "@swc/helpers" "^0.4.14" clsx "^1.1.1" +"@react-aria/visually-hidden@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.7.0.tgz#4056b8bb33f30ca8c5192dfcf706ac8bb2beb61a" + integrity sha512-v/0ujJ67H6LjwY8J7mIGPVB1K8suBArLV+w8UGdX/wFXRL7H4r2fiqlrwAElWSmNbhDQl5BDm/Zh/ub9jB9yzA== + dependencies: + "@react-aria/interactions" "^3.14.0" + "@react-aria/utils" "^3.15.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" + "@react-stately/collections@^3.4.1": version "3.4.1" resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.4.1.tgz#12fb2244243d3b6deec6b5e4f59b8979f745efda" @@ -4513,6 +4635,14 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-stately/collections@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.6.0.tgz#4fbecbbbb354badbc46618262e91743754257673" + integrity sha512-znkaqCPo7F1yyzEKDAB5MpX1Vw5UHcUQhDNrys5YOqAkX6/G/AChnBz0B63UxS3fjyqgnuJylRRmUp9nTqO21w== + dependencies: + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-stately/grid@^3.3.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.3.0.tgz#f55d6bd74b74a81d35282cd2b552ee2ae2b9bbbf" @@ -4555,6 +4685,28 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-stately/list@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.7.0.tgz#7484cc46d995a18b2b43de50449aba7faae76809" + integrity sha512-/BxCqXFjX9P+OJWjIYmUWaOGJ2hlZHUdymVwZPkIWdO9K7069LWckdYFXRqLFMwIGLUcXVfw4jR0BIQqWlR4eA== + dependencies: + "@react-stately/collections" "^3.6.0" + "@react-stately/selection" "^3.12.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + +"@react-stately/menu@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.5.0.tgz#04fda461dc3971bc84bf49436625b3e044bca3bc" + integrity sha512-JL6TcT+SbYdlxNLOS84SXp6njDNZuXfkt05o4rS51evmjM2+hlYaB9+yUMqrCb/J2nW7vVAg51TDAhLgmGTYKg== + dependencies: + "@react-stately/overlays" "^3.5.0" + "@react-stately/utils" "^3.6.0" + "@react-types/menu" "^3.8.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-stately/overlays@^3.4.3": version "3.4.3" resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.4.3.tgz#2e935c404c0845ee7a7c6f001ff057d315161a16" @@ -4564,6 +4716,29 @@ "@react-stately/utils" "^3.5.1" "@react-types/overlays" "^3.6.5" +"@react-stately/overlays@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.5.0.tgz#3c33a6f678f728497c94729e8a861ddf1e8704bb" + integrity sha512-r+U/G0Y4tCfI5wyBeIu+hmcZVRN8ChoK2zM1srPH9nDKsijQard2goX+9YmKng2LJ01Re/P6F8S8jYbpfEdLfQ== + dependencies: + "@react-stately/utils" "^3.6.0" + "@react-types/overlays" "^3.7.0" + "@swc/helpers" "^0.4.14" + +"@react-stately/select@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.4.0.tgz#e6df572279b5baed264552032f8060dbf49c9ebb" + integrity sha512-thSqD3apMCSgZgKtqHKGVIQRyvG8l0supIuzJicBwq6xg+J8X5muPCZgchCSNmU6im/l81XXE8LGuHGgMilORA== + dependencies: + "@react-stately/collections" "^3.6.0" + "@react-stately/list" "^3.7.0" + "@react-stately/menu" "^3.5.0" + "@react-stately/selection" "^3.12.0" + "@react-stately/utils" "^3.6.0" + "@react-types/select" "^3.7.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-stately/selection@^3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.10.1.tgz#dcfb87b6e7bb32db6fd17c083201e1258d5639d0" @@ -4594,6 +4769,16 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-stately/selection@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.12.0.tgz#feb5ad753ea93870566f2c0b07f0387b690bd860" + integrity sha512-qgUaPwqtAl7YaZxxGdb55ZaVuMB1rG+Vr+9fgG8dPtDYCNaPeIlg7ndC4ylzDhCWIx8D5qZotcrqCA4+93TwdA== + dependencies: + "@react-stately/collections" "^3.6.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-stately/table@^3.3.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.3.0.tgz#87f2b69e323e5f805705d6a722b6ef3d6389319c" @@ -4658,6 +4843,17 @@ "@react-types/shared" "^3.16.0" "@swc/helpers" "^0.4.14" +"@react-stately/tree@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.5.0.tgz#1d0dffd93c17b004953c27817be1ae2da9f96e5b" + integrity sha512-5+MzMQUFq3+lbGkZC0SlcIDrYmPvxBKuC8xL5W6SuFekbrrxrS6IJexRe4QulaaAliDpX2/9DVZTt38eVfyf0A== + dependencies: + "@react-stately/collections" "^3.6.0" + "@react-stately/selection" "^3.12.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.17.0" + "@swc/helpers" "^0.4.14" + "@react-stately/utils@^3.5.0": version "3.5.0" resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.5.0.tgz#e76231cfc93042814dcc5d96436e50c807c1d905" @@ -4718,6 +4914,13 @@ dependencies: "@react-types/shared" "^3.16.0" +"@react-types/button@^3.7.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.7.1.tgz#a51d2617a593d9862c72306b3bf0c4b5bff4793d" + integrity sha512-c+8xjmqWSjI5/mEHVLbVSp0eh/z2UU8Ga+wqjbEUZUjm8uopYj1PaCAwZ7YgcAebyQrL/21GyjK6tFHKzuUdJQ== + dependencies: + "@react-types/shared" "^3.17.0" + "@react-types/checkbox@^3.3.2": version "3.3.2" resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.3.2.tgz#513442cb2e73a4d8c8ad14021c424612e98e7cd7" @@ -4805,6 +5008,13 @@ dependencies: "@react-types/shared" "^3.16.0" +"@react-types/overlays@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.7.0.tgz#22dcd1bbc1f8e17b0d7a757414c50ce580ae0d26" + integrity sha512-LstucncZ8dM+xJYEijI1V6jGH20w5XO/T60r7JTrgQElMC86phPeoWkMTN4c2lsRikybolDbvXL6XsF76YO56A== + dependencies: + "@react-types/shared" "^3.17.0" + "@react-types/progress@^3.2.2": version "3.2.2" resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.2.2.tgz#17fd42b0241eba5a21ab4128c654f8d0e0738138" @@ -4812,6 +5022,13 @@ dependencies: "@react-types/shared" "^3.14.0" +"@react-types/select@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.7.0.tgz#7d1840525d345625ac6ad69005b192930ca5abec" + integrity sha512-BaynMuW0dQ9ModFzW291+3n1D9bwKSFh03g3+1PvhRcBg1EXq1vFyfFBj4uuBymI0T7oCbnjGh19xo0vKIYRrA== + dependencies: + "@react-types/shared" "^3.17.0" + "@react-types/shared@^3.13.1": version "3.13.1" resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.13.1.tgz#eda5e3744971606f753baf7879136bf8e3f707ab" From 67290c90caedcc7cdbe00257366a9661deb0111d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Thu, 2 Mar 2023 16:18:07 +0000 Subject: [PATCH 53/69] continue --- src/component-library/Label/Label.style.tsx | 8 +- src/component-library/Label/Label.tsx | 12 +- .../Select/Select.stories.tsx | 1 + src/component-library/Select/Select.style.tsx | 37 +++-- src/component-library/Select/Select.tsx | 122 ++++++++++----- src/component-library/Select/SelectModal.tsx | 99 ++++++------ .../Select/SelectModalContext.tsx | 19 +++ .../Select/SelectTrigger.tsx | 17 +- .../TokenInput/TokenInput.style.tsx | 22 ++- .../TokenInput/TokenInput.tsx | 2 + .../TokenInput/TokenSelect.tsx | 146 ++++++++++-------- src/component-library/css/index.ts | 15 +- src/component-library/theme/theme.ts | 9 +- 13 files changed, 311 insertions(+), 198 deletions(-) create mode 100644 src/component-library/Select/SelectModalContext.tsx diff --git a/src/component-library/Label/Label.style.tsx b/src/component-library/Label/Label.style.tsx index 55c1a22cb1..080fcd267a 100644 --- a/src/component-library/Label/Label.style.tsx +++ b/src/component-library/Label/Label.style.tsx @@ -1,13 +1,19 @@ import styled from 'styled-components'; +import { visuallyHidden } from '../css'; import { theme } from '../theme'; -const StyledLabel = styled.label` +type StyledLabelProps = { + $isVisuallyHidden?: boolean; +}; + +const StyledLabel = styled.label` font-weight: ${theme.fontWeight.medium}; line-height: ${theme.lineHeight.lg}; font-size: ${theme.text.xs}; color: ${theme.colors.textTertiary}; padding: ${theme.spacing.spacing1} 0; + ${({ $isVisuallyHidden }) => $isVisuallyHidden && visuallyHidden()} `; export { StyledLabel }; diff --git a/src/component-library/Label/Label.tsx b/src/component-library/Label/Label.tsx index 927b2b149b..490e90852d 100644 --- a/src/component-library/Label/Label.tsx +++ b/src/component-library/Label/Label.tsx @@ -2,13 +2,17 @@ import { forwardRef, LabelHTMLAttributes } from 'react'; import { StyledLabel } from './Label.style'; -type NativeAttrs = LabelHTMLAttributes; +type Props = { + isVisuallyHidden?: boolean; +}; -type LabelProps = NativeAttrs; +type NativeAttrs = Omit, keyof Props>; + +type LabelProps = Props & NativeAttrs; const Label = forwardRef( - ({ children, ...props }, ref): JSX.Element => ( - + ({ children, isVisuallyHidden, ...props }, ref): JSX.Element => ( + {children} ) diff --git a/src/component-library/Select/Select.stories.tsx b/src/component-library/Select/Select.stories.tsx index 2a9edbb3d4..3cacaba1c3 100644 --- a/src/component-library/Select/Select.stories.tsx +++ b/src/component-library/Select/Select.stories.tsx @@ -45,6 +45,7 @@ const SelectTemplate: Story = (args) => { const Default = SelectTemplate.bind({}); Default.args = { + type: 'modal', placeholder: 'placeholder', label: 'Coin', description: 'Select a coin', diff --git a/src/component-library/Select/Select.style.tsx b/src/component-library/Select/Select.style.tsx index 6105ce5a59..885de8450e 100644 --- a/src/component-library/Select/Select.style.tsx +++ b/src/component-library/Select/Select.style.tsx @@ -1,5 +1,7 @@ import styled from 'styled-components'; +import { ChevronDown } from '@/assets/icons'; + import { List } from '../List'; import { Span } from '../Text'; import { theme } from '../theme'; @@ -9,8 +11,8 @@ type StyledTriggerProps = { $isOpen?: boolean; $isFocusVisible?: boolean; $size: Sizes; - $isDisabled?: boolean; - $hasError?: boolean; + $isDisabled: boolean; + $hasError: boolean; }; type StyledTriggerValueProps = { @@ -23,39 +25,32 @@ const StyledTrigger = styled.button` font: inherit; letter-spacing: inherit; background: none; - appearance: none; + + font-size: ${({ $size }) => theme.select.size[$size].text}; + line-height: ${theme.lineHeight.base}; + color: ${(props) => (props.disabled ? theme.input.disabled.color : theme.input.color)}; + background-color: ${theme.input.background}; + overflow: hidden; display: inline-flex; align-items: center; justify-content: space-between; width: 100%; text-align: left; - /* // TODO: figure out this z-index when select is fully added - z-index: 1000; */ - font-size: ${({ $size }) => theme.select.size[$size].text}; - line-height: ${theme.lineHeight.base}; + padding: ${({ $size }) => theme.select.size[$size].padding}; + cursor: pointer; + max-height: ${({ $size }) => `calc(${theme.input[$size].maxHeight} - 1px)`}; - // Inherited from Input styled - color: ${(props) => (props.disabled ? theme.input.disabled.color : theme.input.color)}; border: ${(props) => props.$isDisabled ? theme.input.disabled.border : props.$hasError ? theme.input.error.border : theme.border.default}; - background-color: ${theme.input.background}; - - max-height: calc(${theme.spacing.spacing16} - 1px); - - overflow: hidden; - border-radius: ${theme.rounded.md}; transition: border-color ${theme.transition.duration.duration150}ms ease-in-out, box-shadow ${theme.transition.duration.duration150}ms ease-in-out; - padding: ${({ $size }) => theme.select.size[$size].padding}; - - cursor: pointer; &:hover:not(:disabled):not(:focus) { border: ${(props) => !props.$isDisabled && !props.$hasError && theme.input.hover.border}; @@ -79,4 +74,8 @@ const StyledList = styled(List)` padding: 0 ${theme.modal.body.paddingX} ${theme.modal.body.paddingY} ${theme.modal.body.paddingX}; `; -export { StyledList, StyledTrigger, StyledTriggerValue }; +const StyledChevronDown = styled(ChevronDown)` + margin-left: ${theme.spacing.spacing2}; +`; + +export { StyledChevronDown, StyledList, StyledTrigger, StyledTriggerValue }; diff --git a/src/component-library/Select/Select.tsx b/src/component-library/Select/Select.tsx index 8a97c2a297..7968e4d91c 100644 --- a/src/component-library/Select/Select.tsx +++ b/src/component-library/Select/Select.tsx @@ -1,105 +1,145 @@ +import { useField } from '@react-aria/label'; import { useSelect } from '@react-aria/select'; import { chain, mergeProps } from '@react-aria/utils'; import { VisuallyHidden } from '@react-aria/visually-hidden'; -import { useSelectState } from '@react-stately/select'; -import { CollectionBase } from '@react-types/shared'; +import { SelectProps as AriaSelectProps, useSelectState } from '@react-stately/select'; +import { CollectionBase, Node } from '@react-types/shared'; import { forwardRef, Key, useRef } from 'react'; import { Field, FieldProps, useFieldProps } from '../Field'; import { hasErrorMessage } from '../HelperText/HelperText'; import { useDOMRef } from '../utils/dom'; +import { triggerChangeEvent } from '../utils/input'; import { Sizes } from '../utils/prop-types'; import { SelectModal } from './SelectModal'; import { SelectTrigger } from './SelectTrigger'; +// TODO: listbox to be implemented type Props = { + type?: 'listbox' | 'modal'; open?: boolean; loading?: boolean; size?: Sizes; + // MEMO: Allows a custom select trigger (TokenInput select) + asSelectTrigger?: any; + customRender?: (item: Node) => JSX.Element; }; -type InheritAttrs = Omit & FieldProps, keyof Props>; +type InheritAttrs = Omit< + CollectionBase & FieldProps & AriaSelectProps, + keyof Props | 'isDisabled' | 'isLoading' | 'isOpen' | 'isRequired' +>; type NativeAttrs = Omit, keyof Props>; type SelectProps = Props & NativeAttrs & InheritAttrs; const Select = forwardRef( - (props, ref): JSX.Element => { - const { name, disabled, loading, open, required, label, errorMessage, size = 'medium', onChange, ...rest } = props; - + ( + { + type = 'listbox', + name, + disabled, + loading, + open, + required, + label, + errorMessage, + size = 'medium', + onChange, + placeholder = 'Select an option', + asSelectTrigger, + onSelectionChange, + customRender = (item) => item.rendered, + ...props + }, + ref + ): JSX.Element => { const inputRef = useDOMRef(ref); + const buttonRef = useRef(null); - const handleSelectionChange = (key: Key) => { - const setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set; - setValue?.call(inputRef.current, key); - - const e = new Event('input', { bubbles: true }); - inputRef.current?.dispatchEvent(e); - }; - - const ariaProps = { + const ariaProps: AriaSelectProps = { isDisabled: disabled, isLoading: loading, isOpen: open, isRequired: required, - name, - ...rest + onSelectionChange: chain((key: Key) => triggerChangeEvent(inputRef, key), onSelectionChange), + onOpenChange: (isOpen) => { + return isOpen ? buttonRef.current?.blur() : buttonRef.current?.focus(); + }, + label, + errorMessage, + placeholder, + ...props }; - const state = useSelectState({ ...ariaProps, onSelectionChange: handleSelectionChange }); - - const buttonRef = useRef(null); + const state = useSelectState(ariaProps); // MEMO: `menuProps` and `triggerProps` not implemented yet - const { labelProps, valueProps, descriptionProps, errorMessageProps } = useSelect(ariaProps, state, buttonRef); + const { labelProps, valueProps, triggerProps, descriptionProps, errorMessageProps } = useSelect( + ariaProps, + state, + buttonRef + ); const { fieldProps, elementProps } = useFieldProps({ - ...rest, + ...props, descriptionProps, errorMessageProps, errorMessage, - labelProps, + labelProps: mergeProps(labelProps, props.labelProps || {}), label }); const hasError = hasErrorMessage(errorMessage); + const selectTriggerProps = + type === 'listbox' + ? triggerProps + : mergeProps(props, { + onPress: () => { + // buttonRef.current?.blur(); + state.setOpen(true); + }, + id: triggerProps.id, + 'aria-labelledby': triggerProps['aria-labelledby'] + }); + + const { fieldProps: hiddenFieldProps, labelProps: hiddenLabelProps } = useField({ label }); + return ( + buttonRef.current?.focus()} tabIndex={-1} + {...hiddenFieldProps} /> { - state.setOpen(true); - buttonRef.current?.blur(); - } - })} + {...mergeProps(elementProps, selectTriggerProps)} + as={asSelectTrigger} ref={buttonRef} size={size} - valueProps={valueProps} hasError={hasError} - placeholder='Select an option' + valueProps={valueProps} + placeholder={placeholder} > - {state.selectedItem && state.selectedItem.rendered} + {state.selectedItem && customRender(state.selectedItem)} - + {type === 'modal' && ( + + )} ); } diff --git a/src/component-library/Select/SelectModal.tsx b/src/component-library/Select/SelectModal.tsx index a2456cf679..e453fcb460 100644 --- a/src/component-library/Select/SelectModal.tsx +++ b/src/component-library/Select/SelectModal.tsx @@ -1,63 +1,70 @@ -import { ListState } from '@react-stately/list'; -import { Key } from 'react'; +import { SelectState } from '@react-stately/select'; +import { forwardRef, Key } from 'react'; import { Modal, ModalBody, ModalHeader, ModalProps } from '@/component-library/Modal'; import { ListItem, ListProps } from '../List'; import { StyledList } from './Select.style'; +import { SelectModalContext } from './SelectModalContext'; type Props = { onSelectionChange?: (key: Key) => void; selectedAccount?: Key; - state: ListState; + state: SelectState; }; type InheritAttrs = Omit; type SelectModalProps = Props & InheritAttrs; -const SelectModal = ({ selectedAccount, state, onSelectionChange, ...props }: SelectModalProps): JSX.Element => { - const handleSelectionChange: ListProps['onSelectionChange'] = (key) => { - const [selectedKey] = [...key]; - - if (!selectedKey) return; - - onSelectionChange?.(selectedKey); - state.selectionManager.setSelectedKeys(key); - }; - - return ( - - - Select Account - - - - {[...state.collection].map((item) => { - return ( - - {item.rendered} - - ); - })} - {} - - - - ); -}; +const SelectModal = forwardRef( + ({ selectedAccount, state, onSelectionChange, onClose, ...props }, ref): JSX.Element => { + const handleSelectionChange: ListProps['onSelectionChange'] = (key) => { + const [selectedKey] = [...key]; + + if (!selectedKey) return; + + onSelectionChange?.(selectedKey); + state.selectionManager.setSelectedKeys(key); + onClose(); + }; + + return ( + + + + Select Account + + + + {[...state.collection].map((item) => { + return ( + + {item.rendered} + + ); + })} + + + + + ); + } +); + +SelectModal.displayName = 'SelectModal'; export { SelectModal }; diff --git a/src/component-library/Select/SelectModalContext.tsx b/src/component-library/Select/SelectModalContext.tsx new file mode 100644 index 0000000000..b7e1fca135 --- /dev/null +++ b/src/component-library/Select/SelectModalContext.tsx @@ -0,0 +1,19 @@ +import { Node } from '@react-types/shared'; +import React from 'react'; + +/* + Used to allow styling inside modal items +*/ + +interface SelectModalConfig { + selectedItem?: Node | null; +} + +const defaultContext = {}; + +const SelectModalContext = React.createContext(defaultContext); + +const useSelectModalContext = (): SelectModalConfig => React.useContext(SelectModalContext); + +export { SelectModalContext, useSelectModalContext }; +export type { SelectModalConfig }; diff --git a/src/component-library/Select/SelectTrigger.tsx b/src/component-library/Select/SelectTrigger.tsx index 2c0583f4c8..aa634d00eb 100644 --- a/src/component-library/Select/SelectTrigger.tsx +++ b/src/component-library/Select/SelectTrigger.tsx @@ -4,14 +4,13 @@ import { mergeProps } from '@react-aria/utils'; import { PressEvent } from '@react-types/shared'; import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react'; -import { ChevronDown } from '@/assets/icons'; - import { TextProps } from '../Text'; import { useDOMRef } from '../utils/dom'; import { Sizes } from '../utils/prop-types'; -import { StyledTrigger, StyledTriggerValue } from './Select.style'; +import { StyledChevronDown, StyledTrigger, StyledTriggerValue } from './Select.style'; type Props = { + as: any; size?: Sizes; isOpen?: boolean; hasError?: boolean; @@ -27,7 +26,7 @@ type SelectTriggerProps = Props & NativeAttrs; // MEMO: this is prune to change when `Select` is added const SelectTrigger = forwardRef( ( - { size = 'medium', hasError, isOpen, children, valueProps, placeholder = 'Select an option', ...props }, + { as, size = 'medium', hasError = false, isOpen, children, valueProps, placeholder = 'Select an option', ...props }, ref ): JSX.Element => { const { disabled } = props; @@ -38,11 +37,13 @@ const SelectTrigger = forwardRef( const { focusProps, isFocusVisible } = useFocusRing(); + const Comp = as || StyledTrigger; + return ( - ( {children || placeholder} - - + + ); } ); diff --git a/src/component-library/TokenInput/TokenInput.style.tsx b/src/component-library/TokenInput/TokenInput.style.tsx index a7896ce06c..e7af3abdfa 100644 --- a/src/component-library/TokenInput/TokenInput.style.tsx +++ b/src/component-library/TokenInput/TokenInput.style.tsx @@ -4,13 +4,10 @@ import { ChevronDown } from '@/assets/icons'; import { Flex } from '../Flex'; import { List } from '../List'; +import { StyledTrigger } from '../Select/Select.style'; import { Span } from '../Text'; import { theme } from '../theme'; -type StyledClickableProps = { - $isClickable: boolean; -}; - type StyledUSDAdornmentProps = { $isDisabled?: boolean; }; @@ -35,13 +32,23 @@ const StyledUSDAdornment = styled.span` align-self: flex-start; `; -const StyledTokenSelect = styled(Flex)` +const StyledTokenAdornment = styled(Flex)` + background-color: ${theme.tokenInput.endAdornment.bg}; + border-radius: ${theme.rounded.md}; + font-size: ${theme.text.s}; + padding: ${theme.spacing.spacing3}; + height: 3rem; + width: auto; + overflow: hidden; +`; + +const StyledTokenSelect = styled(StyledTrigger)` background-color: ${theme.tokenInput.endAdornment.bg}; border-radius: ${theme.rounded.md}; - font-size: ${theme.text.xl2}; + font-size: ${theme.text.s}; padding: ${theme.spacing.spacing3}; - cursor: ${({ $isClickable }) => $isClickable && 'pointer'}; height: 3rem; + max-height: 3rem; width: auto; overflow: hidden; `; @@ -99,6 +106,7 @@ export { StyledListItemLabel, StyledListTokenWrapper, StyledTicker, + StyledTokenAdornment, StyledTokenInputBalanceLabel, StyledTokenInputBalanceValue, StyledTokenInputBalanceWrapper, diff --git a/src/component-library/TokenInput/TokenInput.tsx b/src/component-library/TokenInput/TokenInput.tsx index 1f996f87fa..a08ca69499 100644 --- a/src/component-library/TokenInput/TokenInput.tsx +++ b/src/component-library/TokenInput/TokenInput.tsx @@ -107,6 +107,8 @@ const TokenInput = forwardRef( /> ); + console.log('here'); + const hasLabel = !!label || balance !== undefined; return ( diff --git a/src/component-library/TokenInput/TokenSelect.tsx b/src/component-library/TokenInput/TokenSelect.tsx index 0096690a54..8ee061d107 100644 --- a/src/component-library/TokenInput/TokenSelect.tsx +++ b/src/component-library/TokenInput/TokenSelect.tsx @@ -1,15 +1,20 @@ -import { useButton } from '@react-aria/button'; -import { useField } from '@react-aria/label'; -import { chain, mergeProps } from '@react-aria/utils'; -import { VisuallyHidden } from '@react-aria/visually-hidden'; -import { InputHTMLAttributes, ReactNode, useRef, useState } from 'react'; +import { mergeProps } from '@react-aria/utils'; +import { InputHTMLAttributes, ReactNode } from 'react'; import { CoinIcon } from '../CoinIcon'; +import { Flex } from '../Flex'; +import { Item, Select } from '../Select'; +import { useSelectModalContext } from '../Select/SelectModalContext'; +import { Span } from '../Text'; import { TokenStack } from '../TokenStack'; -import { useDOMRef } from '../utils/dom'; -import { StyledChevronDown, StyledTicker, StyledTokenSelect } from './TokenInput.style'; +import { + StyledListItemLabel, + StyledListTokenWrapper, + StyledTicker, + StyledTokenAdornment, + StyledTokenSelect +} from './TokenInput.style'; import { TokenData } from './TokenList'; -import { TokenListModal } from './TokenListModal'; const Icon = ({ value, icons }: Pick) => { if (!value) return null; @@ -21,7 +26,32 @@ const Icon = ({ value, icons }: Pick) => { return ; }; -type SelectProps = InputHTMLAttributes & { ref?: any; onSelectionChange?: (ticker: string) => void }; +const ListItem = ({ item }: { item: TokenData }) => { + const tickerText = typeof item.ticker === 'string' ? item.ticker : item.ticker.text; + + const isSelected = useSelectModalContext().selectedItem?.key === tickerText; + + return ( + <> + + {typeof item.ticker === 'string' ? ( + + ) : ( + + )} + {tickerText} + + + {item.balance} + + {item.balanceUSD} + + + + ); +}; + +type SelectProps = InputHTMLAttributes & { ref?: any }; type Props = { label?: ReactNode; @@ -43,70 +73,50 @@ const TokenSelect = ({ tokens, isDisabled, onChange, - label: labelProp, - 'aria-label': ariaLabel, - selectProps: selectPropsProp + label, + selectProps }: TokenSelectProps): JSX.Element => { - const [isOpen, setOpen] = useState(false); - - const tokenButtonRef = useRef(null); - - const { ref, onSelectionChange, ...selectProps } = selectPropsProp || {}; - const inputRef = useDOMRef(ref); - - const { buttonProps } = useButton( - { - onPress: () => setOpen(true), - elementType: 'div', - isDisabled - }, - tokenButtonRef - ); - - const label = labelProp || ariaLabel; - - const { labelProps, fieldProps } = useField({ label }); - - const handleClose = () => setOpen(false); - const isSelect = !isDisabled; - return ( - <> - {isSelect && ( - - - - - )} - + if (!isSelect) { + return ( + {value || 'Select Token'} - {isSelect && } - - {isSelect && ( - - )} - + + ); + } + + return ( + ); }; diff --git a/src/component-library/css/index.ts b/src/component-library/css/index.ts index c038356671..0316975e27 100644 --- a/src/component-library/css/index.ts +++ b/src/component-library/css/index.ts @@ -34,4 +34,17 @@ const hideScrollbar = (): FlattenInterpolation => css` scrollbar-width: none; /* Firefox */ `; -export { hideScrollbar, spaceX, spaceY }; +const visuallyHidden = (): FlattenInterpolation => css` + border: 0px; + clip: rect(0px, 0px, 0px, 0px); + clip-path: inset(50%); + height: 1px; + margin: 0px -1px -1px 0px; + overflow: hidden; + padding: 0px; + position: absolute; + width: 1px; + white-space: nowrap; +`; + +export { hideScrollbar, spaceX, spaceY, visuallyHidden }; diff --git a/src/component-library/theme/theme.ts b/src/component-library/theme/theme.ts index f8221e4a55..2c4d12724c 100644 --- a/src/component-library/theme/theme.ts +++ b/src/component-library/theme/theme.ts @@ -114,13 +114,16 @@ const theme = { } }, small: { - text: 'var(--text-s)' + text: 'var(--text-s)', + maxHeight: 'var(--spacing-8)' }, medium: { - text: 'var(--text-base)' + text: 'var(--text-base)', + maxHeight: 'var(--spacing-10)' }, large: { - text: 'var(--text-4xl)' + text: 'var(--text-4xl)', + maxHeight: 'var(--spacing-16)' }, overflow: { large: { From 217cc10583e5a0d991b46377434b75ffe32438d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Fri, 3 Mar 2023 15:13:40 +0000 Subject: [PATCH 54/69] final: done --- .../Select/Select.stories.tsx | 3 +- src/component-library/Select/Select.style.tsx | 18 +- src/component-library/Select/Select.tsx | 250 +++++++++--------- src/component-library/Select/SelectModal.tsx | 40 +-- .../Select/SelectTrigger.tsx | 2 +- .../TokenInput/TokenAdornment.tsx | 45 ++++ .../TokenInput/TokenInput.stories.tsx | 47 ++-- .../TokenInput/TokenInput.style.tsx | 1 + .../TokenInput/TokenInput.tsx | 65 ++--- .../TokenInput/TokenList.tsx | 78 ------ .../TokenInput/TokenListModal.tsx | 32 --- .../TokenInput/TokenSelect.tsx | 140 +++------- 12 files changed, 293 insertions(+), 428 deletions(-) create mode 100644 src/component-library/TokenInput/TokenAdornment.tsx delete mode 100644 src/component-library/TokenInput/TokenList.tsx delete mode 100644 src/component-library/TokenInput/TokenListModal.tsx diff --git a/src/component-library/Select/Select.stories.tsx b/src/component-library/Select/Select.stories.tsx index 3cacaba1c3..1c366984ad 100644 --- a/src/component-library/Select/Select.stories.tsx +++ b/src/component-library/Select/Select.stories.tsx @@ -6,7 +6,7 @@ import { Flex } from '../Flex'; import { Select, SelectProps } from './Select'; import { SelectTrigger, SelectTriggerProps } from './SelectTrigger'; -const SelectTemplate: Story = (args) => { +const SelectTemplate: Story> = (args) => { return ( - - - {state.selectedItem && customRender(state.selectedItem)} - - {type === 'modal' && ( - - )} - - ); - } -); + ...props + }; + + const state = useSelectState(ariaProps); + + // MEMO: `menuProps` and `triggerProps` not implemented yet + const { labelProps, valueProps, triggerProps, descriptionProps, errorMessageProps } = useSelect( + ariaProps, + state, + buttonRef + ); + + const { fieldProps, elementProps } = useFieldProps({ + ...props, + descriptionProps, + errorMessageProps, + errorMessage, + labelProps: mergeProps(labelProps, props.labelProps || {}), + label + }); + + const hasError = hasErrorMessage(errorMessage); + + const selectTriggerProps = + type === 'listbox' + ? triggerProps + : mergeProps(props, { + onPress: () => { + // buttonRef.current?.blur(); + state.setOpen(true); + }, + disabled, + id: triggerProps.id, + 'aria-labelledby': triggerProps['aria-labelledby'] + }); + + const { fieldProps: hiddenFieldProps, labelProps: hiddenLabelProps } = useField({ label }); + + return ( + + + + + + + {state.selectedItem && renderValue(state.selectedItem)} + + {type === 'modal' && ( + + )} + + ); +}; + +const _Select = forwardRef(Select) as ( + props: SelectProps & { ref?: React.ForwardedRef } +) => ReturnType; Select.displayName = 'Select'; -export { Select }; +export { _Select as Select }; export type { SelectProps }; diff --git a/src/component-library/Select/SelectModal.tsx b/src/component-library/Select/SelectModal.tsx index e453fcb460..77c8e07ed6 100644 --- a/src/component-library/Select/SelectModal.tsx +++ b/src/component-library/Select/SelectModal.tsx @@ -1,5 +1,6 @@ +import { useId } from '@react-aria/utils'; import { SelectState } from '@react-stately/select'; -import { forwardRef, Key } from 'react'; +import { forwardRef, Key, ReactNode } from 'react'; import { Modal, ModalBody, ModalHeader, ModalProps } from '@/component-library/Modal'; @@ -8,9 +9,10 @@ import { StyledList } from './Select.style'; import { SelectModalContext } from './SelectModalContext'; type Props = { + state: SelectState; onSelectionChange?: (key: Key) => void; selectedAccount?: Key; - state: SelectState; + title?: ReactNode; }; type InheritAttrs = Omit; @@ -18,7 +20,9 @@ type InheritAttrs = Omit; type SelectModalProps = Props & InheritAttrs; const SelectModal = forwardRef( - ({ selectedAccount, state, onSelectionChange, onClose, ...props }, ref): JSX.Element => { + ({ selectedAccount, state, title, onSelectionChange, onClose, ...props }, ref): JSX.Element => { + const headerId = useId(); + const handleSelectionChange: ListProps['onSelectionChange'] = (key) => { const [selectedKey] = [...key]; @@ -32,31 +36,29 @@ const SelectModal = forwardRef( return ( - - Select Account + + {title} - {[...state.collection].map((item) => { - return ( - - {item.rendered} - - ); - })} + {[...state.collection].map((item) => ( + + {item.rendered} + + ))} diff --git a/src/component-library/Select/SelectTrigger.tsx b/src/component-library/Select/SelectTrigger.tsx index aa634d00eb..2e0c984153 100644 --- a/src/component-library/Select/SelectTrigger.tsx +++ b/src/component-library/Select/SelectTrigger.tsx @@ -33,7 +33,7 @@ const SelectTrigger = forwardRef( const buttonRef = useDOMRef(ref); - const { buttonProps } = useButton(props, buttonRef); + const { buttonProps } = useButton({ ...props, isDisabled: disabled }, buttonRef); const { focusProps, isFocusVisible } = useFocusRing(); diff --git a/src/component-library/TokenInput/TokenAdornment.tsx b/src/component-library/TokenInput/TokenAdornment.tsx new file mode 100644 index 0000000000..cd2cf2be72 --- /dev/null +++ b/src/component-library/TokenInput/TokenAdornment.tsx @@ -0,0 +1,45 @@ +import { useMemo } from 'react'; + +import { CoinIcon } from '../CoinIcon'; +import { FlexProps } from '../Flex'; +import { StyledTicker, StyledTokenAdornment } from './TokenInput.style'; + +type SingleToken = string; + +type MultiToken = { text: string; icons: string[] }; + +type TokenTicker = SingleToken | MultiToken; + +type Props = { + ticker?: TokenTicker; +}; + +type NativeAttrs = Omit; + +type TokenAdornmentProps = Props & NativeAttrs; + +const TokenAdornment = ({ ticker = '', ...props }: TokenAdornmentProps): JSX.Element => { + const { tickerText, tickers } = useMemo(() => { + if (typeof ticker === 'object') { + return { + tickerText: ticker.text, + tickers: ticker.icons + }; + } + + return { + tickerText: ticker, + tickers: undefined + }; + }, [ticker]); + + return ( + + + {tickerText} + + ); +}; + +export { TokenAdornment }; +export type { TokenAdornmentProps, TokenTicker }; diff --git a/src/component-library/TokenInput/TokenInput.stories.tsx b/src/component-library/TokenInput/TokenInput.stories.tsx index dc04d91dd5..2902644a6f 100644 --- a/src/component-library/TokenInput/TokenInput.stories.tsx +++ b/src/component-library/TokenInput/TokenInput.stories.tsx @@ -18,7 +18,7 @@ const Template: Story = (args) => { const WithBalance = Template.bind({}); WithBalance.args = { - defaultTicker: 'KSM', + ticker: 'KSM', balance: 1000.0, balanceLabel: 'Balance', placeholder: '0.00', @@ -28,7 +28,7 @@ WithBalance.args = { const WithoutBalance = Template.bind({}); WithoutBalance.args = { - defaultTicker: 'KSM', + ticker: 'KSM', label: 'Amount', placeholder: '0.00', isDisabled: false @@ -41,34 +41,39 @@ WithCurrencySelect.args = { balanceLabel: 'Balance', placeholder: '0.00', label: 'From', - tokens: [ - { balance: 200, ticker: 'KSM', balanceUSD: '$200' }, - { balance: 200, ticker: 'BTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'IBTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'KBTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'DOT', balanceUSD: '$200' }, - { balance: 200, ticker: 'INTR', balanceUSD: '$200' }, - { balance: 200, ticker: 'LKSM', balanceUSD: '$200' } - ] + selectProps: { + disabled: true, + items: [ + { balance: 200, value: 'KSM', balanceUSD: '$200' }, + { balance: 200, value: 'BTC', balanceUSD: '$200' }, + { balance: 200, value: 'IBTC', balanceUSD: '$200' }, + { balance: 200, value: 'KBTC', balanceUSD: '$200' }, + { balance: 200, value: 'DOT', balanceUSD: '$200' }, + { balance: 200, value: 'INTR', balanceUSD: '$200' }, + { balance: 200, value: 'LKSM', balanceUSD: '$200' } + ] + } }; const MultiToken = Template.bind({}); MultiToken.args = { - ticker: { text: 'LP Token', icons: ['KSM', 'KBTC', 'KINT', 'USDT'] }, balance: 1000.0, balanceLabel: 'Balance', placeholder: '0.00', label: 'Amount', isDisabled: false, - tokens: [ - { balance: 200, ticker: 'KSM', balanceUSD: '$200' }, - { balance: 200, ticker: 'BTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'IBTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'KBTC', balanceUSD: '$200' }, - { balance: 200, ticker: 'DOT', balanceUSD: '$200' }, - { balance: 200, ticker: 'INTR', balanceUSD: '$200' }, - { balance: 200, ticker: { text: 'LP Token', icons: ['KSM', 'KBTC', 'KINT', 'USDT'] }, balanceUSD: '$200' } - ] + selectProps: { + value: 'LP KSM-KBTC-KINT', + items: [ + { balance: 200, value: 'KSM', balanceUSD: '$200' }, + { balance: 200, value: 'BTC', balanceUSD: '$200' }, + { balance: 200, value: 'IBTC', balanceUSD: '$200' }, + { balance: 200, value: 'KBTC', balanceUSD: '$200' }, + { balance: 200, value: 'DOT', balanceUSD: '$200' }, + { balance: 200, value: 'INTR', balanceUSD: '$200' }, + { balance: 200, value: 'LP KSM-KBTC-KINT', tickers: ['KSM', 'KBTC', 'KINT'], balanceUSD: '$200' } + ] + } }; export { MultiToken, WithBalance, WithCurrencySelect, WithoutBalance }; diff --git a/src/component-library/TokenInput/TokenInput.style.tsx b/src/component-library/TokenInput/TokenInput.style.tsx index e7af3abdfa..3331c5b6d2 100644 --- a/src/component-library/TokenInput/TokenInput.style.tsx +++ b/src/component-library/TokenInput/TokenInput.style.tsx @@ -44,6 +44,7 @@ const StyledTokenAdornment = styled(Flex)` const StyledTokenSelect = styled(StyledTrigger)` background-color: ${theme.tokenInput.endAdornment.bg}; + opacity: ${({ $isDisabled }) => $isDisabled && 0.5}; border-radius: ${theme.rounded.md}; font-size: ${theme.text.s}; padding: ${theme.spacing.spacing3}; diff --git a/src/component-library/TokenInput/TokenInput.tsx b/src/component-library/TokenInput/TokenInput.tsx index a08ca69499..dfbe7058a1 100644 --- a/src/component-library/TokenInput/TokenInput.tsx +++ b/src/component-library/TokenInput/TokenInput.tsx @@ -1,22 +1,16 @@ import { useLabel } from '@react-aria/label'; import { mergeProps } from '@react-aria/utils'; -import { forwardRef, InputHTMLAttributes, ReactNode, useEffect, useState } from 'react'; +import { forwardRef, Key, ReactNode, useEffect, useState } from 'react'; import { Flex } from '../Flex'; import { NumberInput, NumberInputProps } from '../NumberInput'; import { useDOMRef } from '../utils/dom'; import { formatUSD } from '../utils/format'; import { triggerChangeEvent } from '../utils/input'; +import { TokenAdornment, TokenTicker } from './TokenAdornment'; import { StyledUSDAdornment } from './TokenInput.style'; import { TokenInputLabel } from './TokenInputLabel'; -import { TokenData } from './TokenList'; -import { TokenSelect } from './TokenSelect'; - -type SingleToken = string; - -type MultiToken = { text: string; icons: string[] }; - -type TokenTicker = SingleToken | MultiToken; +import { TokenSelect, TokenSelectProps } from './TokenSelect'; type Props = { valueUSD?: number; @@ -24,11 +18,9 @@ type Props = { humanBalance?: string | number; balanceLabel?: ReactNode; ticker?: TokenTicker; - defaultTicker?: TokenTicker; - tokens?: TokenData[]; onClickBalance?: (balance?: string | number) => void; onChangeTicker?: (ticker?: string) => void; - selectProps?: InputHTMLAttributes; + selectProps?: TokenSelectProps; }; type InheritAttrs = Omit; @@ -44,9 +36,7 @@ const TokenInput = forwardRef( balanceLabel, isDisabled, label, - ticker: tickerProp, - defaultTicker = '', - tokens = [], + ticker, style, hidden, className, @@ -60,22 +50,14 @@ const TokenInput = forwardRef( ): JSX.Element => { const inputRef = useDOMRef(ref); - const [tickerValue, setTickerValue] = useState( - (selectProps?.defaultValue as string) || (typeof defaultTicker === 'string' ? defaultTicker : defaultTicker?.text) - ); + const [selectValue, setSelectValue] = useState(selectProps?.defaultValue as string); const { labelProps, fieldProps } = useLabel({ label, ...props }); - useEffect(() => { - if (tickerProp === undefined) return; - - setTickerValue(typeof tickerProp === 'string' ? tickerProp : tickerProp?.text); - }, [tickerProp]); - useEffect(() => { if (selectProps?.value === undefined) return; - setTickerValue(selectProps.value as string); + setSelectValue(selectProps.value as string); }, [selectProps?.value]); const handleClickBalance = () => { @@ -85,29 +67,22 @@ const TokenInput = forwardRef( onClickBalance?.(balance); }; - const handleTokenChange = (ticker: string) => { - onChangeTicker?.(ticker); - setTickerValue(ticker); + const handleTokenChange = (ticker: Key) => { + onChangeTicker?.(ticker as string); + setSelectValue(ticker as string); }; - const customIcons = typeof tickerProp === 'object' ? tickerProp.icons : undefined; - - const isSelectDisabled = !tokens?.length; - const endAdornment = ( + const endAdornment = selectProps ? ( - ); - - console.log('here'); + ) : ticker ? ( + + ) : null; const hasLabel = !!label || balance !== undefined; @@ -115,10 +90,10 @@ const TokenInput = forwardRef( ); } diff --git a/src/component-library/TokenInput/TokenSelect.tsx b/src/component-library/TokenInput/TokenSelect.tsx index 0ac4204030..f43dbb4ddf 100644 --- a/src/component-library/TokenInput/TokenSelect.tsx +++ b/src/component-library/TokenInput/TokenSelect.tsx @@ -40,23 +40,31 @@ type TokenData = { type TokenSelectProps = Omit, 'children' | 'type'>; -const TokenSelect = (props: TokenSelectProps): JSX.Element => ( - - {...props} - type='modal' - labelProps={{ isVisuallyHidden: true }} - asSelectTrigger={StyledTokenSelect} - renderValue={(item) => } - placeholder={Select Token} - modalTitle='Select Token' - > - {(data: TokenData) => ( - - - - )} - -); +const TokenSelect = ({ label: labelProp, 'aria-label': ariaLabelProp, ...props }: TokenSelectProps): JSX.Element => { + // it is unlikely that labelProp is not a string, but we need to avoid any accessibility error + const labelText = (typeof labelProp === 'string' && labelProp) || ariaLabelProp; + const ariaLabel = labelText && `Choose token for ${labelText} field`; + + return ( + + {...props} + type='modal' + descriptionProps={{ isHidden: true }} + errorMessageProps={{ isHidden: true }} + asSelectTrigger={StyledTokenSelect} + renderValue={(item) => } + placeholder={Select Token} + modalTitle='Select Token' + aria-label={ariaLabel} + > + {(data: TokenData) => ( + + + + )} + + ); +}; export { TokenSelect }; export type { TokenSelectProps }; From 8b44a6fec40dc8e275c96d05fd333f788c13ef8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Fri, 10 Mar 2023 15:58:34 +0000 Subject: [PATCH 57/69] fix: improvements --- src/component-library/Field/Field.tsx | 6 ++-- .../HelperText/HelperText.tsx | 29 +++++++------------ src/component-library/Input/BaseInput.tsx | 13 ++++++--- src/component-library/Input/Input.tsx | 2 +- src/component-library/Modal/ModalWrapper.tsx | 4 --- src/component-library/Select/Select.tsx | 16 ++++------ src/component-library/Select/SelectModal.tsx | 4 ++- .../TokenInput/TokenInput.stories.tsx | 1 + .../TokenInput/TokenInput.tsx | 6 ++-- .../TokenInput/TokenSelect.tsx | 2 -- src/component-library/TokenInput/index.tsx | 3 +- src/component-library/index.tsx | 2 +- src/component-library/utils/input.ts | 11 ++++++- .../AMM/Swap/components/SwapForm/SwapForm.tsx | 14 ++++----- 14 files changed, 56 insertions(+), 57 deletions(-) diff --git a/src/component-library/Field/Field.tsx b/src/component-library/Field/Field.tsx index e10882d375..ac9b7143c6 100644 --- a/src/component-library/Field/Field.tsx +++ b/src/component-library/Field/Field.tsx @@ -2,8 +2,8 @@ import { forwardRef, HTMLAttributes, ReactNode } from 'react'; import { Flex } from '../Flex'; import { HelperText, HelperTextProps } from '../HelperText'; -import { hasErrorMessage } from '../HelperText/HelperText'; import { Label, LabelProps } from '../Label'; +import { hasError } from '../utils/input'; import { Wrapper } from './Field.style'; type Props = { @@ -22,8 +22,8 @@ const Field = forwardRef( { label, labelProps, errorMessage, errorMessageProps, description, descriptionProps, children, ...props }, ref ): JSX.Element => { - const hasError = hasErrorMessage(errorMessage); - const hasHelpText = !!description || hasError; + const error = hasError({ errorMessage }); + const hasHelpText = !!description || error; return ( diff --git a/src/component-library/HelperText/HelperText.tsx b/src/component-library/HelperText/HelperText.tsx index d4b8f3fde8..1c64332243 100644 --- a/src/component-library/HelperText/HelperText.tsx +++ b/src/component-library/HelperText/HelperText.tsx @@ -1,20 +1,15 @@ import { forwardRef, HTMLAttributes } from 'react'; +import { hasError } from '../utils/input'; import { StyledHelperText, StyledSubHelperText } from './HelperText.style'; -type ErrorMessageProps = HTMLAttributes & { isHidden?: boolean }; - -type DescriptionProps = HTMLAttributes & { isHidden?: boolean }; - -// checks for truthy messages both for string and string[] -const hasErrorMessage = (errorMessage?: string | string[]): boolean => - typeof errorMessage === 'string' ? !!errorMessage : !!errorMessage?.filter(Boolean).length; - type Props = { errorMessage?: string | string[]; - errorMessageProps?: ErrorMessageProps; + // Used to pass accessiblity props + errorMessageProps?: HTMLAttributes; description?: string; - descriptionProps?: DescriptionProps; + // Used to pass accessiblity props + descriptionProps?: HTMLAttributes; }; type NativeAttrs = Omit, keyof Props>; @@ -23,7 +18,7 @@ type HelperTextProps = Props & NativeAttrs; const HelperText = forwardRef( ({ errorMessage, errorMessageProps, description, descriptionProps, ...props }, ref): JSX.Element => { - const isErrorMessage = hasErrorMessage(errorMessage); + const isErrorMessage = hasError({ errorMessage }); const renderErrorMessage = () => { if (Array.isArray(errorMessage)) { @@ -33,16 +28,12 @@ const HelperText = forwardRef( return errorMessage; }; - const { isHidden, ...contentProps } = (isErrorMessage ? errorMessageProps : descriptionProps) || {}; - - console.log(errorMessageProps); - return ( - + {isErrorMessage ? ( -
{renderErrorMessage()}
+
{renderErrorMessage()}
) : ( -
{description}
+
{description}
)}
); @@ -51,5 +42,5 @@ const HelperText = forwardRef( HelperText.displayName = 'HelperText'; -export { hasErrorMessage, HelperText }; +export { HelperText }; export type { HelperTextProps }; diff --git a/src/component-library/Input/BaseInput.tsx b/src/component-library/Input/BaseInput.tsx index a9715ac736..c058bc71c3 100644 --- a/src/component-library/Input/BaseInput.tsx +++ b/src/component-library/Input/BaseInput.tsx @@ -1,9 +1,10 @@ +import { ValidationState } from '@react-types/shared'; import { forwardRef, InputHTMLAttributes, ReactNode, useEffect, useRef, useState } from 'react'; import { Field, useFieldProps } from '../Field'; import { HelperTextProps } from '../HelperText'; -import { hasErrorMessage } from '../HelperText/HelperText'; import { LabelProps } from '../Label'; +import { hasError } from '../utils/input'; import { Sizes } from '../utils/prop-types'; import { Adornment, StyledBaseInput } from './Input.style'; @@ -16,6 +17,7 @@ type Props = { value?: string | ReadonlyArray | number; defaultValue?: string | ReadonlyArray | number; size?: Sizes; + validationState?: ValidationState; onChange?: (e: React.ChangeEvent) => void; }; @@ -26,7 +28,10 @@ type InheritAttrs = Omit; type BaseInputProps = Props & NativeAttrs & InheritAttrs; const BaseInput = forwardRef( - ({ startAdornment, endAdornment, bottomAdornment, disabled, size = 'medium', ...props }, ref): JSX.Element => { + ( + { startAdornment, endAdornment, bottomAdornment, disabled, size = 'medium', validationState, ...props }, + ref + ): JSX.Element => { const endAdornmentRef = useRef(null); const [endAdornmentWidth, setEndAdornmentWidth] = useState(0); @@ -38,7 +43,7 @@ const BaseInput = forwardRef( setEndAdornmentWidth(endAdornmentRef.current.getBoundingClientRect().width); }, [endAdornment]); - const hasError = hasErrorMessage(props.errorMessage); + const error = hasError({ validationState, errorMessage: props.errorMessage }); return ( @@ -49,7 +54,7 @@ const BaseInput = forwardRef( disabled={disabled} $size={size} $adornments={{ bottom: !!bottomAdornment, left: !!startAdornment, right: !!endAdornment }} - $hasError={hasError} + $hasError={error} $isDisabled={!!disabled} $endAdornmentWidth={endAdornmentWidth} {...elementProps} diff --git a/src/component-library/Input/Input.tsx b/src/component-library/Input/Input.tsx index b537fef356..fd650ac824 100644 --- a/src/component-library/Input/Input.tsx +++ b/src/component-library/Input/Input.tsx @@ -24,7 +24,7 @@ const Input = forwardRef( const inputRef = useDOMRef(ref); // We are specifing `validationState` so that when there are errors, `aria-invalid` is set to `true` const { inputProps, descriptionProps, errorMessageProps, labelProps } = useTextField( - { ...props, validationState: props.errorMessage ? 'invalid' : validationState }, + { ...props, validationState: validationState || props.errorMessage ? 'invalid' : validationState }, inputRef ); diff --git a/src/component-library/Modal/ModalWrapper.tsx b/src/component-library/Modal/ModalWrapper.tsx index 9da82de7bf..3bb7dab4c9 100644 --- a/src/component-library/Modal/ModalWrapper.tsx +++ b/src/component-library/Modal/ModalWrapper.tsx @@ -46,10 +46,6 @@ const ModalWrapper = forwardRef( ref as RefObject ); - // CANNOT ESC out of modal - - console.log(underlayProps, modalProps); - const isCentered = align === 'center'; return ( diff --git a/src/component-library/Select/Select.tsx b/src/component-library/Select/Select.tsx index 3597acc405..cfd1df728b 100644 --- a/src/component-library/Select/Select.tsx +++ b/src/component-library/Select/Select.tsx @@ -1,4 +1,3 @@ -import { useField } from '@react-aria/label'; import { useSelect } from '@react-aria/select'; import { chain, mergeProps } from '@react-aria/utils'; import { VisuallyHidden } from '@react-aria/visually-hidden'; @@ -7,9 +6,8 @@ import { CollectionBase, Node } from '@react-types/shared'; import { ForwardedRef, forwardRef, Key, ReactNode, useRef } from 'react'; import { Field, FieldProps, useFieldProps } from '../Field'; -import { hasErrorMessage } from '../HelperText/HelperText'; import { useDOMRef } from '../utils/dom'; -import { triggerChangeEvent } from '../utils/input'; +import { hasError, triggerChangeEvent } from '../utils/input'; import { Sizes } from '../utils/prop-types'; import { SelectModal } from './SelectModal'; import { SelectTrigger } from './SelectTrigger'; @@ -54,6 +52,7 @@ const Select = ( placeholder = 'Select an option', asSelectTrigger, modalTitle, + validationState, onChange, onSelectionChange, renderValue = (item) => item.rendered, @@ -73,6 +72,7 @@ const Select = ( defaultSelectedKey: defaultValue as Key, label, errorMessage, + validationState, onSelectionChange: chain((key: Key) => triggerChangeEvent(inputRef, key), onSelectionChange), ...props }; @@ -96,7 +96,7 @@ const Select = ( }) ); - const hasError = hasErrorMessage(errorMessage); + const error = hasError({ errorMessage, validationState }); const selectTriggerProps = type === 'listbox' @@ -108,12 +108,9 @@ const Select = ( 'aria-labelledby': triggerProps['aria-labelledby'] }); - const { fieldProps: hiddenFieldProps, labelProps: hiddenLabelProps } = useField({ label }); - return ( - - {label && } + ( as={asSelectTrigger} ref={buttonRef} size={size} - hasError={hasError} + hasError={error} valueProps={valueProps} placeholder={placeholder} > diff --git a/src/component-library/Select/SelectModal.tsx b/src/component-library/Select/SelectModal.tsx index 77c8e07ed6..b504a7f65b 100644 --- a/src/component-library/Select/SelectModal.tsx +++ b/src/component-library/Select/SelectModal.tsx @@ -26,7 +26,9 @@ const SelectModal = forwardRef( const handleSelectionChange: ListProps['onSelectionChange'] = (key) => { const [selectedKey] = [...key]; - if (!selectedKey) return; + if (!selectedKey) { + return onClose(); + } onSelectionChange?.(selectedKey); state.selectionManager.setSelectedKeys(key); diff --git a/src/component-library/TokenInput/TokenInput.stories.tsx b/src/component-library/TokenInput/TokenInput.stories.tsx index 54435d4cba..adbeeaa9fa 100644 --- a/src/component-library/TokenInput/TokenInput.stories.tsx +++ b/src/component-library/TokenInput/TokenInput.stories.tsx @@ -73,6 +73,7 @@ MultiToken.args = { { balance: 200, value: 'LP KSM-KBTC-KINT', tickers: ['KSM', 'KBTC', 'KINT'], balanceUSD: '$200' } ] } + // errorMessage: 'Failed' }; export { MultiToken, WithBalance, WithCurrencySelect, WithoutBalance }; diff --git a/src/component-library/TokenInput/TokenInput.tsx b/src/component-library/TokenInput/TokenInput.tsx index e055a0c6cf..0538d6ea5f 100644 --- a/src/component-library/TokenInput/TokenInput.tsx +++ b/src/component-library/TokenInput/TokenInput.tsx @@ -80,7 +80,7 @@ const TokenInput = forwardRef( // Prioritise Number Input description and error message const hasSelectHelperText = !errorMessage && !description && (selectProps?.errorMessage || selectProps?.description); - const { errorMessage: selectErrorProps, ...restSelectProps } = selectProps || {}; + const { ...restSelectProps } = selectProps || {}; const endAdornment = restSelectProps ? ( ( label={label} aria-label={fieldProps['aria-label']} aria-describedby={hasSelectHelperText ? selectHelperTextId : undefined} - // Only show Select errorMessage when Select HelperText is rendered - errorMessage={hasSelectHelperText ? selectErrorProps : undefined} + validationState={hasSelectHelperText ? 'invalid' : undefined} + errorMessage={undefined} /> ) : ticker ? ( diff --git a/src/component-library/TokenInput/TokenSelect.tsx b/src/component-library/TokenInput/TokenSelect.tsx index f43dbb4ddf..9a4cb10604 100644 --- a/src/component-library/TokenInput/TokenSelect.tsx +++ b/src/component-library/TokenInput/TokenSelect.tsx @@ -49,8 +49,6 @@ const TokenSelect = ({ label: labelProp, 'aria-label': ariaLabelProp, ...props } {...props} type='modal' - descriptionProps={{ isHidden: true }} - errorMessageProps={{ isHidden: true }} asSelectTrigger={StyledTokenSelect} renderValue={(item) => } placeholder={Select Token} diff --git a/src/component-library/TokenInput/index.tsx b/src/component-library/TokenInput/index.tsx index c0ceba899e..3454a8938d 100644 --- a/src/component-library/TokenInput/index.tsx +++ b/src/component-library/TokenInput/index.tsx @@ -1,2 +1,3 @@ -export type { TokenInputProps, TokenTicker } from './TokenInput'; +export type { TokenInputProps } from './TokenInput'; export { TokenInput } from './TokenInput'; +export type { TokenSelectProps } from './TokenSelect'; diff --git a/src/component-library/index.tsx b/src/component-library/index.tsx index 809606ecc7..b91ec169da 100644 --- a/src/component-library/index.tsx +++ b/src/component-library/index.tsx @@ -46,7 +46,7 @@ export type { TextLinkProps } from './TextLink'; export { TextLink } from './TextLink'; export type { ComponentLibraryTheme } from './theme'; export { theme } from './theme'; -export type { TokenInputProps } from './TokenInput'; +export type { TokenInputProps, TokenSelectProps } from './TokenInput'; export { TokenInput } from './TokenInput'; export type { TokenStackProps } from './TokenStack'; export { TokenStack } from './TokenStack'; diff --git a/src/component-library/utils/input.ts b/src/component-library/utils/input.ts index 23ecc20360..a28159d5f3 100644 --- a/src/component-library/utils/input.ts +++ b/src/component-library/utils/input.ts @@ -1,3 +1,4 @@ +import { ValidationState } from '@react-types/shared'; import { RefObject } from 'react'; /** @@ -18,4 +19,12 @@ const triggerChangeEvent = ( ref.current?.dispatchEvent(e); }; -export { triggerChangeEvent }; +type HasErrorProps = { errorMessage?: string | string[]; validationState?: ValidationState }; + +const hasErrorMessage = (errorMessage?: string | string[]): boolean => + typeof errorMessage === 'string' ? !!errorMessage : !!errorMessage?.filter(Boolean).length; + +const hasError = ({ errorMessage, validationState }: HasErrorProps): boolean => + (errorMessage && hasErrorMessage(errorMessage)) || validationState === 'invalid'; + +export { hasError, triggerChangeEvent }; diff --git a/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx b/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx index 06d2b17131..f8b7bde476 100644 --- a/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx +++ b/src/pages/AMM/Swap/components/SwapForm/SwapForm.tsx @@ -12,7 +12,7 @@ import { useDebounce } from 'react-use'; import { StoreType } from '@/common/types/util.types'; import { convertMonetaryAmountToValueInUSD, formatUSD, newSafeMonetaryAmount } from '@/common/utils/utils'; -import { Card, CardProps, Divider, Flex, H1, TokenInput, TokenInputProps } from '@/component-library'; +import { Card, CardProps, Divider, Flex, H1, TokenInput, TokenSelectProps } from '@/component-library'; import { GOVERNANCE_TOKEN, TRANSACTION_FEE_AMOUNT } from '@/config/relay-chains'; import { SWAP_INPUT_AMOUNT_FIELD, @@ -277,7 +277,7 @@ const SwapForm = ({ form.values[SWAP_INPUT_AMOUNT_FIELD] ); - const tokens: TokenInputProps['tokens'] = useMemo( + const selectItems: TokenSelectProps['items'] = useMemo( () => currencies ?.filter((currency) => pooledTickers.has(currency.ticker)) @@ -290,7 +290,7 @@ const SwapForm = ({ return { balance: balance?.toHuman() || 0, balanceUSD: formatUSD(balanceUSD || 0, { compact: true }), - ticker: currency.ticker + value: currency.ticker }; }), [currencies, getAvailableBalance, pooledTickers, prices] @@ -317,9 +317,9 @@ const SwapForm = ({ balance={inputBalance?.toString() || 0} humanBalance={inputBalance?.toHuman() || 0} valueUSD={inputAmountUSD} - tokens={tokens} selectProps={mergeProps(form.getFieldProps(SWAP_INPUT_TOKEN_FIELD, false), { - onSelectionChange: (ticker: string) => handleTickerChange(ticker, SWAP_INPUT_TOKEN_FIELD) + onChange: handleTickerChange, + items: selectItems })} {...mergeProps(form.getFieldProps(SWAP_INPUT_AMOUNT_FIELD, false), { onChange: handleChangeInput })} /> @@ -332,9 +332,9 @@ const SwapForm = ({ humanBalance={outputBalance?.toHuman() || 0} valueUSD={outputAmountUSD} value={trade?.outputAmount.toString() || ''} - tokens={tokens} selectProps={mergeProps(form.getFieldProps(SWAP_OUTPUT_TOKEN_FIELD, false), { - onSelectionChange: (ticker: string) => handleTickerChange(ticker, SWAP_OUTPUT_TOKEN_FIELD) + onChange: handleTickerChange, + items: selectItems })} />
From d8d519532905686d672dbfeb2d7aa07a818f56f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Tue, 4 Apr 2023 14:18:18 +0100 Subject: [PATCH 58/69] feat: add dex volume to swap and pools --- src/components/PoolsTable/PoolsTable.tsx | 25 ++- src/pages/AMM/Swap/Swap.tsx | 4 +- .../SwapLiquidity/SwapLiquidity.tsx | 16 +- .../hooks/api/amm/use-get-liquidity-pools.tsx | 11 +- src/utils/hooks/api/use-get-dex-volume.tsx | 160 ++++++++++++++++++ 5 files changed, 194 insertions(+), 22 deletions(-) create mode 100644 src/utils/hooks/api/use-get-dex-volume.tsx diff --git a/src/components/PoolsTable/PoolsTable.tsx b/src/components/PoolsTable/PoolsTable.tsx index 3285d3ca5c..fadc759cd2 100644 --- a/src/components/PoolsTable/PoolsTable.tsx +++ b/src/components/PoolsTable/PoolsTable.tsx @@ -8,6 +8,7 @@ import { formatPercentage, formatUSD } from '@/common/utils/utils'; import { calculateAccountLiquidityUSD, calculateTotalLiquidityUSD } from '@/pages/AMM/shared/utils'; import { getCoinIconProps } from '@/utils/helpers/coin-icon'; import { getFarmingApr } from '@/utils/helpers/pools'; +import { DateRangeVolume, useGetDexVolumes } from '@/utils/hooks/api/use-get-dex-volume'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { AssetCell, BalanceCell, Cell, Table, TableProps } from '../DataGrid'; @@ -25,7 +26,7 @@ type PoolsTableRow = { [PoolsTableColumns.POOL_NAME]: ReactNode; [PoolsTableColumns.APR]: ReactNode; [PoolsTableColumns.TOTAL_LIQUIDITY]: ReactNode; - // [PoolsTableColumns.SEVEN_DAY_VOLUME]: ReactNode; + [PoolsTableColumns.SEVEN_DAY_VOLUME]: ReactNode; [PoolsTableColumns.ACCOUNT_LIQUIDITY]?: ReactNode; }; @@ -40,6 +41,7 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS const { t } = useTranslation(); const prices = useGetPrices(); const titleId = useId(); + const { getDexTotalVolumeUSD } = useGetDexVolumes(DateRangeVolume.D7); const isAccountPools = variant === 'account-pools'; @@ -47,12 +49,11 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS { name: t('amm.pools.pool_name'), uid: PoolsTableColumns.POOL_NAME }, { name: t('apr'), uid: PoolsTableColumns.APR }, { name: t('total_liquidity'), uid: PoolsTableColumns.TOTAL_LIQUIDITY } - // { name: t('7_day_volume'), uid: PoolsTableColumns.SEVEN_DAY_VOLUME } ]; const borrowAssetsColumns = isAccountPools ? [...commonColumns, { name: t('my_liquidity'), uid: PoolsTableColumns.ACCOUNT_LIQUIDITY }] - : commonColumns; + : [...commonColumns, { name: t('7_day_volume'), uid: PoolsTableColumns.SEVEN_DAY_VOLUME }]; const rows: PoolsTableRow[] = useMemo( () => @@ -68,15 +69,13 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS const apr = ; // TODO: revert alignItems prop when `sevenDayVolume` is adressed - const totalLiquidity = ( - - ); + const totalLiquidity = ; - // TODO: uncomment and add real value when squid is ready - // const sevenDayVolume = ; + const total7DayVolumeUSD = getDexTotalVolumeUSD(pooledCurrencies.map((pooled) => pooled.currency.ticker)); + const total7DayVolumeLabel = formatUSD(total7DayVolumeUSD, { compact: true }); + const sevenDayVolume = isAccountPools ? null : ( + + ); const accountLiquidityUSD = accountLPTokenAmount ? calculateAccountLiquidityUSD(accountLPTokenAmount, totalLiquidityUSD, totalSupply) @@ -92,11 +91,11 @@ const PoolsTable = ({ variant, pools, onRowAction, title }: PoolsTableProps): JS poolName, apr, totalLiquidity, - // sevenDayVolume, + sevenDayVolume, accountLiquidity }; }), - [isAccountPools, pools, prices, variant] + [getDexTotalVolumeUSD, isAccountPools, pools, prices, variant] ); return ( diff --git a/src/pages/AMM/Swap/Swap.tsx b/src/pages/AMM/Swap/Swap.tsx index cc0be6ffdf..427fd5b7f8 100644 --- a/src/pages/AMM/Swap/Swap.tsx +++ b/src/pages/AMM/Swap/Swap.tsx @@ -59,11 +59,11 @@ const Swap = (): JSX.Element => { - {pair.input && pair.output && liquidityPool && ( + {pair.input && pair.output && ( )} diff --git a/src/pages/AMM/Swap/components/SwapLiquidity/SwapLiquidity.tsx b/src/pages/AMM/Swap/components/SwapLiquidity/SwapLiquidity.tsx index 6aacf94db4..65571a0230 100644 --- a/src/pages/AMM/Swap/components/SwapLiquidity/SwapLiquidity.tsx +++ b/src/pages/AMM/Swap/components/SwapLiquidity/SwapLiquidity.tsx @@ -2,6 +2,7 @@ import { CurrencyExt, LiquidityPool } from '@interlay/interbtc-api'; import { formatUSD } from '@/common/utils/utils'; import { Card, CardProps, CoinPair, Dd, Dl, DlGroup, Dt, Flex, H2 } from '@/component-library'; +import { DateRangeVolume, useGetDexVolumes } from '@/utils/hooks/api/use-get-dex-volume'; import { useGetPrices } from '@/utils/hooks/api/use-get-prices'; import { calculateTotalLiquidityUSD } from '../../../shared/utils'; @@ -9,8 +10,7 @@ import { calculateTotalLiquidityUSD } from '../../../shared/utils'; type Props = { input: CurrencyExt; output: CurrencyExt; - // TODO: not used - liquidityPool: LiquidityPool; + liquidityPool?: LiquidityPool; }; type InheritAttrs = Omit; @@ -19,7 +19,13 @@ type SwapLiquidityProps = Props & InheritAttrs; const SwapLiquidity = ({ input, output, liquidityPool, ...props }: SwapLiquidityProps): JSX.Element | null => { const prices = useGetPrices(); - const liquidity = calculateTotalLiquidityUSD(liquidityPool.pooledCurrencies, prices); + const { getDexTotalVolumeUSD } = useGetDexVolumes(DateRangeVolume.H24); + + const h24Volume = getDexTotalVolumeUSD([input.ticker, output.ticker]); + const h24VolumeLabel = formatUSD(h24Volume, { compact: true }); + + const liquidity = liquidityPool && calculateTotalLiquidityUSD(liquidityPool.pooledCurrencies, prices); + const liquidityLabel = liquidity ? formatUSD(liquidity, { compact: true }) : '-'; return ( @@ -32,11 +38,11 @@ const SwapLiquidity = ({ input, output, liquidityPool, ...props }: SwapLiquidity
Volume (24h)
-
-
+
{h24VolumeLabel}
Liquidity
-
{formatUSD(liquidity, { compact: true })}
+
{liquidityLabel}
diff --git a/src/utils/hooks/api/amm/use-get-liquidity-pools.tsx b/src/utils/hooks/api/amm/use-get-liquidity-pools.tsx index 7244c4c453..b599f7a88f 100644 --- a/src/utils/hooks/api/amm/use-get-liquidity-pools.tsx +++ b/src/utils/hooks/api/amm/use-get-liquidity-pools.tsx @@ -1,4 +1,5 @@ -import { LiquidityPool } from '@interlay/interbtc-api'; +import { LiquidityPool, StableLiquidityPool } from '@interlay/interbtc-api'; +import { useCallback } from 'react'; import { useErrorHandler } from 'react-error-boundary'; import { useQuery } from 'react-query'; @@ -7,6 +8,7 @@ import { BLOCKTIME_REFETCH_INTERVAL } from '@/utils/constants/api'; interface UseGetLiquidityPools { data: Array | undefined; refetch: () => void; + getStableLiquidityPoolById: (poolId: number) => StableLiquidityPool; } const getLiquidityPools = async (): Promise => window.bridge.amm.getLiquidityPools(); @@ -22,7 +24,12 @@ const useGetLiquidityPools = (): UseGetLiquidityPools => { useErrorHandler(error); - return { data, refetch }; + const getStableLiquidityPoolById = useCallback( + (poolId: number) => data?.find((pool) => (pool as StableLiquidityPool)?.poolId === poolId) as StableLiquidityPool, + [data] + ); + + return { data, refetch, getStableLiquidityPoolById }; }; export { useGetLiquidityPools }; diff --git a/src/utils/hooks/api/use-get-dex-volume.tsx b/src/utils/hooks/api/use-get-dex-volume.tsx new file mode 100644 index 0000000000..2fd70e48b6 --- /dev/null +++ b/src/utils/hooks/api/use-get-dex-volume.tsx @@ -0,0 +1,160 @@ +import { CurrencyExt, newMonetaryAmount } from '@interlay/interbtc-api'; +import { MonetaryAmount } from '@interlay/monetary-js'; +import { subDays } from 'date-fns'; +import { gql, GraphQLClient } from 'graphql-request'; +import { useCallback } from 'react'; +import { useQuery, UseQueryResult } from 'react-query'; + +import { convertMonetaryAmountToValueInUSD } from '@/common/utils/utils'; +import { SQUID_URL } from '@/constants'; +import { REFETCH_INTERVAL } from '@/utils/constants/api'; +import { getTokenPrice } from '@/utils/helpers/prices'; + +import { useGetLiquidityPools } from './amm/use-get-liquidity-pools'; +import { useGetCurrencies } from './use-get-currencies'; +import { useGetPrices } from './use-get-prices'; + +const graphQLClient = new GraphQLClient(SQUID_URL, { + headers: { + 'Content-Type': 'application/json' + } +}); + +// TODO: add this to a dedicated schemas folder +const AMOUNT_FIELDS = gql` + fragment AmountFields on PooledAmount { + amount + amountHuman + token { + ... on NativeToken { + __typename + token + } + ... on ForeignAsset { + __typename + asset + } + ... on StableLpToken { + __typename + poolId + } + } + } +`; + +// TODO: add this to a dedicated schemas folder +const GET_DEX_VOLUMES = gql` + ${AMOUNT_FIELDS} + query poolVolumes($start: DateTime, $end: DateTime) { + startVolumes: cumulativeDexTradingVolumes( + limit: 1 + orderBy: tillTimestamp_DESC + where: { tillTimestamp_lte: $start } + ) { + tillTimestamp + amounts { + ...AmountFields + } + } + endVolumes: cumulativeDexTradingVolumes(limit: 1, orderBy: tillTimestamp_DESC, where: { tillTimestamp_lte: $end }) { + tillTimestamp + amounts { + ...AmountFields + } + } + } +`; + +enum DateRangeVolume { + H24, + D7 +} + +type DexCurrencyVolume = { + amount: MonetaryAmount; + usd: number; +}; + +type DexVolumesData = Record; + +type UseGetCurrenciesResult = UseQueryResult & { + getDexVolumeByTicker: (ticker: string) => DexCurrencyVolume | undefined; + getDexTotalVolumeUSD: (tickers: string[]) => number; +}; + +const useGetDexVolumes = (range: DateRangeVolume): UseGetCurrenciesResult => { + const { getCurrencyFromTicker, getForeignCurrencyFromId } = useGetCurrencies(true); + const { getStableLiquidityPoolById } = useGetLiquidityPools(); + const prices = useGetPrices(); + + const getDexVolumes = useCallback( + async (range: DateRangeVolume): Promise => { + const start = subDays(new Date(), range === DateRangeVolume.D7 ? 7 : 1); + const end = new Date(); + + const data = await graphQLClient.request(GET_DEX_VOLUMES, { start, end }); + + const [startVolumes] = data.startVolumes; + const [endVolumes] = data.endVolumes; + + return startVolumes.amounts.reduce((acc: DexVolumesData, item: any) => { + let currency: CurrencyExt; + let endVolume; + + switch (item.token.__typename) { + case 'NativeToken': { + const { token } = item.token; + currency = getCurrencyFromTicker(token); + endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.token === token); + break; + } + case 'ForeignAsset': { + const { asset } = item.token; + currency = getForeignCurrencyFromId(asset); + endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.asset === asset); + break; + } + case 'StableLpToken': { + const { poolId } = item.token; + currency = getStableLiquidityPoolById(poolId).lpToken; + endVolume = endVolumes.amounts.find((endAmount: any) => endAmount.token.poolId === poolId); + break; + } + default: + return acc; + } + + if (!endVolume) { + return acc; + } + + const volumeAmount = newMonetaryAmount(endVolume.amount - item.amount, currency); + + const volume: DexCurrencyVolume = { + amount: volumeAmount, + usd: convertMonetaryAmountToValueInUSD(volumeAmount, getTokenPrice(prices, currency.ticker)?.usd) || 0 + }; + + return { ...acc, [currency.ticker]: volume }; + }, {}); + }, + [getCurrencyFromTicker, getForeignCurrencyFromId, getStableLiquidityPoolById, prices] + ); + + const queryResult = useQuery({ + queryKey: 'dex-volumes', + queryFn: () => getDexVolumes(range), + refetchInterval: REFETCH_INTERVAL.MINUTE + }); + + const getDexVolumeByTicker = useCallback((ticker: string) => queryResult.data?.[ticker], [queryResult.data]); + + const getDexTotalVolumeUSD = useCallback( + (tickers: string[]) => tickers.reduce((sum, ticker) => sum + (getDexVolumeByTicker(ticker)?.usd || 0), 0), + [getDexVolumeByTicker] + ); + + return { ...queryResult, getDexTotalVolumeUSD, getDexVolumeByTicker }; +}; + +export { DateRangeVolume, useGetDexVolumes }; From bceb11812bffaad10511206a38eea90fa933e779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sim=C3=A3o?= Date: Thu, 20 Apr 2023 14:02:37 +0100 Subject: [PATCH 59/69] fix(Pools): get account liquidity hook (#1142) --- src/test/pages/Pools.test.tsx | 2 +- src/utils/hooks/api/amm/use-get-account-pools.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/pages/Pools.test.tsx b/src/test/pages/Pools.test.tsx index fd1140e981..ef5c3034cb 100644 --- a/src/test/pages/Pools.test.tsx +++ b/src/test/pages/Pools.test.tsx @@ -36,7 +36,7 @@ const TABS = { }; // MEMO: skipped including testing slippage -describe.skip('Pools Page', () => { +describe('Pools Page', () => { beforeEach(() => { mockGetLiquidityProvidedByAccount.mockResolvedValue(DEFAULT_ACCOUNT_LIQUIDITY); }); diff --git a/src/utils/hooks/api/amm/use-get-account-pools.tsx b/src/utils/hooks/api/amm/use-get-account-pools.tsx index 2d440ddbae..dbc20d0c5d 100644 --- a/src/utils/hooks/api/amm/use-get-account-pools.tsx +++ b/src/utils/hooks/api/amm/use-get-account-pools.tsx @@ -68,7 +68,7 @@ const useGetAccountPools = (): UseGetAccountProvidedLiquidity => { const { data, error, refetch: refetchQuery } = useQuery({ queryKey: ['account-pools', accountId], queryFn: () => accountId && liquidityPools && prices && getAccountLiqudityPools(accountId, liquidityPools, prices), - enabled: !!liquidityPools, + enabled: !!accountId && !!liquidityPools && !!prices, refetchInterval: BLOCKTIME_REFETCH_INTERVAL }); From 221202cde2f04cf83476530c2c8ea6857ca5c280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Sim=C3=A3o?= Date: Thu, 20 Apr 2023 12:04:28 +0100 Subject: [PATCH 60/69] fix: rebase --- .../Select/Select.stories.tsx | 12 +- src/component-library/Select/Select.tsx | 8 +- src/component-library/Select/SelectModal.tsx | 4 +- .../TokenInput/TokenInput.tsx | 6 +- .../TokenInput/TokenSelect.tsx | 2 +- .../AMM/Swap/components/SwapForm/SwapForm.tsx | 6 +- yarn.lock | 163 ++++++++++++++++++ 7 files changed, 180 insertions(+), 21 deletions(-) diff --git a/src/component-library/Select/Select.stories.tsx b/src/component-library/Select/Select.stories.tsx index 1c366984ad..f233b502d4 100644 --- a/src/component-library/Select/Select.stories.tsx +++ b/src/component-library/Select/Select.stories.tsx @@ -9,32 +9,32 @@ import { SelectTrigger, SelectTriggerProps } from './SelectTrigger'; const SelectTemplate: Story> = (args) => { return (