From 4fda7e3cc6b87e574e4aee16741b36818fa92fea Mon Sep 17 00:00:00 2001 From: Michael Wang <44713145+mzywang@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:38:26 -0400 Subject: [PATCH] split pool event handlers (#213) * split core handlers * remove yarn codegen from CI * update export * fix(lint): auto-fix [ci] --------- Co-authored-by: mzywang --- .github/workflows/CI.yml | 3 - package.json | 5 +- src/mappings/core.ts | 459 -------------------------------- src/mappings/pool/burn.ts | 118 ++++++++ src/mappings/pool/index.ts | 6 + src/mappings/pool/initialize.ts | 34 +++ src/mappings/pool/mint.ts | 135 ++++++++++ src/mappings/pool/swap.ts | 204 ++++++++++++++ subgraph.yaml | 5 +- yarn.lock | 192 ++++++++++++- 10 files changed, 687 insertions(+), 474 deletions(-) delete mode 100644 src/mappings/core.ts create mode 100644 src/mappings/pool/burn.ts create mode 100644 src/mappings/pool/index.ts create mode 100644 src/mappings/pool/initialize.ts create mode 100644 src/mappings/pool/mint.ts create mode 100644 src/mappings/pool/swap.ts diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3457a330..9e4a998e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -82,8 +82,5 @@ jobs: - name: Install dependencies run: yarn install - - name: Run GraphQL codegen - run: yarn codegen - - name: Build project run: yarn build diff --git a/package.json b/package.json index 96754fd6..975967ca 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,10 @@ "license": "GPL-3.0-or-later", "scripts": { "lint": "eslint . --ext .ts --fix", + "build": "run-s codegen && graph build", + "buildonly": "graph build", + "deploy:alchemy": "graph deploy --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz", "codegen": "graph codegen --output-dir src/types/", - "build": "graph build", "create-local": "graph create ianlapham/uniswap-v3 --node http://127.0.0.1:8020", "deploy-local": "graph deploy ianlapham/uniswap-v3 --debug --ipfs http://localhost:5001 --node http://127.0.0.1:8020", "deploy": "graph deploy ianlapham/uniswap-v3-subgraph --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/ --debug", @@ -22,6 +24,7 @@ "@uniswap/eslint-config": "^1.2.0", "eslint": "^8.57.0", "eslint-config-prettier": "^6.1.0", + "npm-run-all": "^4.1.5", "prettier": "^1.18.2", "typescript": "^3.5.2" } diff --git a/src/mappings/core.ts b/src/mappings/core.ts deleted file mode 100644 index 8943e5e6..00000000 --- a/src/mappings/core.ts +++ /dev/null @@ -1,459 +0,0 @@ -import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' - -import { Bundle, Burn, Factory, Mint, Pool, Swap, Tick, Token } from '../types/schema' -import { Burn as BurnEvent, Initialize, Mint as MintEvent, Swap as SwapEvent } from '../types/templates/Pool/Pool' -import { convertTokenToDecimal, loadTransaction, safeDiv } from '../utils' -import { FACTORY_ADDRESS, ONE_BI, ZERO_BD } from '../utils/constants' -import { - updatePoolDayData, - updatePoolHourData, - updateTokenDayData, - updateTokenHourData, - updateUniswapDayData, -} from '../utils/intervalUpdates' -import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToTokenPrices } from '../utils/pricing' -import { createTick } from '../utils/tick' - -export function handleInitialize(event: Initialize): void { - // update pool sqrt price and tick - const pool = Pool.load(event.address.toHexString())! - pool.sqrtPrice = event.params.sqrtPriceX96 - pool.tick = BigInt.fromI32(event.params.tick) - pool.save() - - // update token prices - const token0 = Token.load(pool.token0) - const token1 = Token.load(pool.token1) - - // update ETH price now that prices could have changed - const bundle = Bundle.load('1')! - bundle.ethPriceUSD = getEthPriceInUSD() - bundle.save() - - updatePoolDayData(event) - updatePoolHourData(event) - - // update token prices - if (token0 && token1) { - token0.derivedETH = findEthPerToken(token0 as Token) - token1.derivedETH = findEthPerToken(token1 as Token) - token0.save() - token1.save() - } -} - -export function handleMint(event: MintEvent): void { - const bundle = Bundle.load('1')! - const poolAddress = event.address.toHexString() - const pool = Pool.load(poolAddress)! - const factory = Factory.load(FACTORY_ADDRESS)! - - const token0 = Token.load(pool.token0) - const token1 = Token.load(pool.token1) - - if (token0 && token1) { - const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - - const amountUSD = amount0 - .times(token0.derivedETH.times(bundle.ethPriceUSD)) - .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) - - // reset tvl aggregates until new amounts calculated - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) - - // update globals - factory.txCount = factory.txCount.plus(ONE_BI) - - // update token0 data - token0.txCount = token0.txCount.plus(ONE_BI) - token0.totalValueLocked = token0.totalValueLocked.plus(amount0) - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) - - // update token1 data - token1.txCount = token1.txCount.plus(ONE_BI) - token1.totalValueLocked = token1.totalValueLocked.plus(amount1) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) - - // pool data - pool.txCount = pool.txCount.plus(ONE_BI) - - // Pools liquidity tracks the currently active liquidity given pools current tick. - // We only want to update it on mint if the new position includes the current tick. - if ( - pool.tick !== null && - BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && - BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) - ) { - pool.liquidity = pool.liquidity.plus(event.params.amount) - } - - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - // reset aggregates with new amounts - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - const transaction = loadTransaction(event) - const mint = new Mint(transaction.id.toString() + '#' + pool.txCount.toString()) - mint.transaction = transaction.id - mint.timestamp = transaction.timestamp - mint.pool = pool.id - mint.token0 = pool.token0 - mint.token1 = pool.token1 - mint.owner = event.params.owner - mint.sender = event.params.sender - mint.origin = event.transaction.from - mint.amount = event.params.amount - mint.amount0 = amount0 - mint.amount1 = amount1 - mint.amountUSD = amountUSD - mint.tickLower = BigInt.fromI32(event.params.tickLower) - mint.tickUpper = BigInt.fromI32(event.params.tickUpper) - mint.logIndex = event.logIndex - - // tick entities - const lowerTickIdx = event.params.tickLower - const upperTickIdx = event.params.tickUpper - - const lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString() - const upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString() - - let lowerTick = Tick.load(lowerTickId) - let upperTick = Tick.load(upperTickId) - - if (lowerTick === null) { - lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event) - } - - if (upperTick === null) { - upperTick = createTick(upperTickId, upperTickIdx, pool.id, event) - } - - const amount = event.params.amount - lowerTick.liquidityGross = lowerTick.liquidityGross.plus(amount) - lowerTick.liquidityNet = lowerTick.liquidityNet.plus(amount) - upperTick.liquidityGross = upperTick.liquidityGross.plus(amount) - upperTick.liquidityNet = upperTick.liquidityNet.minus(amount) - - lowerTick.save() - upperTick.save() - - // TODO: Update Tick's volume, fees, and liquidity provider count. Computing these on the tick - // level requires reimplementing some of the swapping code from v3-core. - - updateUniswapDayData(event) - updatePoolDayData(event) - updatePoolHourData(event) - updateTokenDayData(token0 as Token, event) - updateTokenDayData(token1 as Token, event) - updateTokenHourData(token0 as Token, event) - updateTokenHourData(token1 as Token, event) - - token0.save() - token1.save() - pool.save() - factory.save() - mint.save() - } -} - -export function handleBurn(event: BurnEvent): void { - const bundle = Bundle.load('1')! - const poolAddress = event.address.toHexString() - const pool = Pool.load(poolAddress)! - const factory = Factory.load(FACTORY_ADDRESS)! - - const token0 = Token.load(pool.token0) - const token1 = Token.load(pool.token1) - - if (token0 && token1) { - const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - - const amountUSD = amount0 - .times(token0.derivedETH.times(bundle.ethPriceUSD)) - .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) - - // reset tvl aggregates until new amounts calculated - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) - - // update globals - factory.txCount = factory.txCount.plus(ONE_BI) - - // update token0 data - token0.txCount = token0.txCount.plus(ONE_BI) - token0.totalValueLocked = token0.totalValueLocked.minus(amount0) - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) - - // update token1 data - token1.txCount = token1.txCount.plus(ONE_BI) - token1.totalValueLocked = token1.totalValueLocked.minus(amount1) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) - - // pool data - pool.txCount = pool.txCount.plus(ONE_BI) - // Pools liquidity tracks the currently active liquidity given pools current tick. - // We only want to update it on burn if the position being burnt includes the current tick. - if ( - pool.tick !== null && - BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && - BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) - ) { - pool.liquidity = pool.liquidity.minus(event.params.amount) - } - - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.minus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.minus(amount1) - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - // reset aggregates with new amounts - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - // burn entity - const transaction = loadTransaction(event) - const burn = new Burn(transaction.id + '#' + pool.txCount.toString()) - burn.transaction = transaction.id - burn.timestamp = transaction.timestamp - burn.pool = pool.id - burn.token0 = pool.token0 - burn.token1 = pool.token1 - burn.owner = event.params.owner - burn.origin = event.transaction.from - burn.amount = event.params.amount - burn.amount0 = amount0 - burn.amount1 = amount1 - burn.amountUSD = amountUSD - burn.tickLower = BigInt.fromI32(event.params.tickLower) - burn.tickUpper = BigInt.fromI32(event.params.tickUpper) - burn.logIndex = event.logIndex - - // tick entities - const lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString() - const upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString() - const lowerTick = Tick.load(lowerTickId) - const upperTick = Tick.load(upperTickId) - if (lowerTick && upperTick) { - const amount = event.params.amount - lowerTick.liquidityGross = lowerTick.liquidityGross.minus(amount) - lowerTick.liquidityNet = lowerTick.liquidityNet.minus(amount) - upperTick.liquidityGross = upperTick.liquidityGross.minus(amount) - upperTick.liquidityNet = upperTick.liquidityNet.plus(amount) - - lowerTick.save() - upperTick.save() - } - updateUniswapDayData(event) - updatePoolDayData(event) - updatePoolHourData(event) - updateTokenDayData(token0 as Token, event) - updateTokenDayData(token1 as Token, event) - updateTokenHourData(token0 as Token, event) - updateTokenHourData(token1 as Token, event) - - token0.save() - token1.save() - pool.save() - factory.save() - burn.save() - } -} - -export function handleSwap(event: SwapEvent): void { - const bundle = Bundle.load('1')! - const factory = Factory.load(FACTORY_ADDRESS)! - const pool = Pool.load(event.address.toHexString())! - - // hot fix for bad pricing - if (pool.id == '0x9663f2ca0454accad3e094448ea6f77443880454') { - return - } - - const token0 = Token.load(pool.token0) - const token1 = Token.load(pool.token1) - - if (token0 && token1) { - // amounts - 0/1 are token deltas: can be positive or negative - const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - - // need absolute amounts for volume - let amount0Abs = amount0 - if (amount0.lt(ZERO_BD)) { - amount0Abs = amount0.times(BigDecimal.fromString('-1')) - } - let amount1Abs = amount1 - if (amount1.lt(ZERO_BD)) { - amount1Abs = amount1.times(BigDecimal.fromString('-1')) - } - - const amount0ETH = amount0Abs.times(token0.derivedETH) - const amount1ETH = amount1Abs.times(token1.derivedETH) - const amount0USD = amount0ETH.times(bundle.ethPriceUSD) - const amount1USD = amount1ETH.times(bundle.ethPriceUSD) - - // get amount that should be tracked only - div 2 because cant count both input and output as volume - const amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div( - BigDecimal.fromString('2') - ) - const amountTotalETHTracked = safeDiv(amountTotalUSDTracked, bundle.ethPriceUSD) - const amountTotalUSDUntracked = amount0USD.plus(amount1USD).div(BigDecimal.fromString('2')) - - const feesETH = amountTotalETHTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) - const feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) - - // global updates - factory.txCount = factory.txCount.plus(ONE_BI) - factory.totalVolumeETH = factory.totalVolumeETH.plus(amountTotalETHTracked) - factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked) - factory.untrackedVolumeUSD = factory.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - factory.totalFeesETH = factory.totalFeesETH.plus(feesETH) - factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD) - - // reset aggregate tvl before individual pool tvl updates - const currentPoolTvlETH = pool.totalValueLockedETH - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(currentPoolTvlETH) - - // pool volume - pool.volumeToken0 = pool.volumeToken0.plus(amount0Abs) - pool.volumeToken1 = pool.volumeToken1.plus(amount1Abs) - pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked) - pool.untrackedVolumeUSD = pool.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - pool.feesUSD = pool.feesUSD.plus(feesUSD) - pool.txCount = pool.txCount.plus(ONE_BI) - - // Update the pool with the new active liquidity, price, and tick. - pool.liquidity = event.params.liquidity - pool.tick = BigInt.fromI32(event.params.tick as i32) - pool.sqrtPrice = event.params.sqrtPriceX96 - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) - - // update token0 data - token0.volume = token0.volume.plus(amount0Abs) - token0.totalValueLocked = token0.totalValueLocked.plus(amount0) - token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked) - token0.untrackedVolumeUSD = token0.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - token0.feesUSD = token0.feesUSD.plus(feesUSD) - token0.txCount = token0.txCount.plus(ONE_BI) - - // update token1 data - token1.volume = token1.volume.plus(amount1Abs) - token1.totalValueLocked = token1.totalValueLocked.plus(amount1) - token1.volumeUSD = token1.volumeUSD.plus(amountTotalUSDTracked) - token1.untrackedVolumeUSD = token1.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - token1.feesUSD = token1.feesUSD.plus(feesUSD) - token1.txCount = token1.txCount.plus(ONE_BI) - - // updated pool ratess - const prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token) - pool.token0Price = prices[0] - pool.token1Price = prices[1] - pool.save() - - // update USD pricing - bundle.ethPriceUSD = getEthPriceInUSD() - bundle.save() - token0.derivedETH = findEthPerToken(token0 as Token) - token1.derivedETH = findEthPerToken(token1 as Token) - - /** - * Things afffected by new USD rates - */ - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH).times(bundle.ethPriceUSD) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD) - - // create Swap event - const transaction = loadTransaction(event) - const swap = new Swap(transaction.id + '#' + pool.txCount.toString()) - swap.transaction = transaction.id - swap.timestamp = transaction.timestamp - swap.pool = pool.id - swap.token0 = pool.token0 - swap.token1 = pool.token1 - swap.sender = event.params.sender - swap.origin = event.transaction.from - swap.recipient = event.params.recipient - swap.amount0 = amount0 - swap.amount1 = amount1 - swap.amountUSD = amountTotalUSDTracked - swap.tick = BigInt.fromI32(event.params.tick as i32) - swap.sqrtPriceX96 = event.params.sqrtPriceX96 - swap.logIndex = event.logIndex - - // interval data - const uniswapDayData = updateUniswapDayData(event) - const poolDayData = updatePoolDayData(event) - const poolHourData = updatePoolHourData(event) - const token0DayData = updateTokenDayData(token0 as Token, event) - const token1DayData = updateTokenDayData(token1 as Token, event) - const token0HourData = updateTokenHourData(token0 as Token, event) - const token1HourData = updateTokenHourData(token1 as Token, event) - - // update volume metrics - uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked) - uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked) - uniswapDayData.feesUSD = uniswapDayData.feesUSD.plus(feesUSD) - - poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked) - poolDayData.volumeToken0 = poolDayData.volumeToken0.plus(amount0Abs) - poolDayData.volumeToken1 = poolDayData.volumeToken1.plus(amount1Abs) - poolDayData.feesUSD = poolDayData.feesUSD.plus(feesUSD) - - poolHourData.volumeUSD = poolHourData.volumeUSD.plus(amountTotalUSDTracked) - poolHourData.volumeToken0 = poolHourData.volumeToken0.plus(amount0Abs) - poolHourData.volumeToken1 = poolHourData.volumeToken1.plus(amount1Abs) - poolHourData.feesUSD = poolHourData.feesUSD.plus(feesUSD) - - token0DayData.volume = token0DayData.volume.plus(amount0Abs) - token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked) - token0DayData.untrackedVolumeUSD = token0DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token0DayData.feesUSD = token0DayData.feesUSD.plus(feesUSD) - - token0HourData.volume = token0HourData.volume.plus(amount0Abs) - token0HourData.volumeUSD = token0HourData.volumeUSD.plus(amountTotalUSDTracked) - token0HourData.untrackedVolumeUSD = token0HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token0HourData.feesUSD = token0HourData.feesUSD.plus(feesUSD) - - token1DayData.volume = token1DayData.volume.plus(amount1Abs) - token1DayData.volumeUSD = token1DayData.volumeUSD.plus(amountTotalUSDTracked) - token1DayData.untrackedVolumeUSD = token1DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token1DayData.feesUSD = token1DayData.feesUSD.plus(feesUSD) - - token1HourData.volume = token1HourData.volume.plus(amount1Abs) - token1HourData.volumeUSD = token1HourData.volumeUSD.plus(amountTotalUSDTracked) - token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD) - - swap.save() - token0DayData.save() - token1DayData.save() - uniswapDayData.save() - poolDayData.save() - poolHourData.save() - token0HourData.save() - token1HourData.save() - poolHourData.save() - factory.save() - pool.save() - token0.save() - token1.save() - } -} diff --git a/src/mappings/pool/burn.ts b/src/mappings/pool/burn.ts new file mode 100644 index 00000000..ccd2b391 --- /dev/null +++ b/src/mappings/pool/burn.ts @@ -0,0 +1,118 @@ +import { BigInt } from '@graphprotocol/graph-ts' + +import { Bundle, Burn, Factory, Pool, Tick, Token } from '../../types/schema' +import { Burn as BurnEvent } from '../../types/templates/Pool/Pool' +import { convertTokenToDecimal, loadTransaction } from '../../utils' +import { FACTORY_ADDRESS, ONE_BI } from '../../utils/constants' +import { + updatePoolDayData, + updatePoolHourData, + updateTokenDayData, + updateTokenHourData, + updateUniswapDayData, +} from '../../utils/intervalUpdates' + +export function handleBurn(event: BurnEvent): void { + const bundle = Bundle.load('1')! + const poolAddress = event.address.toHexString() + const pool = Pool.load(poolAddress)! + const factory = Factory.load(FACTORY_ADDRESS)! + + const token0 = Token.load(pool.token0) + const token1 = Token.load(pool.token1) + + if (token0 && token1) { + const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + + const amountUSD = amount0 + .times(token0.derivedETH.times(bundle.ethPriceUSD)) + .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) + + // reset tvl aggregates until new amounts calculated + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) + + // update globals + factory.txCount = factory.txCount.plus(ONE_BI) + + // update token0 data + token0.txCount = token0.txCount.plus(ONE_BI) + token0.totalValueLocked = token0.totalValueLocked.minus(amount0) + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) + + // update token1 data + token1.txCount = token1.txCount.plus(ONE_BI) + token1.totalValueLocked = token1.totalValueLocked.minus(amount1) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) + + // pool data + pool.txCount = pool.txCount.plus(ONE_BI) + // Pools liquidity tracks the currently active liquidity given pools current tick. + // We only want to update it on burn if the position being burnt includes the current tick. + if ( + pool.tick !== null && + BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && + BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) + ) { + pool.liquidity = pool.liquidity.minus(event.params.amount) + } + + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.minus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.minus(amount1) + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + // reset aggregates with new amounts + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + // burn entity + const transaction = loadTransaction(event) + const burn = new Burn(transaction.id + '#' + pool.txCount.toString()) + burn.transaction = transaction.id + burn.timestamp = transaction.timestamp + burn.pool = pool.id + burn.token0 = pool.token0 + burn.token1 = pool.token1 + burn.owner = event.params.owner + burn.origin = event.transaction.from + burn.amount = event.params.amount + burn.amount0 = amount0 + burn.amount1 = amount1 + burn.amountUSD = amountUSD + burn.tickLower = BigInt.fromI32(event.params.tickLower) + burn.tickUpper = BigInt.fromI32(event.params.tickUpper) + burn.logIndex = event.logIndex + + // tick entities + const lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString() + const upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString() + const lowerTick = Tick.load(lowerTickId) + const upperTick = Tick.load(upperTickId) + if (lowerTick && upperTick) { + const amount = event.params.amount + lowerTick.liquidityGross = lowerTick.liquidityGross.minus(amount) + lowerTick.liquidityNet = lowerTick.liquidityNet.minus(amount) + upperTick.liquidityGross = upperTick.liquidityGross.minus(amount) + upperTick.liquidityNet = upperTick.liquidityNet.plus(amount) + + lowerTick.save() + upperTick.save() + } + updateUniswapDayData(event) + updatePoolDayData(event) + updatePoolHourData(event) + updateTokenDayData(token0 as Token, event) + updateTokenDayData(token1 as Token, event) + updateTokenHourData(token0 as Token, event) + updateTokenHourData(token1 as Token, event) + + token0.save() + token1.save() + pool.save() + factory.save() + burn.save() + } +} diff --git a/src/mappings/pool/index.ts b/src/mappings/pool/index.ts new file mode 100644 index 00000000..a93f469c --- /dev/null +++ b/src/mappings/pool/index.ts @@ -0,0 +1,6 @@ +import { handleBurn } from './burn' +import { handleInitialize } from './initialize' +import { handleMint } from './mint' +import { handleSwap } from './swap' + +export { handleBurn, handleInitialize, handleMint, handleSwap } diff --git a/src/mappings/pool/initialize.ts b/src/mappings/pool/initialize.ts new file mode 100644 index 00000000..9e2cc3be --- /dev/null +++ b/src/mappings/pool/initialize.ts @@ -0,0 +1,34 @@ +import { BigInt } from '@graphprotocol/graph-ts' + +import { Bundle, Pool, Token } from '../../types/schema' +import { Initialize } from '../../types/templates/Pool/Pool' +import { updatePoolDayData, updatePoolHourData } from '../../utils/intervalUpdates' +import { findEthPerToken, getEthPriceInUSD } from '../../utils/pricing' + +export function handleInitialize(event: Initialize): void { + // update pool sqrt price and tick + const pool = Pool.load(event.address.toHexString())! + pool.sqrtPrice = event.params.sqrtPriceX96 + pool.tick = BigInt.fromI32(event.params.tick) + pool.save() + + // update token prices + const token0 = Token.load(pool.token0) + const token1 = Token.load(pool.token1) + + // update ETH price now that prices could have changed + const bundle = Bundle.load('1')! + bundle.ethPriceUSD = getEthPriceInUSD() + bundle.save() + + updatePoolDayData(event) + updatePoolHourData(event) + + // update token prices + if (token0 && token1) { + token0.derivedETH = findEthPerToken(token0 as Token) + token1.derivedETH = findEthPerToken(token1 as Token) + token0.save() + token1.save() + } +} diff --git a/src/mappings/pool/mint.ts b/src/mappings/pool/mint.ts new file mode 100644 index 00000000..892ed182 --- /dev/null +++ b/src/mappings/pool/mint.ts @@ -0,0 +1,135 @@ +import { BigInt } from '@graphprotocol/graph-ts' + +import { Bundle, Factory, Mint, Pool, Tick, Token } from '../../types/schema' +import { Mint as MintEvent } from '../../types/templates/Pool/Pool' +import { convertTokenToDecimal, loadTransaction } from '../../utils' +import { FACTORY_ADDRESS, ONE_BI } from '../../utils/constants' +import { + updatePoolDayData, + updatePoolHourData, + updateTokenDayData, + updateTokenHourData, + updateUniswapDayData, +} from '../../utils/intervalUpdates' +import { createTick } from '../../utils/tick' + +export function handleMint(event: MintEvent): void { + const bundle = Bundle.load('1')! + const poolAddress = event.address.toHexString() + const pool = Pool.load(poolAddress)! + const factory = Factory.load(FACTORY_ADDRESS)! + + const token0 = Token.load(pool.token0) + const token1 = Token.load(pool.token1) + + if (token0 && token1) { + const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + + const amountUSD = amount0 + .times(token0.derivedETH.times(bundle.ethPriceUSD)) + .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) + + // reset tvl aggregates until new amounts calculated + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) + + // update globals + factory.txCount = factory.txCount.plus(ONE_BI) + + // update token0 data + token0.txCount = token0.txCount.plus(ONE_BI) + token0.totalValueLocked = token0.totalValueLocked.plus(amount0) + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) + + // update token1 data + token1.txCount = token1.txCount.plus(ONE_BI) + token1.totalValueLocked = token1.totalValueLocked.plus(amount1) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) + + // pool data + pool.txCount = pool.txCount.plus(ONE_BI) + + // Pools liquidity tracks the currently active liquidity given pools current tick. + // We only want to update it on mint if the new position includes the current tick. + if ( + pool.tick !== null && + BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && + BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) + ) { + pool.liquidity = pool.liquidity.plus(event.params.amount) + } + + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + // reset aggregates with new amounts + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + const transaction = loadTransaction(event) + const mint = new Mint(transaction.id.toString() + '#' + pool.txCount.toString()) + mint.transaction = transaction.id + mint.timestamp = transaction.timestamp + mint.pool = pool.id + mint.token0 = pool.token0 + mint.token1 = pool.token1 + mint.owner = event.params.owner + mint.sender = event.params.sender + mint.origin = event.transaction.from + mint.amount = event.params.amount + mint.amount0 = amount0 + mint.amount1 = amount1 + mint.amountUSD = amountUSD + mint.tickLower = BigInt.fromI32(event.params.tickLower) + mint.tickUpper = BigInt.fromI32(event.params.tickUpper) + mint.logIndex = event.logIndex + + // tick entities + const lowerTickIdx = event.params.tickLower + const upperTickIdx = event.params.tickUpper + + const lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString() + const upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString() + + let lowerTick = Tick.load(lowerTickId) + let upperTick = Tick.load(upperTickId) + + if (lowerTick === null) { + lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event) + } + + if (upperTick === null) { + upperTick = createTick(upperTickId, upperTickIdx, pool.id, event) + } + + const amount = event.params.amount + lowerTick.liquidityGross = lowerTick.liquidityGross.plus(amount) + lowerTick.liquidityNet = lowerTick.liquidityNet.plus(amount) + upperTick.liquidityGross = upperTick.liquidityGross.plus(amount) + upperTick.liquidityNet = upperTick.liquidityNet.minus(amount) + + lowerTick.save() + upperTick.save() + + // TODO: Update Tick's volume, fees, and liquidity provider count. Computing these on the tick + // level requires reimplementing some of the swapping code from v3-core. + + updateUniswapDayData(event) + updatePoolDayData(event) + updatePoolHourData(event) + updateTokenDayData(token0 as Token, event) + updateTokenDayData(token1 as Token, event) + updateTokenHourData(token0 as Token, event) + updateTokenHourData(token1 as Token, event) + + token0.save() + token1.save() + pool.save() + factory.save() + mint.save() + } +} diff --git a/src/mappings/pool/swap.ts b/src/mappings/pool/swap.ts new file mode 100644 index 00000000..320decfc --- /dev/null +++ b/src/mappings/pool/swap.ts @@ -0,0 +1,204 @@ +import { BigDecimal, BigInt } from '@graphprotocol/graph-ts' + +import { Bundle, Factory, Pool, Swap, Token } from '../../types/schema' +import { Swap as SwapEvent } from '../../types/templates/Pool/Pool' +import { convertTokenToDecimal, loadTransaction, safeDiv } from '../../utils' +import { FACTORY_ADDRESS, ONE_BI, ZERO_BD } from '../../utils/constants' +import { + updatePoolDayData, + updatePoolHourData, + updateTokenDayData, + updateTokenHourData, + updateUniswapDayData, +} from '../../utils/intervalUpdates' +import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToTokenPrices } from '../../utils/pricing' + +export function handleSwap(event: SwapEvent): void { + const bundle = Bundle.load('1')! + const factory = Factory.load(FACTORY_ADDRESS)! + const pool = Pool.load(event.address.toHexString())! + + // hot fix for bad pricing + if (pool.id == '0x9663f2ca0454accad3e094448ea6f77443880454') { + return + } + + const token0 = Token.load(pool.token0) + const token1 = Token.load(pool.token1) + + if (token0 && token1) { + // amounts - 0/1 are token deltas: can be positive or negative + const amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + const amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + + // need absolute amounts for volume + let amount0Abs = amount0 + if (amount0.lt(ZERO_BD)) { + amount0Abs = amount0.times(BigDecimal.fromString('-1')) + } + let amount1Abs = amount1 + if (amount1.lt(ZERO_BD)) { + amount1Abs = amount1.times(BigDecimal.fromString('-1')) + } + + const amount0ETH = amount0Abs.times(token0.derivedETH) + const amount1ETH = amount1Abs.times(token1.derivedETH) + const amount0USD = amount0ETH.times(bundle.ethPriceUSD) + const amount1USD = amount1ETH.times(bundle.ethPriceUSD) + + // get amount that should be tracked only - div 2 because cant count both input and output as volume + const amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div( + BigDecimal.fromString('2') + ) + const amountTotalETHTracked = safeDiv(amountTotalUSDTracked, bundle.ethPriceUSD) + const amountTotalUSDUntracked = amount0USD.plus(amount1USD).div(BigDecimal.fromString('2')) + + const feesETH = amountTotalETHTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) + const feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) + + // global updates + factory.txCount = factory.txCount.plus(ONE_BI) + factory.totalVolumeETH = factory.totalVolumeETH.plus(amountTotalETHTracked) + factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked) + factory.untrackedVolumeUSD = factory.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + factory.totalFeesETH = factory.totalFeesETH.plus(feesETH) + factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD) + + // reset aggregate tvl before individual pool tvl updates + const currentPoolTvlETH = pool.totalValueLockedETH + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(currentPoolTvlETH) + + // pool volume + pool.volumeToken0 = pool.volumeToken0.plus(amount0Abs) + pool.volumeToken1 = pool.volumeToken1.plus(amount1Abs) + pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked) + pool.untrackedVolumeUSD = pool.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + pool.feesUSD = pool.feesUSD.plus(feesUSD) + pool.txCount = pool.txCount.plus(ONE_BI) + + // Update the pool with the new active liquidity, price, and tick. + pool.liquidity = event.params.liquidity + pool.tick = BigInt.fromI32(event.params.tick as i32) + pool.sqrtPrice = event.params.sqrtPriceX96 + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) + + // update token0 data + token0.volume = token0.volume.plus(amount0Abs) + token0.totalValueLocked = token0.totalValueLocked.plus(amount0) + token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked) + token0.untrackedVolumeUSD = token0.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + token0.feesUSD = token0.feesUSD.plus(feesUSD) + token0.txCount = token0.txCount.plus(ONE_BI) + + // update token1 data + token1.volume = token1.volume.plus(amount1Abs) + token1.totalValueLocked = token1.totalValueLocked.plus(amount1) + token1.volumeUSD = token1.volumeUSD.plus(amountTotalUSDTracked) + token1.untrackedVolumeUSD = token1.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + token1.feesUSD = token1.feesUSD.plus(feesUSD) + token1.txCount = token1.txCount.plus(ONE_BI) + + // updated pool ratess + const prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token) + pool.token0Price = prices[0] + pool.token1Price = prices[1] + pool.save() + + // update USD pricing + bundle.ethPriceUSD = getEthPriceInUSD() + bundle.save() + token0.derivedETH = findEthPerToken(token0 as Token) + token1.derivedETH = findEthPerToken(token1 as Token) + + /** + * Things afffected by new USD rates + */ + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH).times(bundle.ethPriceUSD) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD) + + // create Swap event + const transaction = loadTransaction(event) + const swap = new Swap(transaction.id + '#' + pool.txCount.toString()) + swap.transaction = transaction.id + swap.timestamp = transaction.timestamp + swap.pool = pool.id + swap.token0 = pool.token0 + swap.token1 = pool.token1 + swap.sender = event.params.sender + swap.origin = event.transaction.from + swap.recipient = event.params.recipient + swap.amount0 = amount0 + swap.amount1 = amount1 + swap.amountUSD = amountTotalUSDTracked + swap.tick = BigInt.fromI32(event.params.tick as i32) + swap.sqrtPriceX96 = event.params.sqrtPriceX96 + swap.logIndex = event.logIndex + + // interval data + const uniswapDayData = updateUniswapDayData(event) + const poolDayData = updatePoolDayData(event) + const poolHourData = updatePoolHourData(event) + const token0DayData = updateTokenDayData(token0 as Token, event) + const token1DayData = updateTokenDayData(token1 as Token, event) + const token0HourData = updateTokenHourData(token0 as Token, event) + const token1HourData = updateTokenHourData(token1 as Token, event) + + // update volume metrics + uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked) + uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked) + uniswapDayData.feesUSD = uniswapDayData.feesUSD.plus(feesUSD) + + poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked) + poolDayData.volumeToken0 = poolDayData.volumeToken0.plus(amount0Abs) + poolDayData.volumeToken1 = poolDayData.volumeToken1.plus(amount1Abs) + poolDayData.feesUSD = poolDayData.feesUSD.plus(feesUSD) + + poolHourData.volumeUSD = poolHourData.volumeUSD.plus(amountTotalUSDTracked) + poolHourData.volumeToken0 = poolHourData.volumeToken0.plus(amount0Abs) + poolHourData.volumeToken1 = poolHourData.volumeToken1.plus(amount1Abs) + poolHourData.feesUSD = poolHourData.feesUSD.plus(feesUSD) + + token0DayData.volume = token0DayData.volume.plus(amount0Abs) + token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked) + token0DayData.untrackedVolumeUSD = token0DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token0DayData.feesUSD = token0DayData.feesUSD.plus(feesUSD) + + token0HourData.volume = token0HourData.volume.plus(amount0Abs) + token0HourData.volumeUSD = token0HourData.volumeUSD.plus(amountTotalUSDTracked) + token0HourData.untrackedVolumeUSD = token0HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token0HourData.feesUSD = token0HourData.feesUSD.plus(feesUSD) + + token1DayData.volume = token1DayData.volume.plus(amount1Abs) + token1DayData.volumeUSD = token1DayData.volumeUSD.plus(amountTotalUSDTracked) + token1DayData.untrackedVolumeUSD = token1DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token1DayData.feesUSD = token1DayData.feesUSD.plus(feesUSD) + + token1HourData.volume = token1HourData.volume.plus(amount1Abs) + token1HourData.volumeUSD = token1HourData.volumeUSD.plus(amountTotalUSDTracked) + token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD) + + swap.save() + token0DayData.save() + token1DayData.save() + uniswapDayData.save() + poolDayData.save() + poolHourData.save() + token0HourData.save() + token1HourData.save() + poolHourData.save() + factory.save() + pool.save() + token0.save() + token1.save() + } +} diff --git a/subgraph.yaml b/subgraph.yaml index e351f7ff..8f449b3b 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -6,9 +6,6 @@ schema: features: - nonFatalErrors - grafting -graft: - base: QmZMY9okvPQKzWUqKF8RiRYwqph7Pc4aQZLPhfGvm9xSf4 - block: 13662965 dataSources: - kind: ethereum/contract name: Factory @@ -49,7 +46,7 @@ templates: kind: ethereum/events apiVersion: 0.0.7 language: wasm/assemblyscript - file: ./src/mappings/core.ts + file: ./src/mappings/pool/index.ts entities: - Pool - Token diff --git a/yarn.lock b/yarn.lock index a5151a1c..b4833d2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1450,7 +1450,7 @@ chalk@3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^2.0.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1658,6 +1658,17 @@ cross-spawn@7.0.3, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2790,16 +2801,16 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== -graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" @@ -2905,6 +2916,11 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + http-basic@^8.1.1: version "8.1.3" resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf" @@ -3509,6 +3525,11 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -3604,6 +3625,16 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -3746,6 +3777,11 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== + merge-options@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7" @@ -3942,6 +3978,11 @@ natural-orderby@^2.0.3: resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-2.0.3.tgz#8623bc518ba162f8ff1cdb8941d74deb0fdcc016" integrity sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q== +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" @@ -3959,11 +4000,36 @@ node-gyp-build@^4.2.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + 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== +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -4143,6 +4209,14 @@ parse-duration@^1.0.0: resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-1.1.0.tgz#5192084c5d8f2a3fd676d04a451dbd2e05a1819c" integrity sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ== +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -4171,6 +4245,11 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -4189,6 +4268,13 @@ path-scurry@^1.6.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -4220,6 +4306,16 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== + pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" @@ -4368,6 +4464,15 @@ react-native-fetch-api@^3.0.0: dependencies: p-defer "^3.0.0" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -4485,7 +4590,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.22.4: +resolve@^1.10.0, resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -4605,6 +4710,11 @@ secp256k1@^4.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" +"semver@2 || 3 || 4 || 5", semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + semver@7.3.5, semver@^7.3.2: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -4666,6 +4776,13 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4673,11 +4790,21 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.6.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" @@ -4725,6 +4852,32 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.17" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" + integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== + split-ca@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" @@ -4798,6 +4951,16 @@ string.prototype.matchall@^4.0.10: set-function-name "^2.0.2" side-channel "^1.0.6" +string.prototype.padend@^3.0.0: + version "3.1.6" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz#ba79cf8992609a91c872daa47c6bb144ee7f62a5" + integrity sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + string.prototype.trim@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" @@ -5246,6 +5409,14 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + varint@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" @@ -5374,6 +5545,13 @@ which@2.0.2, which@^2.0.1: 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" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"