diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4ca9f0a --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +AGGREGATOR_PATH=~/solana-flux-aggregator diff --git a/.gitignore b/.gitignore index 1ef400a..875d79d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/package.json b/package.json index ec40513..f1f05f5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "clean": "rm -rf lib", "prepare": "run-s clean build", "shell": "node -e \"$(< shell)\" -i --experimental-repl-await", - "test": "run-s test:unit test:lint test:build", + "test": "mocha -r ts-node/register tests/Stateless.test.ts --timeout 0", "test:build": "run-s build", "test:lint": "eslint src", "test:unit": "jest", @@ -32,7 +32,7 @@ "@types/bn.js": "^4.11.6", "@types/chai": "^4.2.14", "@types/jest": "^26.0.9", - "@types/mocha": "^8.2.0", + "@types/mocha": "^8.2.2", "@typescript-eslint/eslint-plugin": "^4.6.0", "@typescript-eslint/parser": "^4.6.0", "babel-eslint": "^10.0.3", @@ -55,13 +55,16 @@ "trailingComma": "all" }, "dependencies": { + "@project-serum/common": "^0.0.1-beta.3", "@project-serum/serum": "^0.13.20", "@project-serum/sol-wallet-adapter": "^0.1.4", - "@solana/spl-token": "^0.0.13", - "@solana/web3.js": "^0.90.0", + "@solana/spl-token": "0.0.13", + "@solana/web3.js": "^0.95.0", "bn.js": "^5.1.2", "borsh": "https://github.com/defactojob/borsh-js#field-mapper", - "buffer-layout": "^1.2.0" + "buffer-layout": "^1.2.0", + "dotenv": "^10.0.0", + "mocha": "^8.4.0" }, "browserslist": [ ">0.2%", diff --git a/tests/Stateless.test.ts b/tests/Stateless.test.ts new file mode 100644 index 0000000..6dd8997 --- /dev/null +++ b/tests/Stateless.test.ts @@ -0,0 +1,452 @@ +import { MangoClient, MangoGroup, MarginAccount } from '../src/client'; +import { findLargestTokenAccountForOwner } from '../src/utils'; +import IDS from '../src/ids.json'; +import { Account, Connection, PublicKey } from '@solana/web3.js'; +import { Market } from '@project-serum/serum'; +import { expect } from 'chai'; +import { spawn } from 'child_process'; +import { blob, struct, u8, nu64 } from 'buffer-layout'; +import { sleep } from '../src/utils'; +import dotenv from 'dotenv'; + +dotenv.config() + +if (!process.env.AGGREGATOR_PATH) { + console.info("You have not set the AGGREGATOR_PATH in .env, some tests will fail"); +} + +import { + _sendTransaction, + createWalletAndRequestAirdrop, + createMangoGroupSymbolMappings, + createTokenAccountWithBalance, + getOwnedTokenAccounts, + getAndDecodeBidsAndAsksForOwner, + performSingleDepositOrWithdrawal, + getAndDecodeBidsAndAsks, + getOrderSizeAndPrice, + extractInfoFromLogs, + prettyPrintOwnerKeys +} from './test_utils'; + +console.log = function () {}; // NOTE: Disable all unnecessary logging + +let cluster = "devnet"; +const client = new MangoClient(); +const clusterIds = IDS[cluster]; +const mangoProgramId = new PublicKey(clusterIds.mango_program_id); +const dexProgramId = new PublicKey(clusterIds.dex_program_id); +let connection = new Connection(IDS.cluster_urls[cluster], 'singleGossip'); + +let mainnetCluster = "mainnet-beta"; +const mainnetClusterIds = IDS[mainnetCluster]; +const mainnetMangoProgramId = new PublicKey(mainnetClusterIds.mango_program_id); +const mainnetDexProgramId = new PublicKey(mainnetClusterIds.dex_program_id); +let mainnetConnection = new Connection(IDS.cluster_urls[mainnetCluster], 'singleGossip'); + +function chunkOrders(orders: any[], chunkSize: number) { + return orders.reduce((resultArray: any[], item, index) => { + const chunkIndex = Math.floor(index/chunkSize) + if(!resultArray[chunkIndex]) { + resultArray[chunkIndex] = [] + } + resultArray[chunkIndex].push(item) + return resultArray; + }, []); +} + +async function initAccountsWithBalances(neededBalances: number[]) { + const owner = await createWalletAndRequestAirdrop(connection, 5); + const mangoGroupTokenMappings = await createMangoGroupSymbolMappings(connection, mangoGroupIds); + await Promise.all(neededBalances.map(async (x, i) => { + if (x > 0) { + const baseSymbol = mangoGroupSymbols[i]; + await createTokenAccountWithBalance(connection, owner, baseSymbol, mangoGroupTokenMappings, clusterIds.faucets, x); + } + })); + prettyPrintOwnerKeys(owner, "Account"); +} + +async function getSpotMarketDetails(mangoGroupSpotMarket: any): Promise { + const [spotMarketSymbol, spotMarketAddress] = mangoGroupSpotMarket; + const [baseSymbol, quoteSymbol] = spotMarketSymbol.split('/'); + const spotMarket = await Market.load(connection, new PublicKey(spotMarketAddress), { skipPreflight: true, commitment: 'singleGossip'}, dexProgramId); + return { spotMarket, baseSymbol, quoteSymbol }; +} + +async function requestPriceChange(mangoGroup: MangoGroup, requiredPrice: number, baseSymbol: string) { + let prices = await mangoGroup.getPrices(connection); + while (prices[0].toFixed(2) !== requiredPrice.toFixed(2)) { + console.info("Running oracle to change price"); + await performPriceChange(Math.round( requiredPrice * 1e2 ) / 1e2, baseSymbol.toLowerCase()); + console.info("Finished running oracle to change price"); + try { + prices = await mangoGroup.getPrices(connection); + } catch (e) { + console.info("Error, trying to reset connection"); + connection = new Connection(IDS.cluster_urls[cluster], 'singleGossip'); + prices = await mangoGroup.getPrices(connection); + } + } + return prices; +} + +function performPriceChange(requiredPrice: number, baseSymbol: string): Promise { + return new Promise(function(resolve, _){ + const priceChangerOracle = spawn('yarn', ['solink', 'oracle', (requiredPrice * 100).toString()], {cwd: process.env.AGGREGATOR_PATH}); + priceChangerOracle.stdout.on("data", data => { + if (data.includes(`Submit OK {"aggregator":"${baseSymbol}:usd"`)) { + priceChangerOracle.kill(); + resolve(); + } + }); + }) +} + +async function cleanOrderBook(mangoGroupSpotMarket: any) { + console.info("Cleaning order book, this will take a while..."); + const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk); + const mangoGroupTokenMappings = await createMangoGroupSymbolMappings(connection, mangoGroupIds); + const { spotMarket, baseSymbol, quoteSymbol } = await getSpotMarketDetails(mangoGroupSpotMarket); + let bna = await getAndDecodeBidsAndAsks(connection, spotMarket); + let allAsks: any[] = [...bna.askOrderBook].map(x => ({ price: x.price, size: x.size })).reverse(); + let allBids: any[] = [...bna.bidOrderBook].map(x => ({ price: x.price, size: x.size })).reverse(); + if (allAsks.length || allBids.length) { + const owner = await createWalletAndRequestAirdrop(connection, 5); + try { + const marginAccountPk = await client.initMarginAccount(connection, mangoProgramId, mangoGroup, owner); + let marginAccount = await client.getMarginAccount(connection, marginAccountPk, dexProgramId); + const amountNeededToClearAsks: number = Math.ceil(allAsks.reduce((acc, ask) => acc + (ask.price * ask.size), 0) + 10); + await createTokenAccountWithBalance(connection, owner, quoteSymbol, mangoGroupTokenMappings, clusterIds.faucets, amountNeededToClearAsks); + await performSingleDepositOrWithdrawal(connection, owner, client, mangoGroup, mangoProgramId, quoteSymbol, mangoGroupTokenMappings, marginAccount, 'deposit', amountNeededToClearAsks); + const chunkedAsks = chunkOrders(allAsks, 15); + for (let ask of chunkedAsks) { + marginAccount = await client.getMarginAccount(connection, marginAccountPk, dexProgramId); + const price: number = Math.max(...ask.map((x: any) => x.price)); + const size: number = ask.reduce(( a: any, b: any ) => a + b.size, 0); + const roundedSize = Math.round( size * 1e2 ) / 1e2; + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, marginAccount, spotMarket, owner, 'buy', price, roundedSize); + } + const amountNeededToClearBids: number = Math.ceil(allBids.reduce((acc, bid) => acc + (bid.size), 0) + 10); + await createTokenAccountWithBalance(connection, owner, baseSymbol, mangoGroupTokenMappings, clusterIds.faucets, amountNeededToClearBids); + await performSingleDepositOrWithdrawal(connection, owner, client, mangoGroup, mangoProgramId, baseSymbol, mangoGroupTokenMappings, marginAccount, 'deposit', amountNeededToClearBids); + const chunkedBids = chunkOrders(allBids, 15); + for (let bid of chunkedBids) { + marginAccount = await client.getMarginAccount(connection, marginAccountPk, dexProgramId); + const price: number = Math.min(...bid.map((x: any) => x.price)); + const size: number = bid.reduce(( a: any, b: any ) => a + b.size, 0); + const roundedSize = Math.round( size * 1e2 ) / 1e2; + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, marginAccount, spotMarket, owner, 'sell', price, roundedSize); + } + bna = await getAndDecodeBidsAndAsks(connection, spotMarket); + allAsks = [...bna.askOrderBook].map(x => ({ price: x.price, size: x.size })); + allBids = [...bna.bidOrderBook].map(x => ({ price: x.price, size: x.size })); + expect(allAsks).to.be.empty; + expect(allBids).to.be.empty; + prettyPrintOwnerKeys(owner, "Cleaner"); + } catch (error) { + throw new Error(` + Test Error: ${error.message}, + ${prettyPrintOwnerKeys(owner, "Cleaner")} + `); + } + } +} + +async function placeNOrdersAfterLimit(mangoGroupSpotMarket: any, marketIndex: number, orderQuantityAfter: number) { + let openOrdersForOwner: any[]; + const orderQuantity = 128; // Max orders + const buyerOwner = await createWalletAndRequestAirdrop(connection, 5); + prettyPrintOwnerKeys(buyerOwner, "Buyer"); + const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk); + const mangoGroupTokenMappings = await createMangoGroupSymbolMappings(connection, mangoGroupIds); + const buyerMarginAccountPk = await client.initMarginAccount(connection, mangoProgramId, mangoGroup, buyerOwner); + let buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccountPk, dexProgramId); + + const { spotMarket, baseSymbol, quoteSymbol } = await getSpotMarketDetails(mangoGroupSpotMarket); + const baseSymbolIndex = mangoGroupSymbols.findIndex(x => x === baseSymbol); + const quoteSymbolIndex = mangoGroupSymbols.findIndex(x => x === quoteSymbol); + + const [orderSize, orderPrice, _] = await getOrderSizeAndPrice(connection, spotMarket, mangoGroupTokenMappings, baseSymbol, quoteSymbol, 'buy'); + const neededQuoteAmount = orderPrice * orderSize; + const neededBaseAmountForAllTrades = orderSize * orderQuantity; + const neededQuoteAmountForAllTrades = neededQuoteAmount * orderQuantity; + console.info("neededQuoteAmountForAllTrades:", neededQuoteAmountForAllTrades); + + await createTokenAccountWithBalance(connection, buyerOwner, baseSymbol, mangoGroupTokenMappings, clusterIds.faucets, neededQuoteAmountForAllTrades); + await performSingleDepositOrWithdrawal(connection, buyerOwner, client, mangoGroup, mangoProgramId, baseSymbol, mangoGroupTokenMappings, buyerMarginAccount, 'deposit', neededQuoteAmountForAllTrades); + + await requestPriceChange(mangoGroup, orderPrice, baseSymbol); + + for (let i = 0; i < orderQuantity; i++) { + console.info(`Placing a buy order of ${orderSize} ${baseSymbol} for ${orderPrice} ${quoteSymbol} = ~${neededQuoteAmount} ${quoteSymbol} - ${i + 1}/${orderQuantity}`); + buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccount.publicKey, dexProgramId); + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, buyerMarginAccount, spotMarket, buyerOwner, 'buy', orderPrice, orderSize); + } + buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccount.publicKey, dexProgramId); + openOrdersForOwner = await getAndDecodeBidsAndAsksForOwner(connection, spotMarket, buyerMarginAccount.openOrdersAccounts[marketIndex]); + // TODO: this should be a for loop of cancellations + // NOTE: Maybe trying cancelling last order not first + expect(openOrdersForOwner).to.be.an('array').and.to.have.lengthOf(128); + await client.cancelOrder(connection, mangoProgramId, mangoGroup, buyerMarginAccount, buyerOwner, spotMarket, openOrdersForOwner[0]); + buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccount.publicKey, dexProgramId); + openOrdersForOwner = await getAndDecodeBidsAndAsksForOwner(connection, spotMarket, buyerMarginAccount.openOrdersAccounts[marketIndex]); + expect(openOrdersForOwner).to.be.an('array').and.to.have.lengthOf(127); + for (let i = 0; i < orderQuantityAfter; i++) { + console.info(`Placing a buy order of ${orderSize} ${baseSymbol} for ${orderPrice} ${quoteSymbol} = ~${neededQuoteAmount} ${quoteSymbol} - ${i + 1}/${orderQuantityAfter}`); + buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccount.publicKey, dexProgramId); + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, buyerMarginAccount, spotMarket, buyerOwner, 'buy', orderPrice, orderSize); + } + expect(openOrdersForOwner).to.be.an('array').and.to.have.lengthOf(128); +} + +async function stressTestMatchOrder(mangoGroupSpotMarket: any, orderQuantity: number): Promise { + let bna: any, allAsks: any[], allBids: any[]; + const sellerOwner = await createWalletAndRequestAirdrop(connection, 5); + prettyPrintOwnerKeys(sellerOwner, "Seller"); + const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk); + const mangoGroupTokenMappings = await createMangoGroupSymbolMappings(connection, mangoGroupIds); + const sellerMarginAccountPk = await client.initMarginAccount(connection, mangoProgramId, mangoGroup, sellerOwner); + let sellerMarginAccount = await client.getMarginAccount(connection, sellerMarginAccountPk, dexProgramId); + + const { spotMarket, baseSymbol, quoteSymbol } = await getSpotMarketDetails(mangoGroupSpotMarket); + + const [orderSize, orderPrice, _] = await getOrderSizeAndPrice(connection, spotMarket, mangoGroupTokenMappings, baseSymbol, quoteSymbol, 'sell'); + const neededQuoteAmount = orderPrice * orderSize; + const neededBaseAmountForAllTrades = orderSize * orderQuantity; + const neededQuoteAmountForAllTrades = neededQuoteAmount * orderQuantity; + await createTokenAccountWithBalance(connection, sellerOwner, baseSymbol, mangoGroupTokenMappings, clusterIds.faucets, neededBaseAmountForAllTrades); + await performSingleDepositOrWithdrawal(connection, sellerOwner, client, mangoGroup, mangoProgramId, baseSymbol, mangoGroupTokenMappings, sellerMarginAccount, 'deposit', neededBaseAmountForAllTrades); + for (let i = 0; i < orderQuantity; i++) { + console.info(`Placing a sell order of ${orderSize} ${baseSymbol} for ${orderPrice} ${quoteSymbol} = ~${neededQuoteAmount} USD - ${i + 1}/${orderQuantity}`); + sellerMarginAccount = await client.getMarginAccount(connection, sellerMarginAccountPk, dexProgramId); + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, sellerMarginAccount, spotMarket, sellerOwner, 'sell', orderPrice, orderSize); + } + + bna = await getAndDecodeBidsAndAsks(connection, spotMarket); + allAsks = [...bna.askOrderBook].map(x => ({ price: x.price, size: x.size })); + allBids = [...bna.bidOrderBook].map(x => ({ price: x.price, size: x.size })); + + const buyerOwner = await createWalletAndRequestAirdrop(connection, 5); + prettyPrintOwnerKeys(buyerOwner, "Buyer"); + const buyerMarginAccountPk = await client.initMarginAccount(connection, mangoProgramId, mangoGroup, buyerOwner); + const buyerMarginAccount = await client.getMarginAccount(connection, buyerMarginAccountPk, dexProgramId); + await createTokenAccountWithBalance(connection, buyerOwner, quoteSymbol, mangoGroupTokenMappings, clusterIds.faucets, neededQuoteAmountForAllTrades); + await performSingleDepositOrWithdrawal(connection, buyerOwner, client, mangoGroup, mangoProgramId, quoteSymbol, mangoGroupTokenMappings, buyerMarginAccount, 'deposit', neededQuoteAmountForAllTrades); + console.info(`Placing a buy order of ${neededBaseAmountForAllTrades} ${baseSymbol} for ${orderPrice} ${quoteSymbol} = ~${neededQuoteAmountForAllTrades} ${quoteSymbol}`); + const buyTxHash = await client.placeAndSettle(connection, mangoProgramId, mangoGroup, buyerMarginAccount, spotMarket, buyerOwner, 'buy', orderPrice, neededBaseAmountForAllTrades); + console.info("buyTxHash:", buyTxHash); + await connection.confirmTransaction(buyTxHash, 'finalized'); + const buyConfirmedTx: any = await connection.getConfirmedTransaction(buyTxHash); + const buyTxLogInfo = extractInfoFromLogs(buyConfirmedTx); + console.info("Buy txLogInfo:", buyTxLogInfo); + + bna = await getAndDecodeBidsAndAsks(connection, spotMarket); + allAsks = [...bna.askOrderBook].map(x => ({ price: x.price, size: x.size })); + allBids = [...bna.bidOrderBook].map(x => ({ price: x.price, size: x.size })); + expect(allAsks).to.be.empty; + expect(allBids).to.be.empty; +} + +async function stressTestLiquidation(mangoGroupSpotMarket: any, orderQuantity: number, shouldPartialLiquidate: boolean = false) { + let bna: any, allAsks: any[], allBids: any[], prices: number[]; + let leverageCoefficient = 15; + const liqeeOwner = await createWalletAndRequestAirdrop(connection, 5); + prettyPrintOwnerKeys(liqeeOwner, "Liqee"); + const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk); + const mangoGroupTokenMappings = await createMangoGroupSymbolMappings(connection, mangoGroupIds); + const liqeeMarginAccountPk = await client.initMarginAccount(connection, mangoProgramId, mangoGroup, liqeeOwner); + let liqeeMarginAccount = await client.getMarginAccount(connection, liqeeMarginAccountPk, dexProgramId); + + const { spotMarket, baseSymbol, quoteSymbol } = await getSpotMarketDetails(mangoGroupSpotMarket); + const baseSymbolIndex = mangoGroupSymbols.findIndex(x => x === baseSymbol); + const quoteSymbolIndex = mangoGroupSymbols.findIndex(x => x === quoteSymbol); + + const [orderSize, orderPrice, _] = await getOrderSizeAndPrice(connection, spotMarket, mangoGroupTokenMappings, baseSymbol, quoteSymbol, 'buy'); + const neededQuoteAmount = orderPrice * orderSize; + const neededBaseAmountForAllTrades = orderSize * orderQuantity; + const neededQuoteAmountForAllTrades = neededQuoteAmount * orderQuantity; + console.info("neededBaseAmountForAllTrades:", neededBaseAmountForAllTrades); + + await createTokenAccountWithBalance(connection, liqeeOwner, baseSymbol, mangoGroupTokenMappings, clusterIds.faucets, neededBaseAmountForAllTrades); + await performSingleDepositOrWithdrawal(connection, liqeeOwner, client, mangoGroup, mangoProgramId, baseSymbol, mangoGroupTokenMappings, liqeeMarginAccount, 'deposit', neededBaseAmountForAllTrades); + + prices = await requestPriceChange(mangoGroup, orderPrice, baseSymbol); + + for (let i = 0; i < orderQuantity; i++) { + console.info(`Placing a buy order of ${orderSize} ${baseSymbol} for ${orderPrice} ${quoteSymbol} = ~${neededQuoteAmount} ${quoteSymbol} - ${i + 1}/${orderQuantity}`); + liqeeMarginAccount = await client.getMarginAccount(connection, liqeeMarginAccountPk, dexProgramId); + await client.placeAndSettle(connection, mangoProgramId, mangoGroup, liqeeMarginAccount, spotMarket, liqeeOwner, 'buy', orderPrice, orderSize); + } + + liqeeMarginAccount = await client.getMarginAccount(connection, liqeeMarginAccountPk, dexProgramId); + + console.info("collRatio before price change:", liqeeMarginAccount.getCollateralRatio(mangoGroup, prices)); + prices = await requestPriceChange(mangoGroup, orderPrice / leverageCoefficient, baseSymbol); + console.info("collRatio after price change:", liqeeMarginAccount.getCollateralRatio(mangoGroup, prices)); + + const liqorOwner = await createWalletAndRequestAirdrop(connection, 5); + prettyPrintOwnerKeys(liqeeOwner, "Liqor"); + for (let mangoGroupSymbol of mangoGroupSymbols) { + const requiredBalance = (mangoGroupSymbol === quoteSymbol) ? neededQuoteAmountForAllTrades : 0; + await createTokenAccountWithBalance(connection, liqorOwner, mangoGroupSymbol, mangoGroupTokenMappings, clusterIds.faucets, requiredBalance); + } + const tokenWallets = (await Promise.all( + mangoGroup.tokens.map( + (mint) => findLargestTokenAccountForOwner(connection, liqorOwner.publicKey, mint).then( + (response) => response.publicKey + ) + ) + )); + let liquidationTxHash: string; + if (shouldPartialLiquidate) { + liquidationTxHash = await client.partialLiquidate(connection, mangoProgramId, mangoGroup, liqeeMarginAccount, liqorOwner, tokenWallets[quoteSymbolIndex], tokenWallets[baseSymbolIndex], quoteSymbolIndex, baseSymbolIndex, neededQuoteAmountForAllTrades); + } else { + const depositQuantities = new Array(tokenWallets.length).fill(0); + depositQuantities[quoteSymbolIndex] = neededQuoteAmountForAllTrades; + liquidationTxHash = await client.liquidate(connection, mangoProgramId, mangoGroup, liqeeMarginAccount, liqorOwner, tokenWallets, depositQuantities); + } + console.info("liquidationTxHash:", liquidationTxHash); + await connection.confirmTransaction(liquidationTxHash, 'finalized'); + const liquidationConfirmedTx: any = await connection.getConfirmedTransaction(liquidationTxHash); + const liquidationTxLogInfo = extractInfoFromLogs(liquidationConfirmedTx); + console.info("Liquidation txLogInfo:", liquidationTxLogInfo); +} + +const mangoGroupName = 'BTC_ETH_SOL_SRM_USDC'; +const mangoGroupSymbols = mangoGroupName.split('_'); +const mangoGroupIds = clusterIds.mango_groups[mangoGroupName]; +const mangoGroupSpotMarkets: [string, string][] = Object.entries(mangoGroupIds.spot_market_symbols); +const mangoGroupPk = new PublicKey(mangoGroupIds.mango_group_pk); + +const mangoGroupSpotMarket = mangoGroupSpotMarkets[0]; //BTC/USDC +// const mangoGroupSpotMarket = mangoGroupSpotMarkets[1]; //ETH/USDC +// const mangoGroupSpotMarket = mangoGroupSpotMarkets[2]; //SOL/USDC +// const mangoGroupSpotMarket = mangoGroupSpotMarkets[3]; //SRM/USDC + +describe('Log stuff', async() => { + // it('should log token decimals', async() => { + // const MINT_LAYOUT = struct([blob(44), u8('decimals'), blob(37)]); + // const mainnetTokensToTest = [ + // ['BTC', '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E'], + // ['ETH', '2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk'], + // ['SOL', 'So11111111111111111111111111111111111111112'], + // ['SRM', 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt'], + // ['USDT', 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'], + // ['USDC', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'], + // ]; + // const devnetTokensToTest = [ + // ['BTC', 'bypQzRBaSDWiKhoAw3hNkf35eF3z3AZCU8Sxks6mTPP'], + // ['ETH', 'ErWGBLBQMwdyC4H3MR8ef6pFK6gyHAyBxy4o1mHoqKzm'], + // ['SOL', 'So11111111111111111111111111111111111111112'], + // ['SRM', '9FbAMDvXqNjPqZSYt4EWTguJuDrGkfvwr3gSFpiSbX9S'], + // ['USDT', '7KBVenLz5WNH4PA5MdGkJNpDDyNKnBQTwnz1UqJv9GUm'], + // ['USDC', 'H6hy7Ykzc43EuGivv7VVuUKNpKgUoFAfUY3wdPr4UyRX'], + // ]; + // for (let [tokenName, tokenMint] of mainnetTokensToTest) { + // const data: any = await mainnetConnection.getAccountInfo(new PublicKey(tokenMint)); + // const info = MINT_LAYOUT.decode(data.data); + // console.info(`Mainnet ${tokenName} decimals: ${info.decimals}`); + // } + // for (let [tokenName, tokenMint] of devnetTokensToTest) { + // const data: any = await connection.getAccountInfo(new PublicKey(tokenMint)); + // const info = MINT_LAYOUT.decode(data.data); + // console.info(`Devnet ${tokenName} decimals: ${info.decimals}`); + // }; + // }); + // it('should log lotSizes', async() => { + // const mainnetSpotMarketsToTest = [ + // ['BTC/USDC', 'A8YFbxQYFVqKZaoYJLLUVcQiWP7G2MeEgW5wsAQgMvFw'], + // ['ETH/USDC', '4tSvZvnbyzHXLMTiFonMyxZoHmFqau1XArcRCVHLZ5gX'], + // ['SOL/USDC', '9wFFyRfZBsuAha4YcuxcXLKwMxJR43S7fPfQLusDBzvT'], + // ['SRM/USDC', 'ByRys5tuUWDgL73G8JBAEfkdFf8JWBzPBDHsBVQ5vbQA'], + // ]; + // for (let [spotMarketName, spotMarketAddress] of mainnetSpotMarketsToTest) { + // const spotMarket = await Market.load(mainnetConnection, new PublicKey(spotMarketAddress), { skipPreflight: true, commitment: 'singleGossip'}, mainnetDexProgramId); + // console.info(`Mainnet ${spotMarketName} base/quote lotSizes: ${spotMarket['_decoded'].baseLotSize.toString()}/${spotMarket['_decoded'].quoteLotSize.toString()}`); + // } + // }) + // it ('should log order', async() => { + // const { spotMarket } = await getSpotMarketDetails(mangoGroupSpotMarket); + // let bna = await getAndDecodeBidsAndAsks(connection, spotMarket); + // let allAsks: any[] = [...bna.askOrderBook].map(x => ({ price: x.price, size: x.size })).reverse(); + // let allBids: any[] = [...bna.bidOrderBook].map(x => ({ price: x.price, size: x.size })).reverse(); + // console.info(allAsks); + // console.info(allBids); + // }) +}) + +describe('create account with test money', async() => { + it('should create an account with test money', async() => { + await initAccountsWithBalances([50, 50, 50, 1000, 100000]); + }); +}); + +describe('stress test order limits', async() => { + // before(async () => { + // await cleanOrderBook(mangoGroupSpotMarket); + // }); + // it('should be able to place 129th order after cancelling one', async() => { + // await placeNOrdersAfterLimit(mangoGroupSpotMarket, 0, 1); + // }); +}); + +describe('stress testing matching orders', async() => { + // before(async () => { + // await cleanOrderBook(mangoGroupSpotMarket); + // }); + // it('should match 1 order at a single price', async() => { + // await stressTestMatchOrder(mangoGroupSpotMarket, 1); + // }); + // it('should match 10 orders at a single price', async() => { + // await stressTestMatchOrder(mangoGroupSpotMarket, 10); + // }); + // it('should match 20 orders at a single price', async() => { + // await stressTestMatchOrder(mangoGroupSpotMarket, 20); + // }); + // it('should match 25 orders at a single price', async() => { + // await stressTestMatchOrder(mangoGroupSpotMarket, 25); + // }); +}); + +describe('stress testing liquidation', async() => { + // before(async () => { + // await cleanOrderBook(mangoGroupSpotMarket); + // }); + // it('should liquidate an account with 1 open order', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 1); + // }); + // it('should liquidate an account with 10 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 10); + // }); + // it('should liquidate an account with 20 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 20); + // }); + // it('should liquidate an account with 25 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 25); + // }); + // it('should liquidate an account with 128 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 128); + // }); +}); + +describe('stress testing partial liquidation', async() => { + // before(async () => { + // await cleanOrderBook(mangoGroupSpotMarket); + // }); + // it('should partially liquidate an account with 1 open order', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 1, true); + // }); + // it('should partially liquidate an account with 10 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 10, true); + // }); + // it('should partially liquidate an account with 20 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 20, true); + // }); + // it('should partially liquidate an account with 25 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 25, true); + // }); + // it('should partially liquidate an account with 128 open orders', async() => { + // await stressTestLiquidation(mangoGroupSpotMarket, 128, true); + // }); +}); diff --git a/tests/test_utils.ts b/tests/test_utils.ts new file mode 100644 index 0000000..74b3922 --- /dev/null +++ b/tests/test_utils.ts @@ -0,0 +1,444 @@ +import { MangoClient, MangoGroup, MarginAccount } from '../src/client'; +import { Account, Connection, PublicKey, SystemProgram, Transaction, TransactionInstruction, TransactionSignature, TransferParams } from '@solana/web3.js'; +import { Market, TokenInstructions, OpenOrders, Orderbook } from '@project-serum/serum'; +import { token } from '@project-serum/common'; +import { u64, NATIVE_MINT } from "@solana/spl-token"; +import { sleep } from '../src/utils'; +import fs from 'fs'; +console.log = function () {}; // NOTE: Disable all unnecessary logging + +const FAUCET_PROGRAM_ID = new PublicKey( + "4bXpkKSV8swHSnwqtzuboGPaPDeEgAn4Vt8GfarV5rZt" +); + +const getPDA = () => { + return PublicKey.findProgramAddress([Buffer.from("faucet")], FAUCET_PROGRAM_ID); +} + +export async function _sendTransaction ( + connection: Connection, + transaction: Transaction, + signers: Account[], +): Promise { + const signature = await connection.sendTransaction(transaction, signers); + try { + await connection.confirmTransaction(signature); + } catch (e) { + console.info("Error while confirming, trying again"); + await connection.confirmTransaction(signature); + } + return signature; +} + +export async function createTokenAccountInstrs ( + connection: Connection, + newAccountPubkey: PublicKey, + mint: PublicKey, + ownerPk: PublicKey, + lamports?: number, +): Promise { + if (lamports === undefined) lamports = await connection.getMinimumBalanceForRentExemption(165); + return [ + SystemProgram.createAccount({ + fromPubkey: ownerPk, + newAccountPubkey, + space: 165, + lamports, + programId: TokenInstructions.TOKEN_PROGRAM_ID, + }), + TokenInstructions.initializeAccount({ + account: newAccountPubkey, + mint, + owner: ownerPk, + }), + ]; +} + +export async function createWrappedNativeAccount ( + connection: Connection, + owner: Account, + amount: number +): Promise { + // Allocate memory for the account + const balanceNeeded = await connection.getMinimumBalanceForRentExemption(165); + const newAccount = new Account(); + const tx = new Transaction(); + tx.add(SystemProgram.createAccount({ + fromPubkey: owner.publicKey, + newAccountPubkey: newAccount.publicKey, + lamports: balanceNeeded, + space: 165, + programId: TokenInstructions.TOKEN_PROGRAM_ID, + })); // Send lamports to it (these will be wrapped into native tokens by the token program) + tx.add(SystemProgram.transfer({ + fromPubkey: owner.publicKey, + toPubkey: newAccount.publicKey, + lamports: amount + })); // Assign the new account to the native token mint. + // the account will be initialized with a balance equal to the native token balance. + // (i.e. amount) + tx.add(TokenInstructions.initializeAccount({ + account: newAccount.publicKey, + mint: NATIVE_MINT, + owner: owner.publicKey, + })); + const signers = [owner, newAccount]; + const signerPks = signers.map(x => x.publicKey); + tx.setSigners(...signerPks); + await _sendTransaction(connection, tx, signers); + return newAccount.publicKey; +} + +export async function createTokenAccount ( + connection: Connection, + mint: PublicKey, + owner: Account +): Promise { + const newAccount = new Account(); + const tx = new Transaction(); + const signers = [owner, newAccount]; + const signerPks = signers.map(x => x.publicKey); + tx.add(...(await createTokenAccountInstrs(connection, newAccount.publicKey, mint, owner.publicKey))); + tx.setSigners(...signerPks); + await _sendTransaction(connection, tx, signers); + return newAccount.publicKey; +} + +export async function createWalletAndRequestAirdrop( + connection: Connection, + amount: number +): Promise { + console.info("Creating a new wallet"); + const owner = new Account(); + if (amount < 1) throw new Error("SOL is needed for gas fees so at least 1 SOL is required"); + await airdropSol(connection, owner, amount); + return owner; +} + +export async function createMangoGroupSymbolMappings ( + connection: Connection, + mangoGroupIds: any, +): Promise { + const mangoGroupTokenMappings = {}; + const mangoGroupSymbols: [string, string][] = Object.entries(mangoGroupIds.symbols); + for (let [tokenName, tokenMint] of mangoGroupSymbols) { + const tokenSupply = await connection.getTokenSupply(new PublicKey(tokenMint)); + mangoGroupTokenMappings[tokenMint] = { tokenMint: new PublicKey(tokenMint), tokenName, decimals: tokenSupply.value.decimals }; + } + return mangoGroupTokenMappings; +} + +export async function getOwnedTokenAccounts( + connection: Connection, + owner: Account, +): Promise { + const ownedTokenAccounts = await token.getOwnedTokenAccounts(connection, owner.publicKey); + return ownedTokenAccounts; +} + +export async function updateMarginTokenAccountsAndDeposits( + connection: Connection, + owner: Account, + client: MangoClient, + mangoGroup: MangoGroup, + marginAccountPk: PublicKey | null, + state: any, + dexProgramId: PublicKey, +): Promise{ + state.ownedTokenAccounts = await token.getOwnedTokenAccounts(connection, owner.publicKey); + state.marginAccount = (marginAccountPk) ? await client.getMarginAccount(connection, marginAccountPk, dexProgramId) : null; + state.deposits = (state.marginAccount) ? state.marginAccount.getDeposits(mangoGroup) : []; +} + +export async function buildAirdropTokensIx( + amount: u64, + tokenMintPublicKey: PublicKey, + destinationAccountPubkey: PublicKey, + faucetPubkey: PublicKey +) { + const pubkeyNonce = await getPDA(); + const keys = [ + { pubkey: pubkeyNonce[0], isSigner: false, isWritable: false }, + { pubkey: tokenMintPublicKey, isSigner: false, isWritable: true }, + { pubkey: destinationAccountPubkey, isSigner: false, isWritable: true }, + { pubkey: TokenInstructions.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, + { pubkey: faucetPubkey, isSigner: false, isWritable: false } + ]; + return new TransactionInstruction({ + programId: FAUCET_PROGRAM_ID, + data: Buffer.from([1, ...amount.toArray("le", 8)]), + keys + }); +}; + +export async function airdropTokens( + connection: Connection, + feePayerAccount: Account, + faucetAddress: string, + tokenDestinationPublicKey: PublicKey, + mint: PublicKey, + amount: u64 +) { + const faucetPubkey = new PublicKey(faucetAddress); + const ix = await buildAirdropTokensIx(amount, mint, tokenDestinationPublicKey, faucetPubkey); + const tx = new Transaction(); + tx.add(ix); + const signers = [feePayerAccount]; + await _sendTransaction(connection, tx, signers); + return tokenDestinationPublicKey.toBase58(); +}; + +export async function airdropToken( + connection: Connection, + owner: Account, + tokenName: string, + mangoGroupTokenMappings: any, + faucetIds: any, + amount: number +): Promise { + if (tokenName !== 'SOL') throw new Error('This airdrop is function is not meant for SOL'); + const ownedTokenAccounts = await token.getOwnedTokenAccounts(connection, owner.publicKey); + const tokenMapping: any = Object.values(mangoGroupTokenMappings).find((x: any) => x.tokenName === tokenName); + const { tokenMint, decimals } = tokenMapping; + const ownedTokenAccount = ownedTokenAccounts.find((x: any) => x.account.mint.equals(tokenMint)); + if (!ownedTokenAccount) throw new Error(`Token account doesn't exist for ${tokenName}`); + const multiplier = Math.pow(10, decimals); + await airdropTokens(connection, owner, faucetIds[tokenName], ownedTokenAccount.publicKey, tokenMint, new u64(amount * multiplier)); +} + +export async function airdropSol( + connection: Connection, + owner: Account, + amount: number +): Promise { + const roundedSolAmount = Math.round(amount); + console.info(`Requesting ${roundedSolAmount} SOL`); + const generousAccount = [115,98,128,18,66,112,147,244,46,244,118,106,91,202,56,83,58,71,89,226,32,177,177,240,189,23,209,176,138,119,130,140,6,149,55,70,215,34,108,133,225,117,38,141,74,246,232,76,176,10,207,221,68,179,115,158,106,133,35,30,4,177,124,5]; + const backupAcc = new Account(generousAccount); + const tx = new Transaction(); + tx.add(SystemProgram.transfer({fromPubkey: backupAcc.publicKey, lamports: roundedSolAmount * 1e9, toPubkey: owner.publicKey})); + const signers = [backupAcc]; + const signerPks = signers.map(x => x.publicKey); + tx.setSigners(...signerPks); + await _sendTransaction(connection, tx, signers); +} + +export async function airdropMangoGroupTokens( + connection: Connection, + owner: Account, + mangoGroup: MangoGroup, + mangoGroupTokenMappings: any, + ownedTokenAccounts: any, + faucetIds: any +): Promise { + (await Promise.all( + mangoGroup.tokens.map(async (mint: PublicKey) => { + const {tokenName, decimals} = mangoGroupTokenMappings[mint.toString()]; + if (tokenName) { + const ownedTokenAccount = ownedTokenAccounts.find((x: any) => x.account.mint.equals(mint)); + if (tokenName !== 'SOL') { + const multiplier = Math.pow(10, decimals); + await airdropTokens(connection, owner, faucetIds[tokenName], ownedTokenAccount.publicKey, mint, new u64(100 * multiplier)); + } + } + }) + )); +} + +export async function createTokenAccountWithBalance( + connection: Connection, + owner: Account, + tokenName: string, + mangoGroupTokenMappings: any, + faucetIds: any, + amount: number +) { + const tokenMapping: any = Object.values(mangoGroupTokenMappings).find((x: any) => x.tokenName === tokenName); + const { tokenMint, decimals } = tokenMapping; + const multiplier = Math.pow(10, decimals); + const processedAmount = amount * multiplier; + if (tokenName === 'SOL') { + await airdropSol(connection, owner, amount); + await createWrappedNativeAccount(connection, owner, processedAmount); + } else { + await createTokenAccount(connection, tokenMint, owner); + if (amount > 0) { + const ownedTokenAccounts = await token.getOwnedTokenAccounts(connection, owner.publicKey); + const ownedTokenAccount = ownedTokenAccounts.find((x: any) => x.account.mint.equals(tokenMint)); + if (!ownedTokenAccount) throw new Error(`Token account doesn't exist for ${tokenName}`); + await airdropTokens(connection, owner, faucetIds[tokenName], ownedTokenAccount.publicKey, tokenMint, new u64(processedAmount)); + } + } +} + +export async function createTokenAccountsForMangoGroupTokens ( + connection: Connection, + owner: Account, + mangoGroup: MangoGroup, + mangoGroupTokenMappings: any, +) { + (await Promise.all( + mangoGroup.tokens.map(async (mint: PublicKey) => { + const {tokenName} = mangoGroupTokenMappings[mint.toString()]; + if (tokenName) { + if (tokenName === 'SOL') { + await createWrappedNativeAccount(connection, owner, 100 * 1e9); + } else { + await createTokenAccount(connection, mint, owner); + } + } + }) + )); +} + +export async function performSingleDepositOrWithdrawal ( + connection: Connection, + owner: Account, + client: MangoClient, + mangoGroup: MangoGroup, + mangoProgramId: PublicKey, + tokenName: string, + mangoGroupTokenMappings: any, + marginAccount: any, + type: string, + amount: number +) { + const tokenMapping: any = Object.values(mangoGroupTokenMappings).find((x: any) => x.tokenName === tokenName); + const { tokenMint } = tokenMapping; + const ownedTokenAccounts = await token.getOwnedTokenAccounts(connection, owner.publicKey); + const ownedTokenAccount = ownedTokenAccounts.find((x: any) => x.account.mint.equals(tokenMint)); + if (!ownedTokenAccount) throw new Error(`Token account doesn't exist for ${tokenName}`); + if (type === 'deposit') { + await client.deposit(connection, mangoProgramId, mangoGroup, marginAccount, owner, tokenMint, ownedTokenAccount.publicKey, Number(amount)); + } else if (type === 'withdraw') { + await client.withdraw(connection, mangoProgramId, mangoGroup, marginAccount, owner, tokenMint, ownedTokenAccount.publicKey, Number(amount)); + } +} + +export async function performDepositOrWithdrawal ( + connection: Connection, + owner: Account, + client: MangoClient, + mangoGroup: MangoGroup, + mangoProgramId: PublicKey, + state: any, + type: string, + amount: number +) { + (await Promise.all( + mangoGroup.tokens.map(async (mint: PublicKey) => { + const ownedTokenAccount = state.ownedTokenAccounts.find((x: any) => x.account.mint.equals(mint)); + if (type === 'deposit') { + await client.deposit(connection, mangoProgramId, mangoGroup, state.marginAccount, owner, mint, ownedTokenAccount.publicKey, Number(amount)); + } else if (type === 'withdraw') { + await client.withdraw(connection, mangoProgramId, mangoGroup, state.marginAccount, owner, mint, ownedTokenAccount.publicKey, Number(amount)); + } + }) + )); +} + +export async function getAndDecodeBidsAndAsks ( + connection: Connection, + spotMarket: Market +): Promise { + const bidData = (await connection.getAccountInfo(spotMarket['_decoded'].bids))?.data; + const bidOrderBook = bidData ? Orderbook.decode(spotMarket, Buffer.from(bidData)): []; + const askData = (await connection.getAccountInfo(spotMarket['_decoded'].asks))?.data; + const askOrderBook = askData ? Orderbook.decode(spotMarket, Buffer.from(askData)): []; + return {bidOrderBook, askOrderBook}; +} + +export async function getAndDecodeBidsAndAsksForOwner ( + connection: Connection, + spotMarket: Market, + openOrdersAccount: OpenOrders | undefined, +): Promise { + if (!openOrdersAccount) throw new Error(`openOrdersAccount not found`); + const { bidOrderBook, askOrderBook } = await getAndDecodeBidsAndAsks(connection, spotMarket); + const openOrdersForOwner = [...bidOrderBook, ...askOrderBook].filter((o) => + o.openOrdersAddress.equals(openOrdersAccount.address) + ) + return openOrdersForOwner; +} + +export async function getBidOrAskPriceEdge( + connection: Connection, + spotMarket: Market, + bidOrAsk: string, + maxOrMin: string +): Promise{ + const { bidOrderBook, askOrderBook } = await getAndDecodeBidsAndAsks(connection, spotMarket); + const [orderBookSide, orderBookOtherSide] = (bidOrAsk === 'bid' ? [bidOrderBook, askOrderBook] : [askOrderBook, bidOrderBook]); + const orderBookSidePrices: number[] = [...orderBookSide].map(x => x.price); + if (!orderBookSidePrices.length) { + // NOTE: This is a very arbitrary error prevention mechanism if one or both sides of the order book are empty + const orderBookOtherSidePrices: number[] = [...orderBookOtherSide].map(x => x.price); + if (bidOrAsk === 'bid') { + orderBookSidePrices.push(orderBookOtherSidePrices.length ? Math.min(...orderBookOtherSidePrices) / 2 : 10); // TODO: Maybe have a default value + } else { + orderBookSidePrices.push(orderBookOtherSidePrices.length ? Math.max(...orderBookOtherSidePrices) + 10 : 10); // TODO: Maybe have a default value + } + } + if (maxOrMin === 'min') { + return Math.min(...orderBookSidePrices); + } else { + return Math.max(...orderBookSidePrices); + } +} + +export async function getOrderSizeAndPrice( + connection: Connection, + spotMarket: Market, + mangoGroupTokenMappings: any, + baseSymbol: string, + quoteSymbol: string, + side: string +): Promise{ + // NOTE: Always use minOrderSize + const tokenMapping: any = Object.values(mangoGroupTokenMappings).find((x: any) => x.tokenName === baseSymbol); + const { decimals } = tokenMapping; + const [stepSize, orderSize] = (decimals === 6) ? [0.01, 1] : [10, 0.01]; + const edge = (side === 'buy') ? ['bid', 'max'] : ['ask', 'min']; + const orderPrice: number = Math.max(await getBidOrAskPriceEdge(connection, spotMarket, edge[0], edge[1]), stepSize); + return [orderSize, orderPrice, stepSize]; +} + + +export function extractInfoFromLogs( + confirmedTx: any +): any { + if (!confirmedTx) throw new Error(`Couldn't find confirmed transaction`); + let invocationCount: number = 0; + let invocationComputeUnits: any[] = []; + const logMessages = confirmedTx.meta.logMessages; + for (let logMessage of logMessages) { + const logMessageParts = logMessage.split(' '); + if (logMessageParts.length === 4) { + if (logMessageParts[2] === 'invoke' && (/(\[[0-9]*\])/g).test(logMessageParts[3])) { + invocationCount += 1; + } + } else if (logMessageParts.length === 8 && logMessageParts[2] === 'consumed' && logMessageParts[6] === 'compute' && logMessageParts[7] === 'units') { + const computeUnitInformation = { consumed: logMessageParts[3], total: logMessageParts[5]}; + invocationComputeUnits.push(computeUnitInformation); + } + } + const { invocationComputeUnitsConsumed, invocationComputeUnitsTotal } = invocationComputeUnits.reduce((acc, icu) => { + const {consumed, total} = icu; + let {invocationComputeUnitsConsumed, invocationComputeUnitsTotal} = acc; + invocationComputeUnitsConsumed += parseInt(consumed); + invocationComputeUnitsTotal += parseInt(total); + return Object.assign(acc, { invocationComputeUnitsConsumed, invocationComputeUnitsTotal }); + }, {invocationComputeUnitsConsumed: 0, invocationComputeUnitsTotal: 0}); + return { invocationCount, invocationComputeUnitsConsumed, invocationComputeUnitsTotal, invocationComputeUnits }; +} + +export function prettyPrintOwnerKeys( + owner: Account, + name: string +): void { + console.info("============"); + console.info(`${name}'s wallet's public key: ${owner.publicKey.toString()}`); + console.info("============"); + console.info(`${name}'s wallet's secret, to import in Sollet: \n [${owner.secretKey.toString()}]`); + console.info("============"); +} diff --git a/tsconfig.json b/tsconfig.json index 8083ad6..50af598 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,6 @@ "sourceMap": true, "jsx": "react" }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.test.js", "node_modules", "**/node_modules"] + "include": ["./tests/**/*", "./src/**/*"], + "exclude": ["./tests/**/*.test.js", "./src/**/*.test.js", "node_modules", "**/node_modules"] } diff --git a/yarn.lock b/yarn.lock index 1ae2318..ccb6401 100644 --- a/yarn.lock +++ b/yarn.lock @@ -267,7 +267,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1": +"@babel/runtime@^7.10.5": + version "7.13.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.7.tgz#d494e39d198ee9ca04f4dcb76d25d9d7a1dc961a" + integrity sha512-h+ilqoX998mRVM5FtB5ijRuHUDVt5l3yfoOi2uh18Z/O3hvyaHQ39NpxVkCIG5yFs+mLq/ewFp8Bss6zmWv6ZA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== @@ -541,6 +548,15 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" +"@project-serum/common@^0.0.1-beta.3": + version "0.0.1-beta.3" + resolved "https://registry.yarnpkg.com/@project-serum/common/-/common-0.0.1-beta.3.tgz#53586eaff9d9fd7e8938b1e12080c935b8b6ad07" + integrity sha512-gnQE/eUydTtto5okCgLWj1M97R9RRPJqnhKklikYI7jP/pnNhDmngSXC/dmfzED2GXSJEIKNIlxVw1k+E2Aw3w== + dependencies: + "@project-serum/serum" "^0.13.21" + bn.js "^5.1.2" + superstruct "0.8.3" + "@project-serum/serum@^0.13.20": version "0.13.34" resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.13.34.tgz#c76477c27e14d975afa38b6c352b3abe92af6e52" @@ -550,6 +566,15 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@project-serum/serum@^0.13.21": + version "0.13.37" + resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.13.37.tgz#18cc2613a655a8e782e14c4d55a2707a79fbc625" + integrity sha512-Bt7D/0P0M1b+xyygCU9z1p7Pec6vontzy4Q92TgIg33/J1qiAR/899HXGlr7oho/NntGNwIlbEU22nqsWWuAiA== + dependencies: + "@solana/web3.js" "^0.90.0" + bn.js "^5.1.2" + buffer-layout "^1.2.0" + "@project-serum/sol-wallet-adapter@^0.1.4": version "0.1.8" resolved "https://registry.yarnpkg.com/@project-serum/sol-wallet-adapter/-/sol-wallet-adapter-0.1.8.tgz#90c6c1da793d32ed4ba3c67c5702a5bc804ef197" @@ -572,7 +597,7 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@solana/spl-token@^0.0.13": +"@solana/spl-token@0.0.13": version "0.0.13" resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.0.13.tgz#5e0b235b1f8b34643280401dbfddeb34d13d1acd" integrity sha512-WT8M9V/hxURR5jLbhr3zgwVsgcY6m8UhHtK045w7o+jx8FJ9MKARkj387WBFU7mKiFq0k8jw/8YL7XmnIUuH8Q== @@ -630,6 +655,25 @@ tweetnacl "^1.0.0" ws "^7.0.0" +"@solana/web3.js@^0.95.0": + version "0.95.0" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-0.95.0.tgz#c028c800bf078bec90945240370df51026f8bdab" + integrity sha512-jdjAESYTChAYI1aZwH1RggcoT22BxdB9tDKBOt2Iw9SSpZ1Bb81ydrP+7eksE1AwQj6lpzrgtVt2d3sFosqupQ== + dependencies: + "@babel/runtime" "^7.12.5" + bn.js "^5.0.0" + bs58 "^4.0.1" + buffer "6.0.1" + buffer-layout "^1.2.0" + crypto-hash "^1.2.2" + jayson "^3.4.4" + js-sha3 "^0.8.0" + node-fetch "^2.6.1" + rpc-websockets "^7.4.2" + secp256k1 "^4.0.2" + superstruct "^0.14.2" + tweetnacl "^1.0.0" + "@tsconfig/node10@^1.0.0": version "1.0.7" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.7.tgz#1eb1de36c73478a2479cc661ef5af1c16d86d606" @@ -740,20 +784,20 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.169.tgz#83c217688f07a4d9ef8f28a3ebd1d318f6ff4cbb" integrity sha512-DvmZHoHTFJ8zhVYwCLWbQ7uAbYQEk52Ev2/ZiQ7Y7gQGeV9pjBqjnQpECMHfKS1rCYAhMI7LHVxwyZLZinJgdw== -"@types/mocha@^8.2.0": +"@types/mocha@^8.2.2": version "8.2.2" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0" integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw== "@types/node@*": - version "15.0.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.3.tgz#ee09fcaac513576474c327da5818d421b98db88a" - integrity sha512-/WbxFeBU+0F79z9RdEOXH4CsDga+ibi5M8uEYr91u3CkT/pdWcV8MCook+4wDPnZBexRdwWS+PiVZ2xJviAzcQ== + version "15.0.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67" + integrity sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA== "@types/node@^12.12.54": - version "12.20.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.13.tgz#e743bae112bd779ac9650f907197dd2caa7f0364" - integrity sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A== + version "12.20.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.12.tgz#fd9c1c2cfab536a2383ed1ef70f94adea743a226" + integrity sha512-KQZ1al2hKOONAs2MFv+yTQP1LkDWMrRJ9YCVRalXltOfXsBmH5IownLxQaiq0lnAHwAViLnh2aTYqrPcRGEbgg== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -862,6 +906,11 @@ "@typescript-eslint/types" "4.23.0" eslint-visitor-keys "^2.0.0" +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -923,7 +972,7 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" -ansi-colors@^4.1.1: +ansi-colors@4.1.1, ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== @@ -935,6 +984,11 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" @@ -967,7 +1021,7 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.0.3: +anymatch@^3.0.3, anymatch@~3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -987,6 +1041,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -1181,16 +1240,26 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.2: +bn.js@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^5.1.2: + version "5.1.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== + boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -1229,7 +1298,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1246,6 +1315,11 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + browserslist@^4.14.5: version "4.16.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" @@ -1288,6 +1362,14 @@ buffer-layout@^1.2.0: resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.1.tgz#17b6db7abea303cab35eebd77919b89de026297d" integrity sha512-RUTGEYG1vX0Zp1dStQFl8yeU/LEBPXVtHwzzDbPWkE5zq+Prt9fkFLKNiwmaeHg6BBiRMcQAgj4cynazO6eekw== +buffer@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" + integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + buffer@^5.4.3: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -1427,6 +1509,21 @@ cheerio@0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" +chokidar@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -1461,6 +1558,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -1642,6 +1748,13 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1649,18 +1762,16 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decimal.js@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" @@ -1739,6 +1850,11 @@ diff-sequences@^26.6.2: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -1819,6 +1935,11 @@ dotenv@8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -1934,6 +2055,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2264,6 +2390,14 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -2280,6 +2414,11 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flatted@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" @@ -2325,7 +2464,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2: +fsevents@^2.1.2, fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -2345,7 +2484,7 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -2405,13 +2544,25 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -2460,6 +2611,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -2544,6 +2700,11 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2676,6 +2837,13 @@ is-bigint@^1.0.1: resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" @@ -2776,6 +2944,11 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -2786,7 +2959,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -2815,6 +2988,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -2942,7 +3120,7 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jayson@^3.0.1: +jayson@^3.0.1, jayson@^3.4.4: version "3.6.2" resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.2.tgz#e551e25abf2efe333051a6ed88b10f08c5288f50" integrity sha512-hbl+x2xH6FT7nckw+Pq3lKOIJaMBKOgNJEVfvloDBWB8iSfzn/1U2igj1A5rplqNMFN/OnnaTNw8qPKVmoq83Q== @@ -3332,11 +3510,23 @@ jest@^26.6.3: import-local "^3.0.2" jest-cli "^26.6.3" +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== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" + integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== + dependencies: + argparse "^2.0.1" + js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" @@ -3545,6 +3735,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.assignin@^4.0.9: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" @@ -3620,6 +3817,13 @@ lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3727,7 +3931,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -3752,6 +3956,37 @@ mkdirp@1.0.4, mkdirp@1.x: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mocha@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" + integrity sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.1" + debug "4.3.1" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.6" + growl "1.10.5" + he "1.2.0" + js-yaml "4.0.0" + log-symbols "4.0.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.20" + serialize-javascript "5.0.1" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + wide-align "1.1.3" + workerpool "6.1.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3762,6 +3997,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -3771,6 +4011,11 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nanoid@3.1.20: + version "3.1.20" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" + integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -3803,7 +4048,7 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-fetch@^2.2.0: +node-fetch@^2.2.0, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -3857,7 +4102,7 @@ normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -4011,6 +4256,13 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -4018,6 +4270,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -4205,6 +4464,13 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" @@ -4247,6 +4513,13 @@ readable-stream@^3.1.1: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -4411,7 +4684,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4481,6 +4754,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +serialize-javascript@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -4704,6 +4984,14 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^4.1.0, string-width@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" @@ -4745,6 +5033,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" @@ -4772,11 +5067,24 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +superstruct@0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.8.3.tgz#fb4d8901aca3bf9f79afab1bbab7a7f335cc4ef2" + integrity sha512-LbtbFpktW1FcwxVIJlxdk7bCyBq/GzOx2FSFLRLTUhWIA1gHkYPIl3aXRG5mBdGZtnPNT6t+4eEcLDCMOuBHww== + dependencies: + kind-of "^6.0.2" + tiny-invariant "^1.0.6" + +superstruct@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" + integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== + superstruct@^0.8.3: version "0.8.4" resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.8.4.tgz#478a19649f6b02c6319c02044db6a1f5863c391f" @@ -4785,6 +5093,13 @@ superstruct@^0.8.3: kind-of "^6.0.2" tiny-invariant "^1.0.6" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -5230,6 +5545,13 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which@2.0.2, which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -5237,18 +5559,23 @@ which@^1.2.9: dependencies: isexe "^2.0.0" -which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: - isexe "^2.0.0" + string-width "^1.0.2 || 2" word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +workerpool@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" + integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -5258,6 +5585,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -5293,12 +5629,22 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@20.x: +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.7" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== @@ -5311,6 +5657,29 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -5332,3 +5701,8 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==