diff --git a/JoyboyCommunity/src/constants/tokens.ts b/JoyboyCommunity/src/constants/tokens.ts index e09cbc92..17c03e0c 100644 --- a/JoyboyCommunity/src/constants/tokens.ts +++ b/JoyboyCommunity/src/constants/tokens.ts @@ -11,8 +11,7 @@ export type MultiChainTokens = Record; export enum TokenSymbol { ETH = 'ETH', - /* STRK = 'STRK', - JBY = 'JBY', */ + USDC = 'USDC', } export const ETH: MultiChainToken = { @@ -34,48 +33,28 @@ export const ETH: MultiChainToken = { }, }; -/* export const STRK: MultiChainToken = { +export const USDC: MultiChainToken = { [constants.StarknetChainId.SN_MAIN]: { - name: 'Stark', - symbol: TokenSymbol.STRK, - decimals: 18, + name: 'USD Coin', + symbol: TokenSymbol.USDC, + decimals: 6, address: getChecksumAddress( - '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d', + '0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8', ), }, [constants.StarknetChainId.SN_SEPOLIA]: { - name: 'Stark', - symbol: TokenSymbol.STRK, - decimals: 18, + name: 'USD Coin', + symbol: TokenSymbol.USDC, + decimals: 6, address: getChecksumAddress( - '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d', + '0x053b40a647cedfca6ca84f542a0fe36736031905a9639a7f19a3c1e66bfd5080', ), }, }; -export const JBY: MultiChainToken = { - [constants.StarknetChainId.SN_MAIN]: { - name: 'Joyboy', - symbol: TokenSymbol.JBY, - decimals: 18, - address: getChecksumAddress( - '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', - ), - }, - [constants.StarknetChainId.SN_SEPOLIA]: { - name: 'Joyboy', - symbol: TokenSymbol.JBY, - decimals: 18, - address: getChecksumAddress( - '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', - ), - }, -}; */ - export const TOKENS: MultiChainTokens = { [TokenSymbol.ETH]: ETH, - /* [TokenSymbol.STRK]: STRK, - [TokenSymbol.JBY]: JBY, */ + [TokenSymbol.USDC]: USDC, }; export const TOKEN_ADDRESSES: Record< diff --git a/JoyboyCommunity/src/hooks/useWindowDimensions.ts b/JoyboyCommunity/src/hooks/useWindowDimensions.ts index dc72a67f..b89e436c 100644 --- a/JoyboyCommunity/src/hooks/useWindowDimensions.ts +++ b/JoyboyCommunity/src/hooks/useWindowDimensions.ts @@ -5,7 +5,7 @@ import {WEB_MAX_WIDTH} from '../constants/misc'; export const useWindowDimensions = () => { const dimensions = useRNWindowDimensions(); - if (Platform.OS === 'web') dimensions.width = WEB_MAX_WIDTH; + if (Platform.OS === 'web') dimensions.width = Math.min(dimensions.width, WEB_MAX_WIDTH); return dimensions; }; diff --git a/JoyboyCommunity/src/screens/Auth/Login.tsx b/JoyboyCommunity/src/screens/Auth/Login.tsx index 055882d3..ee1ea733 100644 --- a/JoyboyCommunity/src/screens/Auth/Login.tsx +++ b/JoyboyCommunity/src/screens/Auth/Login.tsx @@ -66,7 +66,6 @@ export const Login: React.FC = ({navigation}) => { description: 'Creating a new account will delete your current account. Are you sure you want to continue?', buttons: [ - {type: 'default', label: 'Cancel', onPress: hideDialog}, { type: 'primary', label: 'Continue', @@ -75,6 +74,7 @@ export const Login: React.FC = ({navigation}) => { hideDialog(); }, }, + {type: 'default', label: 'Cancel', onPress: hideDialog}, ], }); }; diff --git a/JoyboyCommunity/src/screens/Tips/index.tsx b/JoyboyCommunity/src/screens/Tips/index.tsx index c0f33f73..f8512133 100644 --- a/JoyboyCommunity/src/screens/Tips/index.tsx +++ b/JoyboyCommunity/src/screens/Tips/index.tsx @@ -40,12 +40,26 @@ export const Tips: React.FC = () => { const connectedAccount = await waitConnection(); if (!connectedAccount || !connectedAccount.address) return; + const deposit = await provider.callContract({ + contractAddress: ESCROW_ADDRESSES[CHAIN_ID], + entrypoint: Entrypoint.GET_DEPOSIT, + calldata: [depositId], + }); + + if (deposit[0] === '0x0') { + showToast({ + type: 'error', + title: 'This tip is not available anymore', + }); + return; + } + const getNostrEvent = async (gasAmount: bigint) => { const event = new NDKEvent(ndk); event.kind = NDKKind.Text; event.content = `claim: ${cairo.felt(depositId)},${cairo.felt( connectedAccount.address!, - )},${cairo.felt(ETH[CHAIN_ID].address)},${gasAmount.toString()}`; + )},${cairo.felt(deposit[3])},${gasAmount.toString()}`; event.tags = []; await event.sign(); @@ -53,7 +67,8 @@ export const Tips: React.FC = () => { }; const feeResult = await estimateClaim.mutateAsync(await getNostrEvent(BigInt(1))); - const fee = BigInt(feeResult.data.fee); + const ethFee = BigInt(feeResult.data.ethFee); + const tokenFee = BigInt(feeResult.data.tokenFee); const [balanceLow, balanceHigh] = await provider.callContract({ contractAddress: ETH[CHAIN_ID].address, @@ -62,10 +77,10 @@ export const Tips: React.FC = () => { }); const balance = uint256.uint256ToBN({low: balanceLow, high: balanceHigh}); - if (balance < fee) { + if (balance < ethFee) { // Send the claim through backend - const claimResult = await claim.mutateAsync(await getNostrEvent(fee)); + const claimResult = await claim.mutateAsync(await getNostrEvent(tokenFee)); const txHash = claimResult.data.transaction_hash; showTransactionModal(txHash, async (receipt) => { diff --git a/website/package.json b/website/package.json index f730dffa..53c31729 100644 --- a/website/package.json +++ b/website/package.json @@ -9,9 +9,12 @@ "lint": "next lint" }, "dependencies": { + "@avnu/avnu-sdk": "^2.0.0", + "ethers": "^6.13.1", "framer-motion": "^11.2.4", "next": "^14.2.3", "nostr-tools": "^2.7.0", + "qs": "^6.12.3", "react": "^18.3.1", "react-dom": "^18.3.1", "starknet": "6.9.0", diff --git a/website/src/app/api/deposit/calldata.ts b/website/src/app/api/deposit/calldata.ts index 70d0a00b..d8a37682 100644 --- a/website/src/app/api/deposit/calldata.ts +++ b/website/src/app/api/deposit/calldata.ts @@ -74,5 +74,5 @@ export const getClaimCallData = async (data: (typeof ClaimSchema)['_output']) => uint256.bnToUint256(gasAmount), ]); - return {calldata, gasAmount}; + return {calldata, gasAmount, tokenAddress}; }; diff --git a/website/src/app/api/deposit/claim/route.ts b/website/src/app/api/deposit/claim/route.ts index 9bc4005b..6898e8ae 100644 --- a/website/src/app/api/deposit/claim/route.ts +++ b/website/src/app/api/deposit/claim/route.ts @@ -1,8 +1,9 @@ +import {fetchBuildExecuteTransaction, fetchQuotes} from '@avnu/avnu-sdk'; import {NextRequest, NextResponse} from 'next/server'; import {Calldata} from 'starknet'; -import {ESCROW_ADDRESSES} from '@/constants/contracts'; -import {Entrypoint} from '@/constants/misc'; +import {ESCROW_ADDRESSES, ETH_ADDRESSES} from '@/constants/contracts'; +import {AVNU_URL, Entrypoint} from '@/constants/misc'; import {account} from '@/services/account'; import {provider} from '@/services/provider'; import {ErrorCode} from '@/utils/errors'; @@ -24,10 +25,12 @@ export async function POST(request: NextRequest) { let claimCallData: Calldata; let gasAmount: bigint; + let gasTokenAddress: string; try { const result = await getClaimCallData(body.data); claimCallData = result.calldata; gasAmount = result.gasAmount; + gasTokenAddress = result.tokenAddress; } catch (error) { if (error instanceof Error) { return NextResponse.json({code: error.message}, {status: HTTPStatus.BadRequest}); @@ -37,18 +40,69 @@ export async function POST(request: NextRequest) { } try { - const {transaction_hash} = await account.execute( - [ + if (gasTokenAddress === ETH_ADDRESSES[await provider.getChainId()]) { + // ETH transaction + + const {transaction_hash} = await account.execute([ { contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], entrypoint: Entrypoint.CLAIM, calldata: claimCallData, }, - ], - {maxFee: gasAmount}, - ); + ]); + + return NextResponse.json({transaction_hash}, {status: HTTPStatus.OK}); + } else { + // ERC20 transaction + + const result = await account.estimateInvokeFee([ + { + contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], + entrypoint: Entrypoint.CLAIM, + calldata: claimCallData, + }, + ]); + + const gasFeeQuotes = await fetchQuotes( + { + buyTokenAddress: ETH_ADDRESSES[await provider.getChainId()], + sellTokenAddress: gasTokenAddress, + sellAmount: gasAmount, + }, + {baseUrl: AVNU_URL}, + ); + const gasFeeQuote = gasFeeQuotes[0]; + + if (!gasFeeQuote) { + return NextResponse.json({code: ErrorCode.NO_ROUTE_FOUND}, {status: HTTPStatus.BadRequest}); + } + + if (result.overall_fee > gasFeeQuote.buyAmount) { + return NextResponse.json( + {code: ErrorCode.INVALID_GAS_AMOUNT}, + {status: HTTPStatus.BadRequest}, + ); + } - return NextResponse.json({transaction_hash}, {status: HTTPStatus.OK}); + const {calls: swapCalls} = await fetchBuildExecuteTransaction( + gasFeeQuote.quoteId, + account.address, + undefined, + undefined, + {baseUrl: AVNU_URL}, + ); + + const {transaction_hash} = await account.execute([ + { + contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], + entrypoint: Entrypoint.CLAIM, + calldata: claimCallData, + }, + ...swapCalls, + ]); + + return NextResponse.json({transaction_hash}, {status: HTTPStatus.OK}); + } } catch (error) { return NextResponse.json( {code: ErrorCode.TRANSACTION_ERROR, error}, diff --git a/website/src/app/api/deposit/estimate-claim/route.ts b/website/src/app/api/deposit/estimate-claim/route.ts index 55f682ee..e9093aa3 100644 --- a/website/src/app/api/deposit/estimate-claim/route.ts +++ b/website/src/app/api/deposit/estimate-claim/route.ts @@ -1,8 +1,9 @@ +import {fetchBuildExecuteTransaction, fetchQuotes} from '@avnu/avnu-sdk'; import {NextRequest, NextResponse} from 'next/server'; import {Calldata} from 'starknet'; -import {ESCROW_ADDRESSES} from '@/constants/contracts'; -import {Entrypoint} from '@/constants/misc'; +import {ESCROW_ADDRESSES, ETH_ADDRESSES} from '@/constants/contracts'; +import {AVNU_URL, Entrypoint} from '@/constants/misc'; import {account} from '@/services/account'; import {provider} from '@/services/provider'; import {ErrorCode} from '@/utils/errors'; @@ -23,9 +24,11 @@ export async function POST(request: NextRequest) { } let claimCallData: Calldata; + let gasTokenAddress: string; try { - const {calldata} = await getClaimCallData(body.data); + const {calldata, tokenAddress} = await getClaimCallData(body.data); claimCallData = calldata; + gasTokenAddress = tokenAddress; } catch (error) { if (error instanceof Error) { return NextResponse.json({code: error.message}, {status: HTTPStatus.BadRequest}); @@ -35,18 +38,78 @@ export async function POST(request: NextRequest) { } try { - const result = await account.estimateInvokeFee([ - { - contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], - entrypoint: Entrypoint.CLAIM, - calldata: claimCallData, - }, - ]); - - // Using 1.1 as a multiplier to ensure the fee is enough - const fee = ((result.overall_fee * BigInt(11)) / BigInt(10)).toString(); - - return NextResponse.json({fee}, {status: HTTPStatus.OK}); + if (gasTokenAddress === ETH_ADDRESSES[await provider.getChainId()]) { + // ETH fee estimation + + const result = await account.estimateInvokeFee([ + { + contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], + entrypoint: Entrypoint.CLAIM, + calldata: claimCallData, + }, + ]); + + // Using 1.1 as a multiplier to ensure the fee is enough + const fee = ((result.overall_fee * BigInt(11)) / BigInt(10)).toString(); + + return NextResponse.json({ethFee: fee, tokenFee: fee}, {status: HTTPStatus.OK}); + } else { + // ERC20 fee estimation + + const quotes = await fetchQuotes( + { + sellTokenAddress: ETH_ADDRESSES[await provider.getChainId()], + buyTokenAddress: gasTokenAddress, + sellAmount: BigInt(1), + takerAddress: account.address, + }, + {baseUrl: AVNU_URL}, + ); + const quote = quotes[0]; + + console.log(ETH_ADDRESSES[await provider.getChainId()], gasTokenAddress, quote); + + if (!quote) { + return NextResponse.json({code: ErrorCode.NO_ROUTE_FOUND}, {status: HTTPStatus.BadRequest}); + } + + const {calls: swapCalls} = await fetchBuildExecuteTransaction( + quote.quoteId, + account.address, + undefined, + undefined, + {baseUrl: AVNU_URL}, + ); + + const result = await account.estimateInvokeFee([ + { + contractAddress: ESCROW_ADDRESSES[await provider.getChainId()], + entrypoint: Entrypoint.CLAIM, + calldata: claimCallData, + }, + ...swapCalls, + ]); + + // Using 1.1 as a multiplier to ensure the fee is enough + const ethFee = (result.overall_fee * BigInt(11)) / BigInt(10); + + const feeQuotes = await fetchQuotes( + { + sellTokenAddress: ETH_ADDRESSES[await provider.getChainId()], + buyTokenAddress: gasTokenAddress, + sellAmount: ethFee, + takerAddress: account.address, + }, + {baseUrl: AVNU_URL}, + ); + const feeQuote = feeQuotes[0]; + + if (!feeQuote) { + return NextResponse.json({code: ErrorCode.NO_ROUTE_FOUND}, {status: HTTPStatus.BadRequest}); + } + + return NextResponse.json({ethFee, tokenFee: feeQuote.buyAmount}, {status: HTTPStatus.OK}); + } } catch (error) { return NextResponse.json( {code: ErrorCode.ESTIMATION_ERROR, error}, diff --git a/website/src/constants/contracts.ts b/website/src/constants/contracts.ts index 1846905e..68565f6e 100644 --- a/website/src/constants/contracts.ts +++ b/website/src/constants/contracts.ts @@ -5,3 +5,10 @@ export const ESCROW_ADDRESSES = { [constants.StarknetChainId.SN_SEPOLIA]: '0x078a022e6906c83e049a30f7464b939b831ecbe47029480d7e89684f20c8d263', }; + +export const ETH_ADDRESSES = { + [constants.StarknetChainId.SN_MAIN]: + '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', + [constants.StarknetChainId.SN_SEPOLIA]: + '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', +}; diff --git a/website/src/constants/misc.ts b/website/src/constants/misc.ts index 4c35fc00..61ed60e9 100644 --- a/website/src/constants/misc.ts +++ b/website/src/constants/misc.ts @@ -1,3 +1,6 @@ +import {BASE_URL as AVNU_BASE_URL, SEPOLIA_BASE_URL as AVNU_SEPOLIA_BASE_URL} from '@avnu/avnu-sdk'; +import {constants} from 'starknet'; + export enum Entrypoint { // ERC-20 NAME = 'name', @@ -10,3 +13,9 @@ export enum Entrypoint { CLAIM = 'claim', GET_DEPOSIT = 'get_deposit', } + +export const NETWORK_NAME = process.env.NETWORK_NAME as constants.NetworkName; +export const AVNU_URL = + process.env.NETWORK_NAME === 'SN_SEPOLIA' ? AVNU_SEPOLIA_BASE_URL : AVNU_BASE_URL; + +if (!NETWORK_NAME) throw new Error('NETWORK_NAME is not set'); diff --git a/website/src/services/provider.ts b/website/src/services/provider.ts index dbb31dbb..51353a98 100644 --- a/website/src/services/provider.ts +++ b/website/src/services/provider.ts @@ -1,8 +1,10 @@ import {constants, RpcProvider} from 'starknet'; +import {NETWORK_NAME} from '@/constants/misc'; + if (!process.env.PROVIDER_URL) throw new Error('PROVIDER_URL is not set'); export const provider = new RpcProvider({ nodeUrl: process.env.PROVIDER_URL, - chainId: constants.StarknetChainId.SN_SEPOLIA, + chainId: constants.StarknetChainId[NETWORK_NAME], }); diff --git a/website/src/utils/errors.ts b/website/src/utils/errors.ts index 39abbe16..38e474b1 100644 --- a/website/src/utils/errors.ts +++ b/website/src/utils/errors.ts @@ -8,6 +8,7 @@ const ErrorCodesArray = [ 'INVALID_GAS_AMOUNT', 'TRANSACTION_ERROR', 'ESTIMATION_ERROR', + 'NO_ROUTE_FOUND', ] as const; export type ErrorCode = (typeof ErrorCodesArray)[number]; diff --git a/website/yarn.lock b/website/yarn.lock index 39e6817a..0c0a2f06 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2,11 +2,21 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@alloc/quick-lru@^5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== +"@avnu/avnu-sdk@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@avnu/avnu-sdk/-/avnu-sdk-2.0.0.tgz#c86f3c6432e265e46d6d20524d27fecba682220a" + integrity sha512-mNRxvOa3VYt1+HM5LWSLmpQBOIrw6hfVjZkf4rbpC44H/Vem16PqoGpv0rgnoedVom6q8iLgjiI8Lr2NI9g+GA== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -306,6 +316,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^20": version "20.14.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.9.tgz#12e8e765ab27f8c421a1820c99f5f313a933b420" @@ -513,6 +528,11 @@ acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -1443,6 +1463,19 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +ethers@^6.13.1: + version "6.13.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.1.tgz#2b9f9c7455cde9d38b30fe6589972eb083652961" + integrity sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.17.1" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -2602,6 +2635,13 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +qs@^6.12.3: + version "6.12.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.3.tgz#e43ce03c8521b9c7fd7f1f13e514e5ca37727754" + integrity sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ== + dependencies: + side-channel "^1.0.6" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -3096,6 +3136,11 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -3340,6 +3385,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"