From e5df603d33fecab16a17eda8d16bdb4cf2768abf Mon Sep 17 00:00:00 2001 From: Maxence Raballand Date: Mon, 25 Nov 2024 17:12:54 +0100 Subject: [PATCH 1/3] feat: add getTokens and getMarkets --- .changeset/spotty-islands-admire.md | 5 ++ src/actions/index.ts | 16 ++++ src/actions/reader.test.ts | 66 +++++++++++++++ src/actions/reader.ts | 80 +++++++++++++++++++ src/actions/tokens.test.ts | 86 ++++++++++++++++++++ src/actions/tokens.ts | 111 ++++++++++++++++++++++++++ src/builder/index.ts | 4 + src/builder/reader.ts | 16 ++++ src/bundle/public/general-actions.ts | 34 +++++++- src/bundle/public/mangrove-actions.ts | 47 ++++++++++- 10 files changed, 462 insertions(+), 3 deletions(-) create mode 100644 .changeset/spotty-islands-admire.md create mode 100644 src/actions/reader.test.ts create mode 100644 src/actions/reader.ts create mode 100644 src/actions/tokens.test.ts create mode 100644 src/actions/tokens.ts create mode 100644 src/builder/reader.ts diff --git a/.changeset/spotty-islands-admire.md b/.changeset/spotty-islands-admire.md new file mode 100644 index 0000000..81e8cd9 --- /dev/null +++ b/.changeset/spotty-islands-admire.md @@ -0,0 +1,5 @@ +--- +"@mangrovedao/mgv": patch +--- + +Added getTokens and getOpenMarkets diff --git a/src/actions/index.ts b/src/actions/index.ts index 0f23c7d..5ec73c4 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -119,3 +119,19 @@ export type { GetKandelStateResult, KandelStatus, } from './kandel/view.js' + +export { getTokens, GetTokenInfoError } from './tokens.js' + +export type { + GetTokensParams, + GetTokensResult, +} from './tokens.js' + +export { getRawOpenMarkets, getOpenMarkets } from './reader.js' + +export type { + GetOpenMarketArgs, + GetOpenMarketRawArgs, + GetOpenMarketRawResult, + GetOpenMarketResult, +} from './reader.js' diff --git a/src/actions/reader.test.ts b/src/actions/reader.test.ts new file mode 100644 index 0000000..f89c53b --- /dev/null +++ b/src/actions/reader.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, inject, it } from 'vitest' +import { getClient } from '~test/src/client.js' +import { getOpenMarkets } from './reader.js' + +const client = getClient() +const params = inject('mangrove') +const { WETH, USDC, DAI } = inject('tokens') +const { wethDAI, wethUSDC } = inject('markets') + +describe('getOpenMarkets', () => { + it('should return the open markets', async () => { + const markets = await getOpenMarkets(client, params, { + cashnesses: { + WETH: 1, + USDC: 1000, + DAI: 1000, + }, + }) + + expect(markets[0]?.base.address.toLowerCase()).toEqual( + wethUSDC.base.address.toLowerCase(), + ) + expect(markets[0]?.quote.address.toLowerCase()).toEqual( + wethUSDC.quote.address.toLowerCase(), + ) + expect(markets[1]?.base.address.toLowerCase()).toEqual( + wethDAI.base.address.toLowerCase(), + ) + expect(markets[1]?.quote.address.toLowerCase()).toEqual( + wethDAI.quote.address.toLowerCase(), + ) + + expect(markets[0]?.base.symbol).toEqual(WETH.symbol) + expect(markets[0]?.quote.symbol).toEqual(USDC.symbol) + expect(markets[1]?.base.symbol).toEqual(WETH.symbol) + expect(markets[1]?.quote.symbol).toEqual(DAI.symbol) + + expect(markets[0]?.base.decimals).toEqual(WETH.decimals) + expect(markets[0]?.quote.decimals).toEqual(USDC.decimals) + expect(markets[1]?.base.decimals).toEqual(WETH.decimals) + expect(markets[1]?.quote.decimals).toEqual(DAI.decimals) + }) + + it('should return the open markets with inverted cashnesses', async () => { + const markets = await getOpenMarkets(client, params, { + cashnesses: { + WETH: 100000, + USDC: 1000, + DAI: 1000, + }, + }) + + expect(markets[0]?.base.address.toLowerCase()).toEqual( + wethUSDC.quote.address.toLowerCase(), + ) + expect(markets[0]?.quote.address.toLowerCase()).toEqual( + wethUSDC.base.address.toLowerCase(), + ) + expect(markets[1]?.base.address.toLowerCase()).toEqual( + wethDAI.quote.address.toLowerCase(), + ) + expect(markets[1]?.quote.address.toLowerCase()).toEqual( + wethDAI.base.address.toLowerCase(), + ) + }) +}) diff --git a/src/actions/reader.ts b/src/actions/reader.ts new file mode 100644 index 0000000..4461801 --- /dev/null +++ b/src/actions/reader.ts @@ -0,0 +1,80 @@ +import type { Address, Client, ContractFunctionParameters } from 'viem' +import { readContract } from 'viem/actions' +import { getOpenMarketsParams, type mgvReaderABI } from '../builder/reader.js' +import type { + BuiltArgs, + MangroveActionsDefaultParams, + MarketParams, +} from '../types/index.js' +import { getAction } from '../utils/getAction.js' +import { type GetTokensParams, getTokens } from './tokens.js' + +export type GetOpenMarketRawArgs = Omit< + ContractFunctionParameters, + BuiltArgs +> + +export type GetOpenMarketRawResult = { + tkn0: Address + tkn1: Address + tickSpacing: bigint +}[] + +export async function getRawOpenMarkets( + client: Client, + params: MangroveActionsDefaultParams, + args?: GetOpenMarketRawArgs, +): Promise { + const result = await getAction( + client, + readContract, + 'readContract', + )({ + ...args, + address: params.mgvReader, + ...getOpenMarketsParams, + }) + + return result[0] as GetOpenMarketRawResult +} + +export type GetOpenMarketArgs = Omit & + GetOpenMarketRawArgs & { + // symbol -> cashness + cashnesses: Record + } + +export type GetOpenMarketResult = MarketParams[] + +export async function getOpenMarkets( + client: Client, + params: MangroveActionsDefaultParams, + args: GetOpenMarketArgs, +): Promise { + const raw = await getRawOpenMarkets(client, params, args) + const tokens = await getTokens(client, { + ...args, + tokens: raw.flatMap((market) => [market.tkn0, market.tkn1]), + }) + + return raw.map((market): MarketParams => { + // we don't use isAddressEqual because both are supposedly checksummed from viem + const tkn0 = tokens.find((token) => token.address === market.tkn0) + const tkn1 = tokens.find((token) => token.address === market.tkn1) + + if (!tkn0 || !tkn1) { + throw new Error( + 'Token not found, this is a bug, please report at https://github.com/mangrovedao/mgv/issues', + ) + } + + const tkn0Cashness = args.cashnesses[tkn0.symbol] ?? 0 + const tkn1Cashness = args.cashnesses[tkn1.symbol] ?? 0 + + return { + base: tkn0Cashness > tkn1Cashness ? tkn1 : tkn0, + quote: tkn0Cashness > tkn1Cashness ? tkn0 : tkn1, + tickSpacing: market.tickSpacing, + } + }) +} diff --git a/src/actions/tokens.test.ts b/src/actions/tokens.test.ts new file mode 100644 index 0000000..e3bdf29 --- /dev/null +++ b/src/actions/tokens.test.ts @@ -0,0 +1,86 @@ +import { ContractFunctionExecutionError, zeroAddress } from 'viem' +import { describe, expect, inject, it } from 'vitest' +import { getClient } from '~test/src/client.js' +import { GetTokenInfoError, getTokens } from './tokens.js' + +const { WETH, USDC, DAI } = inject('tokens') +const client = getClient() + +describe('tokens', () => { + it('should get tokens', async () => { + const tokens = await getTokens(client, { tokens: [WETH.address] as const }) + expect(tokens).toEqual([WETH]) + + const foundWETH = tokens[0] + + expect(foundWETH.mgvTestToken).toBe(false) + expect(foundWETH.address).toBe(WETH.address) + expect(foundWETH.symbol).toBe(WETH.symbol) + expect(foundWETH.decimals).toBe(WETH.decimals) + }) + + it('should get multiple tokens', async () => { + const tokens = await getTokens(client, { + tokens: [WETH.address, USDC.address, DAI.address] as const, + }) + expect(tokens).toEqual([WETH, USDC, DAI]) + + const foundWETH = tokens[0] + expect(foundWETH.mgvTestToken).toBe(false) + expect(foundWETH.address).toBe(WETH.address) + expect(foundWETH.symbol).toBe(WETH.symbol) + expect(foundWETH.decimals).toBe(WETH.decimals) + + const foundUSDC = tokens[1] + expect(foundUSDC.mgvTestToken).toBe(false) + expect(foundUSDC.address).toBe(USDC.address) + expect(foundUSDC.symbol).toBe(USDC.symbol) + expect(foundUSDC.decimals).toBe(USDC.decimals) + + const foundDAI = tokens[2] + expect(foundDAI.mgvTestToken).toBe(false) + expect(foundDAI.address).toBe(DAI.address) + expect(foundDAI.symbol).toBe(DAI.symbol) + expect(foundDAI.decimals).toBe(DAI.decimals) + }) + + it('should get test tokens', async () => { + const tokens = await getTokens(client, { + tokens: [WETH.address] as const, + testTokens: [WETH.address], + }) + + const foundWETH = tokens[0] + expect(foundWETH.mgvTestToken).toBe(true) + expect(foundWETH.address).toBe(WETH.address) + expect(foundWETH.symbol).toBe(WETH.symbol) + expect(foundWETH.decimals).toBe(WETH.decimals) + }) + + it('should have display decimals', async () => { + const tokens = await getTokens(client, { + tokens: [WETH.address, USDC.address, DAI.address] as const, + displayDecimals: { [WETH.symbol]: 1000 }, + priceDisplayDecimals: { [WETH.symbol]: 1000 }, + }) + + const foundWETH = tokens[0] + expect(foundWETH.displayDecimals).toBe(1000) + expect(foundWETH.priceDisplayDecimals).toBe(1000) + }) + + it('should fail on unknown token', async () => { + try { + await getTokens(client, { tokens: [zeroAddress] as const }) + } catch (error) { + expect(error).toBeInstanceOf(GetTokenInfoError) + const typedError = error as GetTokenInfoError + expect(typedError.shortMessage).toBe( + `No decimals found for token ${zeroAddress}`, + ) + expect(typedError.cause).toBeInstanceOf(ContractFunctionExecutionError) + const typedCause = typedError.cause as ContractFunctionExecutionError + expect(typedCause.contractAddress).toBe(zeroAddress) + } + }) +}) diff --git a/src/actions/tokens.ts b/src/actions/tokens.ts new file mode 100644 index 0000000..3ed2b3b --- /dev/null +++ b/src/actions/tokens.ts @@ -0,0 +1,111 @@ +import { + type Address, + BaseError, + type Client, + type MulticallParameters, + parseAbi, +} from 'viem' +import { multicall } from 'viem/actions' +import { type Token, buildToken } from '../addresses/index.js' +import { getAction } from '../utils/getAction.js' + +export type GetTokensParams = + { + tokens: T + displayDecimals?: Record + priceDisplayDecimals?: Record + testTokens?: T[number][] + } & Omit + +export type GetTokensResult = + { + [K in keyof T]: Token + } + +const tokenABI = parseAbi([ + 'function decimals() external view returns (uint8)', + 'function symbol() external view returns (string)', +]) + +export class GetTokenInfoError extends BaseError { + constructor( + tokenAddress: Address, + param: 'decimals' | 'symbol', + cause: Error, + ) { + super(`No ${param} found for token ${tokenAddress}`, { cause }) + } +} + +export async function getTokens< + T extends readonly Address[] = readonly Address[], +>( + client: Client, + { + tokens, + displayDecimals = {}, + priceDisplayDecimals = {}, + testTokens = [], + }: GetTokensParams, +): Promise> { + const tokenInfos = await getAction( + client, + multicall, + 'multicall', + )({ + contracts: tokens.flatMap( + (token) => + [ + { + address: token, + abi: tokenABI, + functionName: 'decimals', + }, + { + address: token, + abi: tokenABI, + functionName: 'symbol', + }, + ] as const, + ), + }) + + return tokens.map((token: T[number], i) => { + const decimalsResult = tokenInfos[i * 2] + const symbolResult = tokenInfos[i * 2 + 1] + + if (!decimalsResult || !symbolResult) + throw new Error( + 'Error while getting token infos, This is a bug, please report at https://github.com/mangrovedao/mgv/issues', + ) + + if (decimalsResult.status === 'failure') + throw new GetTokenInfoError(token, 'decimals', decimalsResult.error) + if (symbolResult.status === 'failure') + throw new GetTokenInfoError(token, 'symbol', symbolResult.error) + + const decimals = decimalsResult.result + const symbol = symbolResult.result + + if (typeof symbol !== 'string') + throw new Error( + 'Error while getting token infos, This is a bug, please report at https://github.com/mangrovedao/mgv/issues', + ) + if (typeof decimals !== 'number') + throw new Error( + 'Error while getting token infos, This is a bug, please report at https://github.com/mangrovedao/mgv/issues', + ) + + const display = displayDecimals[symbol] + const priceDisplay = priceDisplayDecimals[symbol] + + return buildToken({ + address: token, + symbol, + decimals, + displayDecimals: display, + priceDisplayDecimals: priceDisplay, + mgvTestToken: testTokens.includes(token), + }) + }) as GetTokensResult +} diff --git a/src/builder/index.ts b/src/builder/index.ts index 0186b31..13345cf 100644 --- a/src/builder/index.ts +++ b/src/builder/index.ts @@ -112,3 +112,7 @@ export { deployRouterParams, bindParams, } from './smart-router.js' + +// reader + +export { getOpenMarketsParams, mgvReaderABI } from './reader.js' diff --git a/src/builder/reader.ts b/src/builder/reader.ts new file mode 100644 index 0000000..6793069 --- /dev/null +++ b/src/builder/reader.ts @@ -0,0 +1,16 @@ +import { type ContractFunctionParameters, parseAbi } from 'viem' + +export const mgvReaderABI = parseAbi([ + 'struct Market { address tkn0; address tkn1; uint tickSpacing;}', + 'struct MarketConfig {LocalUnpacked config01;LocalUnpacked config10;}', + 'struct LocalUnpacked { bool active; uint fee; uint density; uint binPosInLeaf; uint level3; uint level2; uint level1; uint root; uint kilo_offer_gasbase; bool lock; uint last;}', + 'function openMarkets() external view returns (Market[] memory, MarketConfig[] memory)', +]) + +export const getOpenMarketsParams = { + abi: mgvReaderABI, + functionName: 'openMarkets', +} satisfies Omit< + ContractFunctionParameters, + 'address' +> diff --git a/src/bundle/public/general-actions.ts b/src/bundle/public/general-actions.ts index 418acf7..b3d1f23 100644 --- a/src/bundle/public/general-actions.ts +++ b/src/bundle/public/general-actions.ts @@ -1,9 +1,14 @@ -import type { Client } from 'viem' +import type { Address, Client } from 'viem' import { type GetBalanceResult, type GetBalancesArgs, getBalances, } from '../../actions/balances.js' +import { + type GetTokensParams, + type GetTokensResult, + getTokens, +} from '../../actions/tokens.js' import type { Logic } from '../../addresses/logics/utils.js' export type GeneralActions = { @@ -17,8 +22,35 @@ export type GeneralActions = { getBalances: ( args: GetBalancesArgs, ) => Promise> + + /** + * + * @param args.tokens the tokens to get info for + * @param args.displayDecimals the decimals to display for each token + * @param args.priceDisplayDecimals the decimals to display for each token's price + * @param args.testTokens the tokens that are mangrove test tokens + * @returns all tokens and their info + * @example + * ```ts + * const tokens = await client.getTokens({ + * tokens: [WETHaddress, USDCaddress], + * displayDecimals: { WETH: 4, USDC: 2 }, // optional + * priceDisplayDecimals: { WETH: 2, USDC: 4 }, // optional + * testTokens: [WETH.address] // optional + * }) + * // Returns: + * // { + * // WETH: { address: "0x...", symbol: "WETH", decimals: 18, displayDecimals: 4, priceDisplayDecimals: 2, isTestToken: true }, + * // USDC: { address: "0x...", symbol: "USDC", decimals: 6, displayDecimals: 2, priceDisplayDecimals: 4, isTestToken: false } + * // } + * ``` + */ + getTokens: ( + args: GetTokensParams, + ) => Promise> } export const generalActions = (client: Client): GeneralActions => ({ getBalances: (args) => getBalances(client, args), + getTokens: (args) => getTokens(client, args), }) diff --git a/src/bundle/public/mangrove-actions.ts b/src/bundle/public/mangrove-actions.ts index d6bb63a..b3b44c2 100644 --- a/src/bundle/public/mangrove-actions.ts +++ b/src/bundle/public/mangrove-actions.ts @@ -1,6 +1,10 @@ import type { Address, Client } from 'viem' -import type { GetUserRouterArgs } from '../../actions/index.js' -import { getUserRouter } from '../../actions/index.js' +import type { + GetOpenMarketArgs, + GetOpenMarketResult, + GetUserRouterArgs, +} from '../../actions/index.js' +import { getOpenMarkets, getUserRouter } from '../../actions/index.js' import { type GetOrdersArgs, type GetSingleOrderArgs, @@ -34,6 +38,44 @@ export type MangroveActions = { /** Gets multiple orders details given their markets, sides, and ids */ getOrders: (args: GetOrdersArgs) => Promise + + /** + * Gets all open markets on Mangrove + * @param args.cashnesses The cashness values for each token symbol (e.g. { "WETH": 10, "USDC": 100 }). + * Tokens with higher cashness will be quote tokens, lower cashness will be base tokens. + * For example, in the WETH/USDC market, WETH has higher cashness so it's the quote token. + * @param args.displayDecimals The number of decimals to display for each token symbol + * @param args.priceDisplayDecimals The number of decimals to display for prices in each token symbol + * @param args.testTokens Array of token addresses that are test tokens + * @returns Array of market parameters containing token pairs and tick spacing + * @example + * ```ts + * const markets = await client.getOpenMarkets({ + * cashnesses: { + * "WETH": 10, // Lower cashness -> WETH will be base token + * "USDC": 100 // Higher cashness -> USDC will be quote token + * }, + * displayDecimals: { + * "WETH": 4, + * "USDC": 2 + * }, + * priceDisplayDecimals: { + * "WETH": 2, + * "USDC": 4 + * } + * }); + * // Returns: + * // [ + * // { + * // base: { address: "0x...", symbol: "WETH", decimals: 18, ... }, + * // quote: { address: "0x...", symbol: "USDC", decimals: 6, ... }, + * // tickSpacing: 1n + * // }, + * // ... + * // ] + * ``` + */ + getOpenMarkets: (args: GetOpenMarketArgs) => Promise } export function mangroveActions(actionsParams: MangroveActionsDefaultParams) { @@ -43,5 +85,6 @@ export function mangroveActions(actionsParams: MangroveActionsDefaultParams) { simulateDeployRouter(client, actionsParams, args), getOrder: (args) => getOrder(client, actionsParams, args), getOrders: (args) => getOrders(client, actionsParams, args), + getOpenMarkets: (args) => getOpenMarkets(client, actionsParams, args), }) } From 6e590071830662a5ffe50188ca2a211b6daf9402 Mon Sep 17 00:00:00 2001 From: Maxence Raballand Date: Mon, 25 Nov 2024 17:29:19 +0100 Subject: [PATCH 2/3] chore: update tests from biem anvil to prool --- bun.lockb | Bin 116720 -> 123944 bytes package.json | 10 ++++++---- src/package.json | 2 +- test/globalSetup.ts | 23 +++++++++++++---------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/bun.lockb b/bun.lockb index 37431af1aa1b16d5dcf89a69c672367346ee028a..a9442eeb9619f4fa570da9c79c71b34d07a5a361 100755 GIT binary patch delta 27132 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 e@H4q_UHzS3sku%^Njuaz`lwPm?&y2%=5.0.4", - "viem": "^2.9.1" + "viem": ">=2.9.1" }, "peerDependenciesMeta": { "typescript": { diff --git a/test/globalSetup.ts b/test/globalSetup.ts index e3babf1..b0364e6 100644 --- a/test/globalSetup.ts +++ b/test/globalSetup.ts @@ -1,4 +1,6 @@ -import { createAnvil, startProxy } from '@viem/anvil' +import { createServer, defineInstance } from 'prool' +import { anvil } from 'prool/instances' +// import { createAnvil, startProxy } from '@viem/anvil' import { type Address, parseAbi, parseEther, parseUnits } from 'viem' import { foundry } from 'viem/chains' import type { GlobalSetupContext } from 'vitest/node' @@ -26,12 +28,11 @@ export const multicall: Address = '0xcA11bde05977b3631167028862bE2a173976CA11' export default async function ({ provide }: GlobalSetupContext) { // create an anvil instance - const anvil = createAnvil({ + const globalInstance = anvil({ port: Number(process.env.MAIN_PORT || 8546), - chainId: foundry.id, ipc: '/tmp/anvil.ipc', }) - await anvil.start() + await globalInstance.start() // setting initial balances of accounts for (const account of accounts) { @@ -130,16 +131,18 @@ export default async function ({ provide }: GlobalSetupContext) { }) // starts a proxy pool from there - const shutdown = await startProxy({ - port: Number(process.env.PROXY_PORT || 8545), - options: { + const server = createServer({ + instance: anvil({ forkUrl: '/tmp/anvil.ipc', - }, + }), + port: Number(process.env.PROXY_PORT || 8545), }) + await server.start() + return async () => { - await shutdown() - await anvil.stop() + await server.stop() + await globalInstance.stop() } } From b36456265d027bf5bc21bb6067a042ddc0d2663b Mon Sep 17 00:00:00 2001 From: maxencerb Date: Mon, 25 Nov 2024 16:29:53 +0000 Subject: [PATCH 3/3] chore: format --- bun.lockb | Bin 123944 -> 123968 bytes package.json | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/bun.lockb b/bun.lockb index a9442eeb9619f4fa570da9c79c71b34d07a5a361..d8c5c63e133b35e5544ef82bf0d4821ec14d1c46 100755 GIT binary patch delta 21021 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 delta 20955 zcmeHvd014((*EfKqYR3I0s?}9xGM;#fS@C|MKg-vHn>KF0Y=#u6;v49;x5?6c8g1l zafuq2xZ#RR;vO}cXkum7*m3 z1*lIAAJ^!FbX#&dEVSiYCt5)VqZhKMC4@-xoTP&EpmEkBp5x?Ix*7tc#b&5X=Di9^ zLW_`3G|gHNl#`uTfTog@kT)7Wq0ah&lAC*glKXO!^75@gnfa06$@)#`@%hf$X>x&D zxhE*fOYOChAO%{wNsI%IKB}jpupk&pz5F!O`f>QpU zdE@t9P{+NkWG_m}$gt%XNMC!Z4dq)i$6FCgSI{6?at4$X-099`7F;^rTg@JupPiLz z%di%Kr+(K#jPxnU%z8Z(};h@nwQ2mR=Y^_SG!mRO0F1_my`?-N*)1f z{%}xu*}fH&%KJf%RJP>@DYGG^i7M9x`4j`GN%;l2k|gC>3-fKMMbaIV(^zi~R89C7 zC`>K22Wb^jYFN>E{r|D~BqbAmFm zlamUphc(_&vpKef+VLRx0^wk{YBVR$T2NpswdSQ4W+r6?*-~_Yju1fK_GX}DNlp-k zsKA<+6O@@m!;;rZZO9Sjq|hUnMT54!wW|1SP_nd78`UElz>wT~;Hf=N)Fb)p$oDNp z;uTF`KPa4G9}WsH+b4q}Fzj7G8-Y#_RvVZAN~1d%6kfHDw-s0sds0G(I@;IUsUGR9 z@#UdvJ9Wdi)1pud z`4kfmkWUJY?5NT$8qLTq%ptkv;cEU<$dUX7O~C?NR=cA7oFWPFY=fMX7@@kRA1IA| ziq)DEWX;W>4#y{DNGIFzosPk!bE72*qifFw^#vWE@tr`)VGTjaVLwJm5~9ieA*es- zeo)F^0*dgn7l4uj2ZPdxhilXel;nQuq~?DDO8p!IZAdYjlbv6XoS!cph*b^Kr*~FT zR<Q)L{ne1r${p<8;&_vq!2{MMsP+HbBUyh0liZjh zNz$J!`58(1^q|w1orf-bn6a0w-D}B&x>Dk8|~y>uU^KWz`9rX zKIahrz}1P*syET;a{iHLR|j-9E~+2T*C79w4Wf+~kRmAujvnP^j=Zv;$(ZJ-W;*dIsL{rtay2;{73l<~GvsS1`tH#< zgTj3WE(T?eyb3)I!tQ5?+A=KL49*13iI;)9t#Pp0JHpr=`yqs|UC~W0t;s9{v_UH_z9V?(5tf(MxHvZ!DBrljFZ6i z2Is(I10#&rwKAxIRvX}9O_CTGc(?={mR=}DKG^;%N9unDjs{IujOmC)kJN_?Q8ob_ z4WZh@Tj0XMK{u2=2G>C;W8m6ihNv9MX7@iI6yPN2Aa#Dzx|BA)CXNL9_trj z48x)E^W|O(m(TS{x8zoCA*L5>{CR!C7!oN?012 z=`lwh?GBEl)a7UrxbEPX;-J&uD9n{*#Ng4KrXfwffs{hNI{7QWQ45Nce7ZR=Zefxg zTJXviCgUJ%chzabu=K10NA(m*<1LND{0xYYgIn^-mL@}LOEjh|;H!`#VRbU!05=Sr zMC+Rz-ilYYG8w0}QhQb=p78)UHIQMKe6JNRZf!EQX|2aCt&8Kpso_H|*+v}s&*|St z#i4b5RWb~0L&HeVk%dU9fnSAIKW)RK+M0|l+N$j+3%fB1+#uB~JRWv~qY9V}jUxT2DHzov0(kSF(&4AQf;HXDsDjJ`HO9WSw$70|X2dis2mc-ylCotXAYFJzvwZrFC zKBaZEaTZb(b_fMjc@xv%MV&J|0%w9@ogMKg?ZuyZMa!E)`IB}gxpf$i3Naa{z)vKu zJ{;c-Mx_#Zgt`aiqv;P!$i1r{E|i)JH^ns6fUlTFChwcvP6l zxEq-?5SU4*@HIGEM^!}wG5x49l^Y9=j8lAN+z*Z(^H3l>(g}<@Iceb9qe~K0A6kXr zs+-&aPSuD!@wLXOliCkkcUmDZjnPUPII>U~Hp5nM%45a&Em9Q02F1caB-Qrt_%fz~ z`&D6iO(ZW4HyJM@69Y?DV2LtfBMwJXbv*BSb>dMGCV74*UL0XEY=l9>`ILxgg99`k zs-#9BrRMELYM_$m+(nW`DycN2Y)a}PQb|fG6ca%$U4T@YlJ^KHtCAXqIscN9+W%|H z3!|deC`3vvy@HggK~StDS*V6QJ(gESn+&Ir(M_2O&TupNR-X#SLCBy$gG0k3WZsQe zb~YIn_fU2rouduckm|(`A=RiS!d6M8B85E)@-{1ZU1B>sBB6>!Vg%H}$w;XcP9W7+ zso?s8o|lMJoRaqjQhhl!f`rxx_Bv`+J5p+MCw|SVjmL-DTq06xja5j!h~_#wBB53d z!4y!%CL^V3f|Syn>}2MZ-Ar;^ssN1=)(6lH#W z)tRjZ;5cw3sjOo1+P=y@2ADXs?2!p~3F8 zZzPN3l`oiN5yzjrU^0G=wS)w*JYo(s!;-5`q_Wl##?imwR)9mi(&TK7^{hXS>SHo` z#{XIY+tvhdzls>=fFlbqD+BNt0T;%f21d(I<9YFmCS$h*NeWVx!VJp>N5P`(qMi1G z8w5^?rJVLgrvd6jsiiywP2dp2m_#(sCW9lL@n{COSL3kb2lpK~a*Fau-!*ZVW3AGf zl0+XNr5XUXCK3aD0J@0EfG|2 z46U3f$TS8k6Q%lVH2yiN zdV(?xzTR`a|O6_a|sQfK}E~1pb1EBn!dMNJ% zLl;ph*hLJk=PCJf4?rHM1gN2d09{0>-XV=12BnKA?ADm2yj=PAjxKt2_< z)XIsHd}~lrJQ$RU+R;s;lnl{$q9oS=lu3L^VI5}RhsHJF=f*h^O395~l|o61(JB$G zg?zKd6Rih+q{jb0q-sR`Um7H@jMfzSBiaDv6SVUGPPK^q?}BLc|J3kblrR0unpQVx zMAEL+BTC6KjVDUUsT%*Es59hB=V^jODXN=U-27F;dYR#P8}d(aQLoZ0EoC9ONr01|TPQ2gpf10J?}0-;)?z ze}z&z|7ov5?NIsOdk#3^?>z^F1FpaK9DnaQ{@!!Y+BupQ+&`gz?>Wdh|7ov5o}=>r zFZUc58Gq%xnI{&z@O$UY%z<~hVBt=aT)5#KGq%eW;P!!gbivH<*7!XOPoM0<*S}|G zM*a|-*Ay2%_@bHNb;`RIehQrRT{CmxYcE>(#1a?oamvi<@}yH1-m=t%p9JT|H%+(j zYv5dFm|1=9cG|*c*~M*LxX; zYnqvj=`+nNnJ3MJeJkN}a8~a2GVB9a z__CR$@hWiXufn2PW@h8LvtZvUSOjhy510-6z|EL#W|{mFxQVM_(Ht|&=4EqW-x^p1 zE|-VSg?->&nQLbG{1&)bYhlqmGb`j3^I+d=un61)9y=fQfm=V{%!>F!a7)+0q6KC) ziLYG%`(B4d3(af_Pgn^1!0iTC%2_$=TMzrn&8&>?0GId%?5i-dX*{U{_HBTD;AU{Q zMX(QC;UY78nOA{J-w6A-na$?8+`{JY)40#&0gEkc9xuXuKEH(f0^aHs3tPy`a4+ZA zaj)Q^ODt>=pN%``w{Ty~I|&PWg;(Idgx|qk@Ytmmwv;c!eHnj<`*PlAnT4(3YnQ>A zw_we3GkcXMEQdAVc7t2Z*$P;*9oDQcv$cH33JZIU8&_J`I-Z34>wG`%>$%&j7WM|W z;l6=a;l7c3ud=XBJQw%P{50-w@_^MAwuKkrzLj6XeH(AJ#=_p>Ww>wW*Kyy$L)Ti^ zPCgs=UHlgAZ}U#CS=eq~f%_hQ2lu@^b{)oLAI4>!neFEf!7bg7ae3X$4)C?F!;(r^ zvfj)N@r3oT1l(?LM>u-}mK=a3Zhk5$@;tCEPFYR&QF^d%O(yi~Kt7mw4zF z3%kr`i zn(b!x2~XG#YryRW_bF#PEbJy9iu*0T1NYCkai@iS&XaKeg73%uOYXMI!oK1*+`r~k zxZmd9Z(GjnTbH~3GX>v5apY@$a`N7at$-`uV$d50{rg)=-YdCm+Ai0Bu4E+Yl7j65{_I(} zx$@9EX-aP9IDBI?N0Pq8JF5Cxh0#idT0h}66<&|n$Jny?>W725|DD?MZ4VxNXROlo z_B&37(b%lHXtfHITKwj>PVybUUEh4`>|kiz5?@68O{4tg11CdCJ7_}Lyxga$+$v<( zl7|bJ^GW1VcS9q2@b^*jGmtwzijH~N85#Jhs#MZRYYyiBOeF#OHwAljQ@;{PF3`U< zI172Tl+NQHJ(f{rgrYV)W>CBX7c@|s|6e|X>`_JbHzp!CXLmZYbY)+Nqg`1dt0lZ+ zSPQm7#Ky4tr8BiHZ6i=h(!0QPfG+(-CB3T|ujHsNElFK^b6N+WI`qPlWSjtusB+QE zNh+fkRhKA%tBsaN8^BXYqaA0dt(uT(iHD>Qy?Th%S*+UI@?? ziVV`JE>HoG4ed2K(ue*@LHf}PP};`30sR58AwsK5?=}$?>bt;BTIKr43;;;sC@s$& z>0?OK%h6~p&jV?Cc|})eEzc9_6-tgIb3d*y}z zX%(Xh`XGHAX;OeZL~eJ{Trt(Kvz#KuQAyl zq-5a*2r|j7{s1*fO7+(A0+8+kkOD6v4}Z%4`w;5%~28TdA)m*A(dh zz#r(R<++lkxL9w&y0aFdZFjb`l-?Vz1n5J)!}KyOu7Q5monr~oBtU^315o@>ypY!?h^p?aVQC4H z^d_3(oF)p*%O*e|@CeO60e%La0UrXFfp>v3Kou|_SO_cv<^eN-mw{QpRA3q~9Vi1{ z1o{E-z(AlEIr{}9Xu?r^Q=HOdp~>++6gUrD0Nw*Ae5yccb@BtYfZqyi2G#>_5RktC zSO?H5G8#w%#sJAc3Sb3NfixhUCY}w6vA{SW1IPrjfNUTK$OZC%e4qfJuhotRMgsKj z5sKwFpg#}~Bme_|fxsYOFfatL0Exg*U>GnQ7(uR&f#$J5H^2`5D(D5^9B>%e2P_9x z0IvW`fKXr#FdG;OSb#x5GhjQg4R{mS0MJT7D?=NgEf56s0J;OEAK)f{r9dTc0HD=i z2e1){208=nfe2t3a1hu8bOgcyT9j#FUkxk-7Jx4YDu9VV5zrej1AT!wpg%Bxy6TC< z6;z_-BLFyt^eCVV*b9C?uo@@^CIORy!N3rpA~KBqFUIy}-AZZMZ~(}aG(=Py3&a2+05wLgm4RPyks{=7 za=Rm7035V5@il;&fIr{@I0KaL1Q@k+EzsIPUGfmQm#m>#;sel<;SIO~o&e=jUOm7A zpqWH`1At~yV}R;YUGf-NPEQ8n$>0E>1wgSA2s8zn1LUb73I+J1Hi}W8}_A zfZ~ASgBl_)h5{V`iWiEH&H%}ofOWuH;5C4Tbp@~nSOo}R3Ggbg2&e$c(Z90DB!i9t zMgvK}OTbWoVu2!mAdmpW0~A~oWVG1y0J;NMY?N4g5tM@Q1%NE=15i*>a1HA+ZEDqsh)fh-^s$N70h}^!cLFq3fx(#>}*a~a` z-qI-L?F4oJ)D<;JRY`_;YQ7SnHueEjwjVeEkgmEaBzG7f+2g=5pb9ujE91YA(2b%- zsj+u}e*hl=r-4&|qOY*`WrkAfgR-sz*MJX!4}hz{72ti~GH?mF2)qYe0L}yFfV03E z;1l2m@G6Ka z1)2adQ@4b)NdE%<8Spa@0Q?(x3Pb>PQBGUK+CVLUwv4oOtN|DRN7@+BVy$gH*WM56K}u^ zpm3xpY=bn79)(FOq+0;Z0ooQ()HMR7?a>CLDYQc-B{5Es2lDvoLv+B!C;P z8&>|~UQ0-Zk)Bu`9Tbn+EeTipjr{KPEu{_EfWdYYz6H=j|6%sVqG#Fd*EEcEBpcC7 zh_u#G#FNAc438^pef(rn`mw~t>t(hTISr6=#Zf#cWM1*#gU7hpQ-&TtwyN$LgUtSc z91rB^zs?@~{@td<*{(y;ez1$sT=8PP7)Ug`GUFvr&+Ncfw zX$IS#)1=2osM|rUi+=s7U;Q`Z!`RA?d;PdN2NE4syY*jv-%S}d_>;~@dno-XcI&?@ z-;y2rcE7UxJHM2;`C^|RR(~n8 z5{w9qJk&l2rT$25O)1S?;eViZxT?1PBlV&0gb(=U#h>n?-;iMRj2%S{VH(f8nd))* zxKY>r&XQu(YF9@zngl`pHl?2Bj&a1vwzs{fw1|U5NHE3{li5xEF+AIxblkSE z<1VEHv4d@@sz>}uNKmZhzVV4PzJ+%>Bxrz9SO3ZJ>#W7u$~FGmP!fTXj@b6pSC&wF z*pG{s^f=~Kh7!^pLqEB`*p>jD^`A3;6c|3`df83tmtw0u7NYv1d?c*fUtg5G1WDx= z(CGhCRUe0$`@#YsN!FpQNA*R>07yEzi+LkJJ>A96qd=RvixTAf>c7$c;Mx7pu)90-=(Yf zyx3T2NQt#G?xGGUd&ONe8ia-DCM0RGJAN%j-rM*Qg^T8_Z{0=4ASk7uoe*D=aqz~D zU0Wd0QJtz7&NU>VpA+%m#FU(sAD(+35=x+A3*s!U3}StK_45^+?^yi0u9^1)5?WAx z?I}7BhUP`yV$NVJsnfm1;la=k{59g|`-s{@K;Q8ZF+&jE`dI-#xis1B5wqrj%z8Cc zmlFN7fW4cV-=2Tz*f~WD#d+G~H^7gMe&X&hG!K8?Kyz|EKk=_2P*6WgU|O#QFYP~2 z_hUstWi5juqbyKxyq~}u`@X(s8Y#~iJ0G%v^)Y?5CM}JabcliaicNLziZ|% ztWBDag`9)|(0U91b362N9x5%ZZx=j`s#iU-S`7U4F69Zq;z|+)XRvS@gHXGou5M!1 z7`8_~*iOVGBkJ{kXdIh(^T64@PYbK(g?@5F@i2<*j*~`cE$*wNZ zPpI&1?(^1^aUHR!VG&lIcKTr#QtIIo_sVl`RF@=#h*2q6z*8|5j99=&y9O5~oQ=Bd z&RS!p)0G_}wxmFJ{n!2#?S{>7zPn2&cUFWtc;MORg@~IZu>!m+_}q%)dCl9V6;-#P z*)JD`ieM|OEDseiQwgUbts}eKFGBdIqh?}+h)Tz{U+Ys`NoP~t z|H#{7td050QJus*8^qCZow4XpJ9oo=z}>Un$c4+MIx=iyu(iS`%1&a$Sd5E)Qb)q_ z`}bqkTzXb5;T0vyArY>h?Xjzwps!Ix@#6PI6eqPAq zQOim?tUU8ewS<16$XBt=oE~-WaiY59!zj^q95mCc zE{)qcLW?7K>P$Bgl7ZgzlRi$>j2FFbXC8B8cqA)NW&JFW0j7&>eEr-uRF~A~E=s7b zetO8Nh9Q;j-$@=;Euo(;64Gt?OM7e7m8(m-brJ;X(7y-5#s5t!w;CH*D0sEO4Q z`uQz9`flLZ`O9Zjm-Oi&8fBrbe&Wlif7u&Petj^nme9|HadI=Y*~b>2t1g+^Lu8;>hHn?%>Yz4(2bWji{ZqNs;vN-Xt92OS-ziVJoQySF{aj}OVJL3Cs%_n$qP+g+575={^O0Ykm zDX$*{^I=r$wk7BA>0kZq8A&B#3-tH{O;K0tSKQ2Ht>vTfqIMpOl3OQ;$$6;JAwm7< zezBwbprJQ@sOip3UC6Itk|rT{NDxc%;JkGS;tbLDvUrA?;rfYhjpffqCEUMHAHGAe zmxH2z@Zv)Iyr94QSchIc@i5t3`-5k{biYbNrfrn)YUAyEEPQ|dN<({b5&q{dF7z|c z#s{3AGVjaA_s}{XDC9wGyE7)ihGR{|8ls!(iYt?_4c8xGU$hfLCS&>S93rkwM!xze zyMQxsglh?2;;64?yu^tTY)cQsiYJtb-R+W6Gv-9WU@dMSgU_PS%5oWBLpKcwKl$92goSlgy#8O1!5tb%S&tQWb zFw(+*CMH+lQ8q#hzRv3Hoq2(U$gy-39=ft7Wva)H;fSrQq>Ox=qL!19WXlT59y1nc zRU#`VGbpbxD~L|NQcf!?!r6G@)k_1mkShkXR?- za+G=Q&6vs34dR7zWOkj$414YK*q7}bGp%`PV%+;IP_(q;SS3owoP<7%pUJ8 zJ<7T}sCDigXK#y5FQdcE^XSlg5`yJ3nWs2(lJ!(YqAoB`2h2(lTh0PR=|bkVH}NW~ w<6^XbrUuL`k^LD9HD1(MNhE!a_D+7r1{y;?S4Cn(z~?N&I7?%flE|n31HvV+g#Z8m diff --git a/package.json b/package.json index 4fa99e3..61e00bf 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,6 @@ { "name": "mgv", - "workspaces": [ - "src", - "test" - ], + "workspaces": ["src", "test"], "module": "src/index.ts", "private": true, "type": "module",