├── .gitignore ├── tsconfig.json ├── package.json ├── LICENSE ├── README.md ├── src ├── api.ts ├── types.d.ts └── market-maker.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node16/tsconfig.json", 3 | "compilerOptions": {}, 4 | "include": ["src"], 5 | "exclude": ["node_modules"] 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "market-maker", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "start": "ts-node src/market-maker.ts", 6 | "format": "npx prettier --write ." 7 | }, 8 | "main": "functions/src/index.js", 9 | "dependencies": { 10 | "dotenv": "16.0.1", 11 | "lodash": "4.17.21", 12 | "node-fetch": "2.6.2" 13 | }, 14 | "devDependencies": { 15 | "@tsconfig/node16": "1.0.3", 16 | "@types/lodash": "4.14.182", 17 | "@types/node": "18.6.1", 18 | "@types/node-fetch": "2.6.2", 19 | "ts-node": "10.9.1", 20 | "typescript": "4.7.4" 21 | }, 22 | "prettier": { 23 | "semi": false, 24 | "singleQuote": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Manifold Markets 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A market-making bot for Manifold 2 | 3 | Create limit orders via the Manifold API to provide liquidity, and potentially make a profit! 4 | 5 | The bot works by first computing an exponential moving average and exponential moving variance of the probability. Then it creates limit orders above and below the current market price using these stats. 6 | 7 | If there's volatility in the market, it will fill the pair of limit orders above and below, which will earn you profit (buy low, sell high!). 8 | 9 | In any case, creating open limit orders increases the liquidity in the markets, which is a service to traders. 10 | 11 | 12 | # Run this bot! 13 | 14 | 1. Clone the repository 15 | 2. Locate your Manifold API Key. You can find it in Your profile => Edit => Api key. 16 | 3. Create a `.env` file in the root directory with your api key, replacing the `xxx`'s, and your username. 17 | 18 | ``` 19 | MANIFOLD_API_KEY=xxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 20 | MANIFOLD_USERNAME=YourUsername 21 | ``` 22 | 23 | 4. Install npm packages with `yarn` 24 | 5. Run `yarn start` 25 | 26 | (Be careful! This bot will be placing limit orders with your mana.) 27 | 28 | Feel free to fork and extend this bot with more advanced strategies! 29 | -------------------------------------------------------------------------------- /src/api.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config' 2 | import fetch from 'node-fetch' 3 | import { Bet, FullMarket, LiteMarket } from './types' 4 | 5 | const yourKey = process.env.MANIFOLD_API_KEY 6 | 7 | const API_URL = 'https://api.manifold.markets/v0' 8 | 9 | export const getFullMarket = async (id: string) => { 10 | const market: FullMarket = await fetch(`${API_URL}/market/${id}`).then( 11 | (res) => res.json() 12 | ) 13 | return market 14 | } 15 | 16 | const getMarkets = async (limit = 1000, before?: string) => { 17 | const markets: LiteMarket[] = await fetch( 18 | before 19 | ? `${API_URL}/markets?limit=${limit}&before=${before}` 20 | : `${API_URL}/markets?limit=${limit}` 21 | ).then((res) => res.json()) 22 | 23 | return markets 24 | } 25 | 26 | export const getAllMarkets = async () => { 27 | const allMarkets = [] 28 | let before: string | undefined = undefined 29 | 30 | while (true) { 31 | const markets: LiteMarket[] = await getMarkets(1000, before) 32 | 33 | allMarkets.push(...markets) 34 | before = markets[markets.length - 1].id 35 | console.log('Loaded', allMarkets.length, 'markets', 'before', before) 36 | 37 | if (markets.length < 1000) break 38 | } 39 | 40 | return allMarkets 41 | } 42 | 43 | export const getMarketBySlug = async (slug: string) => { 44 | const market: FullMarket = await fetch(`${API_URL}/slug/${slug}`).then( 45 | (res) => res.json() 46 | ) 47 | return market 48 | } 49 | 50 | const getBets = async ( 51 | username: string, 52 | limit = 1000, 53 | before: string | undefined = undefined 54 | ) => { 55 | const bets: Bet[] = await fetch( 56 | before 57 | ? `${API_URL}/bets?username=${username}&limit=${limit}&before=${before}` 58 | : `${API_URL}/bets?username=${username}&limit=${limit}` 59 | ).then((res) => res.json()) 60 | return bets 61 | } 62 | 63 | export const getAllBets = async (username: string) => { 64 | const allBets: Bet[] = [] 65 | let before: string | undefined = undefined 66 | 67 | while (true) { 68 | const bets: Bet[] = await getBets(username, 1000, before) 69 | if (bets.length === 0) break 70 | allBets.push(...bets) 71 | before = bets[bets.length - 1].id 72 | console.log('Loaded', allBets.length, 'bets', 'before', before) 73 | 74 | if (bets.length < 1000) break 75 | } 76 | 77 | return allBets 78 | } 79 | 80 | export const placeBet = (bet: { 81 | contractId: string 82 | outcome: 'YES' | 'NO' 83 | amount: number 84 | limitProb?: number 85 | }) => { 86 | return fetch(`${API_URL}/bet`, { 87 | method: 'POST', 88 | headers: { 89 | 'Content-Type': 'application/json', 90 | Authorization: `Key ${yourKey}`, 91 | }, 92 | body: JSON.stringify(bet), 93 | }).then((res) => res.json()) 94 | } 95 | 96 | export const cancelBet = (betId: string) => { 97 | return fetch(`${API_URL}/bet/cancel/${betId}`, { 98 | method: 'POST', 99 | headers: { 100 | 'Content-Type': 'application/json', 101 | Authorization: `Key ${yourKey}`, 102 | }, 103 | }).then((res) => res.json()) 104 | } 105 | 106 | export const batchedWaitAll = async ( 107 | createPromises: (() => Promise)[], 108 | batchSize = 10 109 | ) => { 110 | const numBatches = Math.ceil(createPromises.length / batchSize) 111 | const result: T[] = [] 112 | for (let batchIndex = 0; batchIndex < numBatches; batchIndex++) { 113 | const from = batchIndex * batchSize 114 | const to = from + batchSize 115 | 116 | const promises = createPromises.slice(from, to).map((f) => f()) 117 | 118 | const batch = await Promise.all(promises) 119 | result.push(...batch) 120 | } 121 | 122 | return result 123 | } 124 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | // Information about a market, but without bets or comments 2 | export type LiteMarket = { 3 | // Unique identifer for this market 4 | id: string 5 | 6 | // Attributes about the creator 7 | creatorUsername: string 8 | creatorName: string 9 | createdTime: number // milliseconds since epoch 10 | creatorAvatarUrl?: string 11 | 12 | // Market attributes. All times are in milliseconds since epoch 13 | closeTime?: number // Min of creator's chosen date, and resolutionTime 14 | question: string 15 | description: string 16 | 17 | // A list of tags on each market. Any user can add tags to any market. 18 | // This list also includes the predefined categories shown as filters on the home page. 19 | tags: string[] 20 | 21 | // Note: This url always points to https://manifold.markets, regardless of what instance the api is running on. 22 | // This url includes the creator's username, but this doesn't need to be correct when constructing valid URLs. 23 | // i.e. https://manifold.markets/Austin/test-market is the same as https://manifold.markets/foo/test-market 24 | url: string 25 | 26 | outcomeType: string // BINARY, FREE_RESPONSE, or NUMERIC 27 | mechanism: string // dpm-2 or cpmm-1 28 | 29 | probability: number 30 | pool: { outcome: number } // For CPMM markets, the number of shares in the liquidity pool. For DPM markets, the amount of mana invested in each answer. 31 | p?: number // CPMM markets only, probability constant in y^p * n^(1-p) = k 32 | totalLiquidity?: number // CPMM markets only, the amount of mana deposited into the liquidity pool 33 | 34 | volume: number 35 | volume7Days: number 36 | volume24Hours: number 37 | 38 | isResolved: boolean 39 | resolutionTime?: number 40 | resolution?: string 41 | resolutionProbability?: number // Used for BINARY markets resolved to MKT 42 | } 43 | 44 | // A complete market, along with bets, comments, and answers (for free response markets) 45 | export type FullMarket = LiteMarket & { 46 | bets: Bet[] 47 | } 48 | 49 | export type Bet = { 50 | id: string 51 | userId: string 52 | contractId: string 53 | createdTime: number 54 | 55 | amount: number // bet size; negative if SELL bet 56 | loanAmount?: number 57 | outcome: string 58 | shares: number // dynamic parimutuel pool weight or fixed ; negative if SELL bet 59 | 60 | probBefore: number 61 | probAfter: number 62 | 63 | sale?: { 64 | amount: number // amount user makes from sale 65 | betId: string // id of bet being sold 66 | // TODO: add sale time? 67 | } 68 | 69 | fees: Fees 70 | 71 | isSold?: boolean // true if this BUY bet has been sold 72 | isAnte?: boolean 73 | isLiquidityProvision?: boolean 74 | isRedemption?: boolean 75 | } & Partial 76 | 77 | export type NumericBet = Bet & { 78 | value: number 79 | allOutcomeShares: { [outcome: string]: number } 80 | allBetAmounts: { [outcome: string]: number } 81 | } 82 | 83 | // Binary market limit order. 84 | export type LimitBet = Bet & LimitProps 85 | 86 | type LimitProps = { 87 | orderAmount: number // Amount of limit order. 88 | limitProb: number // [0, 1]. Bet to this probability. 89 | isFilled: boolean // Whether all of the bet amount has been filled. 90 | isCancelled: boolean // Whether to prevent any further fills. 91 | // A record of each transaction that partially (or fully) fills the orderAmount. 92 | // I.e. A limit order could be filled by partially matching with several bets. 93 | // Non-limit orders can also be filled by matching with multiple limit orders. 94 | fills: fill[] 95 | } 96 | 97 | export type fill = { 98 | // The id the bet matched against, or null if the bet was matched by the pool. 99 | matchedBetId: string | null 100 | amount: number 101 | shares: number 102 | timestamp: number 103 | // If the fill is a sale, it means the matching bet has shares of the same outcome. 104 | // I.e. -fill.shares === matchedBet.shares 105 | isSale?: boolean 106 | } 107 | -------------------------------------------------------------------------------- /src/market-maker.ts: -------------------------------------------------------------------------------- 1 | import { sortBy, sumBy, uniq } from 'lodash' 2 | import { 3 | batchedWaitAll, 4 | cancelBet, 5 | getAllBets, 6 | getAllMarkets, 7 | getFullMarket, 8 | placeBet, 9 | } from './api' 10 | import type { Bet, FullMarket } from './types' 11 | 12 | const mode = true ? 'ADD_BETS' : 'RESET' 13 | 14 | const main = async () => { 15 | const username = process.env.MANIFOLD_USERNAME 16 | const key = process.env.MANIFOLD_API_KEY 17 | if (!username) { 18 | throw new Error('Please set MANIFOLD_USERNAME variable in .env file.') 19 | } 20 | if (!key) { 21 | throw new Error('Please set MANIFOLD_API_KEY variable in .env file.') 22 | } 23 | const myBets = await getAllBets(username) 24 | const myContractIds = uniq(myBets.map((bet) => bet.contractId)) 25 | 26 | console.log( 27 | 'Got bets', 28 | myBets.length, 29 | 'Contracts bet on', 30 | myContractIds.length 31 | ) 32 | 33 | if (mode === 'RESET') { 34 | await cancelLimitBets(myBets) 35 | await betOnTopMarkets([]) 36 | } else { 37 | // Bet on new markets. 38 | await betOnTopMarkets(myContractIds) 39 | } 40 | } 41 | 42 | const betOnTopMarkets = async (excludeContractIds: string[]) => { 43 | const markets = await getAllMarkets() 44 | console.log('Loaded', markets.length) 45 | 46 | const openBinaryMarkets = markets 47 | .filter((market) => market.outcomeType === 'BINARY') 48 | .filter( 49 | (market) => 50 | !market.isResolved && market.closeTime && market.closeTime > Date.now() 51 | ) 52 | .filter((market) => !excludeContractIds.includes(market.id)) 53 | 54 | console.log('Open binary markets', openBinaryMarkets.length) 55 | 56 | await batchedWaitAll( 57 | openBinaryMarkets.map((market) => async () => { 58 | const fullMarket = await getFullMarket(market.id) 59 | if (fullMarket.bets === undefined) return 60 | const marketBets = fullMarket.bets.filter( 61 | (bet) => bet.limitProb === undefined 62 | ) 63 | 64 | if (marketBets.length >= 10) { 65 | const bets = await placeLimitBets(fullMarket) 66 | if (bets.length) 67 | console.log('Placed orders for', fullMarket.question, ':', bets) 68 | } 69 | }), 70 | 2 71 | ) 72 | } 73 | 74 | const cancelLimitBets = async (bets: Bet[]) => { 75 | const openBets = bets.filter( 76 | (bet) => bet.limitProb !== undefined && !bet.isCancelled && !bet.isFilled 77 | ) 78 | 79 | await Promise.all(openBets.map((bet) => cancelBet(bet.id))) 80 | } 81 | 82 | const placeLimitBets = async (market: FullMarket) => { 83 | const { bets, id } = market 84 | 85 | const sortedBets = sortBy(bets, (bet) => bet.createdTime) 86 | const marketBets = sortedBets.filter((bet) => bet.limitProb === undefined) 87 | 88 | const vol = sumBy(marketBets, (bet) => Math.abs(bet.amount)) 89 | const logVol = Math.log(vol) 90 | const amount = 10 + logVol * 15 91 | 92 | const ranges = computeRanges(marketBets) 93 | const limitBets = ranges 94 | .map((range, i) => rangeToBets(range, amount * (i + 1))) 95 | .flat() 96 | 97 | await Promise.all( 98 | limitBets.map((bet) => placeBet({ ...bet, contractId: id })) 99 | ) 100 | return limitBets 101 | } 102 | 103 | const computeRanges = (marketBets: Bet[]) => { 104 | const vol = sumBy(marketBets, (bet) => Math.abs(bet.amount)) 105 | const logVol = Math.log(vol) 106 | const updateFactor = 0.1 + (0.2 * Math.max(0, 12 - logVol)) / 12 107 | 108 | if (marketBets.length <= 1) return [] 109 | 110 | const lastPrice = marketBets[marketBets.length - 1].probAfter 111 | const prices = marketBets.map((bet) => ({ 112 | price: lastPrice - bet.probAfter, 113 | amount: bet.amount, 114 | })) 115 | const { average, std } = movingAverageExp(prices, updateFactor) 116 | const downSpread = 2 * lastPrice * std 117 | const upSpread = 2 * std * (1 - lastPrice) 118 | const [low, high] = [ 119 | lastPrice - downSpread + Math.min(average, 0), 120 | lastPrice + upSpread + Math.max(0, average), 121 | ] 122 | const [low2, high2] = [low - std, high + std] 123 | 124 | return [[low, high] as [number, number], [low2, high2] as [number, number]] 125 | } 126 | 127 | const rangeToBets = (range: [number, number], amount: number) => { 128 | const [low, high] = range 129 | if ( 130 | isNaN(low) || 131 | isNaN(high) || 132 | low <= 0.001 || 133 | high <= 0.001 || 134 | low >= 0.999 || 135 | high >= 0.999 136 | ) 137 | return [] 138 | 139 | const shares = Math.min(amount / low, amount / (1 - high)) 140 | const yesAmount = shares * low 141 | const noAmount = shares * (1 - high) 142 | 143 | return [ 144 | { 145 | outcome: 'YES' as const, 146 | amount: yesAmount, 147 | limitProb: low, 148 | }, 149 | { 150 | outcome: 'NO' as const, 151 | amount: noAmount, 152 | limitProb: high, 153 | }, 154 | ] 155 | } 156 | 157 | const movingAverageExp = ( 158 | values: { price: number; amount: number }[], 159 | updateFactor = 0.2 160 | ) => { 161 | let average = values[0].price 162 | let variance = 0 163 | 164 | for (let i = 0; i < values.length; i++) { 165 | const { price, amount } = values[i] 166 | // Moving average where time is the amount bet. 167 | // I.e. amount / 100 is one unit of time. 168 | const a = 1 - (1 - updateFactor) ** (Math.abs(amount) / 100) 169 | 170 | average = average * (1 - a) + price * a 171 | variance = variance * (1 - a) + (price - average) ** 2 * a 172 | } 173 | const std = Math.sqrt(variance) 174 | return { average, variance, std } 175 | } 176 | 177 | if (require.main === module) { 178 | console.log('hello world!') 179 | main() 180 | } 181 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@cspotcode/source-map-support@^0.8.0": 6 | version "0.8.1" 7 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" 8 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== 9 | dependencies: 10 | "@jridgewell/trace-mapping" "0.3.9" 11 | 12 | "@jridgewell/resolve-uri@^3.0.3": 13 | version "3.1.0" 14 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" 15 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== 16 | 17 | "@jridgewell/sourcemap-codec@^1.4.10": 18 | version "1.4.14" 19 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" 20 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== 21 | 22 | "@jridgewell/trace-mapping@0.3.9": 23 | version "0.3.9" 24 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" 25 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== 26 | dependencies: 27 | "@jridgewell/resolve-uri" "^3.0.3" 28 | "@jridgewell/sourcemap-codec" "^1.4.10" 29 | 30 | "@tsconfig/node10@^1.0.7": 31 | version "1.0.9" 32 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" 33 | integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== 34 | 35 | "@tsconfig/node12@^1.0.7": 36 | version "1.0.11" 37 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" 38 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== 39 | 40 | "@tsconfig/node14@^1.0.0": 41 | version "1.0.3" 42 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" 43 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== 44 | 45 | "@tsconfig/node16@1.0.3", "@tsconfig/node16@^1.0.2": 46 | version "1.0.3" 47 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" 48 | integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== 49 | 50 | "@types/lodash@^4.14.182": 51 | version "4.14.182" 52 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" 53 | integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== 54 | 55 | "@types/node-fetch@2.6.2": 56 | version "2.6.2" 57 | resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" 58 | integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== 59 | dependencies: 60 | "@types/node" "*" 61 | form-data "^3.0.0" 62 | 63 | "@types/node@*", "@types/node@18.6.1": 64 | version "18.6.1" 65 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.1.tgz#828e4785ccca13f44e2fb6852ae0ef11e3e20ba5" 66 | integrity sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg== 67 | 68 | acorn-walk@^8.1.1: 69 | version "8.2.0" 70 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" 71 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== 72 | 73 | acorn@^8.4.1: 74 | version "8.8.0" 75 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" 76 | integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== 77 | 78 | arg@^4.1.0: 79 | version "4.1.3" 80 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 81 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 82 | 83 | asynckit@^0.4.0: 84 | version "0.4.0" 85 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 86 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 87 | 88 | combined-stream@^1.0.8: 89 | version "1.0.8" 90 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 91 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 92 | dependencies: 93 | delayed-stream "~1.0.0" 94 | 95 | create-require@^1.1.0: 96 | version "1.1.1" 97 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 98 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 99 | 100 | delayed-stream@~1.0.0: 101 | version "1.0.0" 102 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 103 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 104 | 105 | diff@^4.0.1: 106 | version "4.0.2" 107 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 108 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 109 | 110 | dotenv@16.0.1: 111 | version "16.0.1" 112 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" 113 | integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== 114 | 115 | form-data@^3.0.0: 116 | version "3.0.1" 117 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" 118 | integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== 119 | dependencies: 120 | asynckit "^0.4.0" 121 | combined-stream "^1.0.8" 122 | mime-types "^2.1.12" 123 | 124 | lodash@4.17.21: 125 | version "4.17.21" 126 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 127 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 128 | 129 | make-error@^1.1.1: 130 | version "1.3.6" 131 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 132 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 133 | 134 | mime-db@1.52.0: 135 | version "1.52.0" 136 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 137 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 138 | 139 | mime-types@^2.1.12: 140 | version "2.1.35" 141 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 142 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 143 | dependencies: 144 | mime-db "1.52.0" 145 | 146 | node-fetch@2.6.2: 147 | version "2.6.2" 148 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" 149 | integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== 150 | 151 | ts-node@10.9.1: 152 | version "10.9.1" 153 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" 154 | integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== 155 | dependencies: 156 | "@cspotcode/source-map-support" "^0.8.0" 157 | "@tsconfig/node10" "^1.0.7" 158 | "@tsconfig/node12" "^1.0.7" 159 | "@tsconfig/node14" "^1.0.0" 160 | "@tsconfig/node16" "^1.0.2" 161 | acorn "^8.4.1" 162 | acorn-walk "^8.1.1" 163 | arg "^4.1.0" 164 | create-require "^1.1.0" 165 | diff "^4.0.1" 166 | make-error "^1.1.1" 167 | v8-compile-cache-lib "^3.0.1" 168 | yn "3.1.1" 169 | 170 | typescript@4.7.4: 171 | version "4.7.4" 172 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" 173 | integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== 174 | 175 | v8-compile-cache-lib@^3.0.1: 176 | version "3.0.1" 177 | resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" 178 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== 179 | 180 | yn@3.1.1: 181 | version "3.1.1" 182 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 183 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 184 | --------------------------------------------------------------------------------