diff --git a/.github/workflows/publish_oraiswap_v3.yml b/.github/workflows/publish_oraiswap_v3.yml new file mode 100644 index 00000000..0ec5f27b --- /dev/null +++ b/.github/workflows/publish_oraiswap_v3.yml @@ -0,0 +1,67 @@ +# name: publish_package_oraiswap_v3 + +# # Controls when the action will run. +# on: +# # Triggers the workflow on push or pull request events but only for the main branch +# push: +# branches: [feat/zapper-2] + +# # Allows you to run this workflow manually from the Actions tab +# workflow_dispatch: + +# # A workflow run is made up of one or more jobs that can run sequentially or in parallel +# jobs: +# build: +# runs-on: ubuntu-20.04 +# strategy: +# matrix: +# node-version: ["18"] +# steps: +# - name: Cancel Previous Runs +# uses: styfle/cancel-workflow-action@0.8.0 +# with: +# access_token: ${{ github.token }} +# - uses: actions/checkout@v2 +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v2 +# with: +# node-version: ${{ matrix.node-version }} +# - name: Get yarn cache directory path +# id: yarn-cache-dir-path +# run: echo "::set-output name=dir::$(yarn cache dir)" +# - uses: actions/cache@v4 +# id: yarn-cache +# with: +# path: | +# ${{ steps.yarn-cache-dir-path.outputs.dir }} +# ./node_modules/ +# key: ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }} +# restore-keys: | +# ${{ runner.os }}-yarn- +# - name: Install Dependencies +# run: yarn +# - name: Build +# run: yarn build +# - name: Authenticate with private NPM package +# run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc +# - name: Publish Oraiswap v3 +# id: publish-oraiswap-v3 +# continue-on-error: true +# run: yarn deploy:beta packages/oraiswap-v3 +# env: +# CI: false +# NPM_TOKEN: ${{ secrets.NPM_TOKEN }} +# - name: Publish Contract SDK +# id: publish-oraidex-contracts-sdk +# continue-on-error: true +# run: yarn deploy:beta packages/contracts-sdk +# env: +# CI: false +# NPM_TOKEN: ${{ secrets.NPM_TOKEN }} +# - name: Publish Contract Build +# id: publish-oraidex-contracts-build +# continue-on-error: true +# run: yarn deploy:beta packages/contracts-build +# env: +# CI: false +# NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 2dfd1baa..7f27c0a6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,7 @@ cache/ packages/contract-state-simulate/public/ coverage -.nx/cache \ No newline at end of file +.nx/cache +.nx/workspace-data + +.yarn \ No newline at end of file diff --git a/.yarnrc b/.yarnrc new file mode 100644 index 00000000..34b504ab --- /dev/null +++ b/.yarnrc @@ -0,0 +1,5 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + + +yarn-path ".yarn/releases/yarn-1.22.22.cjs" diff --git a/package.json b/package.json index d7e2793a..cb19efdf 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "husky": "^9.0.11", "jest": "^29.7.0", "lerna": "^8.1.2", - "nx": "18.1.2", + "nx": "19.7.3", "patch-package": "^8.0.0", "rimraf": "^5.0.5", "ts-jest": "^29.1.2", diff --git a/packages/contracts-build/data/zapper.wasm b/packages/contracts-build/data/zapper.wasm new file mode 100644 index 00000000..a81ea44f Binary files /dev/null and b/packages/contracts-build/data/zapper.wasm differ diff --git a/packages/contracts-build/package.json b/packages/contracts-build/package.json index b2d5b466..92947064 100644 --- a/packages/contracts-build/package.json +++ b/packages/contracts-build/package.json @@ -1,6 +1,6 @@ { "name": "@oraichain/oraidex-contracts-build", - "version": "1.0.36", + "version": "1.0.37", "main": "build/index.js", "license": "MIT", "scripts": { diff --git a/packages/contracts-build/src/index.ts b/packages/contracts-build/src/index.ts index a560e6a7..bfebdadb 100644 --- a/packages/contracts-build/src/index.ts +++ b/packages/contracts-build/src/index.ts @@ -16,7 +16,8 @@ export type ContractName = | "oraiswap-router" | "oraiswap-staking" | "oraidex-listing-contract" - | "oraiswap-v3"; + | "oraiswap-v3" + | "zapper"; const contractDir = path.join(__dirname, "..", "data"); diff --git a/packages/contracts-sdk/package.json b/packages/contracts-sdk/package.json index 0e470993..30cc4a69 100644 --- a/packages/contracts-sdk/package.json +++ b/packages/contracts-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@oraichain/oraidex-contracts-sdk", - "version": "1.0.51", + "version": "1.0.52", "main": "build/index.js", "files": [ "build/", diff --git a/packages/contracts-sdk/src/Zapper.client.ts b/packages/contracts-sdk/src/Zapper.client.ts new file mode 100644 index 00000000..d3b6d51a --- /dev/null +++ b/packages/contracts-sdk/src/Zapper.client.ts @@ -0,0 +1,166 @@ +/** +* This file was automatically generated by @oraichain/ts-codegen@0.35.9. +* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, +* and run the @oraichain/ts-codegen generate command to regenerate this file. +*/ + +import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate"; +import { Coin, StdFee } from "@cosmjs/amino"; +import {Addr, InstantiateMsg, ExecuteMsg, Uint128, AssetInfo, Liquidity, Percentage, SwapOperation, AssetInfo2, Decimal, Asset, PoolKey, FeeTier, Route, QueryMsg, MigrateMsg, Config, ProtocolFee} from "./Zapper.types"; +export interface ZapperReadOnlyInterface { + contractAddress: string; + config: () => Promise; + protocolFee: () => Promise; +} +export class ZapperQueryClient implements ZapperReadOnlyInterface { + client: CosmWasmClient; + contractAddress: string; + + constructor(client: CosmWasmClient, contractAddress: string) { + this.client = client; + this.contractAddress = contractAddress; + this.config = this.config.bind(this); + this.protocolFee = this.protocolFee.bind(this); + } + + config = async (): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + config: {} + }); + }; + protocolFee = async (): Promise => { + return this.client.queryContractSmart(this.contractAddress, { + protocol_fee: {} + }); + }; +} +export interface ZapperInterface extends ZapperReadOnlyInterface { + contractAddress: string; + sender: string; + updateConfig: ({ + admin, + dexV3, + mixedRouter + }: { + admin?: Addr; + dexV3?: Addr; + mixedRouter?: Addr; + }, _fee?: number | StdFee | "auto", _memo?: string, _funds?: Coin[]) => Promise; + zapInLiquidity: ({ + assetIn, + minimumLiquidity, + poolKey, + routes, + tickLowerIndex, + tickUpperIndex + }: { + assetIn: Asset; + minimumLiquidity?: Liquidity; + poolKey: PoolKey; + routes: Route[]; + tickLowerIndex: number; + tickUpperIndex: number; + }, _fee?: number | StdFee | "auto", _memo?: string, _funds?: Coin[]) => Promise; + zapOutLiquidity: ({ + positionIndex, + routes + }: { + positionIndex: number; + routes: Route[]; + }, _fee?: number | StdFee | "auto", _memo?: string, _funds?: Coin[]) => Promise; + registerProtocolFee: ({ + feeReceiver, + percent + }: { + feeReceiver: Addr; + percent: Decimal; + }, _fee?: number | StdFee | "auto", _memo?: string, _funds?: Coin[]) => Promise; +} +export class ZapperClient extends ZapperQueryClient implements ZapperInterface { + client: SigningCosmWasmClient; + sender: string; + contractAddress: string; + + constructor(client: SigningCosmWasmClient, sender: string, contractAddress: string) { + super(client, contractAddress); + this.client = client; + this.sender = sender; + this.contractAddress = contractAddress; + this.updateConfig = this.updateConfig.bind(this); + this.zapInLiquidity = this.zapInLiquidity.bind(this); + this.zapOutLiquidity = this.zapOutLiquidity.bind(this); + this.registerProtocolFee = this.registerProtocolFee.bind(this); + } + + updateConfig = async ({ + admin, + dexV3, + mixedRouter + }: { + admin?: Addr; + dexV3?: Addr; + mixedRouter?: Addr; + }, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise => { + return await this.client.execute(this.sender, this.contractAddress, { + update_config: { + admin, + dex_v3: dexV3, + mixed_router: mixedRouter + } + }, _fee, _memo, _funds); + }; + zapInLiquidity = async ({ + assetIn, + minimumLiquidity, + poolKey, + routes, + tickLowerIndex, + tickUpperIndex + }: { + assetIn: Asset; + minimumLiquidity?: Liquidity; + poolKey: PoolKey; + routes: Route[]; + tickLowerIndex: number; + tickUpperIndex: number; + }, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise => { + return await this.client.execute(this.sender, this.contractAddress, { + zap_in_liquidity: { + asset_in: assetIn, + minimum_liquidity: minimumLiquidity, + pool_key: poolKey, + routes, + tick_lower_index: tickLowerIndex, + tick_upper_index: tickUpperIndex + } + }, _fee, _memo, _funds); + }; + zapOutLiquidity = async ({ + positionIndex, + routes + }: { + positionIndex: number; + routes: Route[]; + }, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise => { + return await this.client.execute(this.sender, this.contractAddress, { + zap_out_liquidity: { + position_index: positionIndex, + routes + } + }, _fee, _memo, _funds); + }; + registerProtocolFee = async ({ + feeReceiver, + percent + }: { + feeReceiver: Addr; + percent: Decimal; + }, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise => { + return await this.client.execute(this.sender, this.contractAddress, { + register_protocol_fee: { + fee_receiver: feeReceiver, + percent + } + }, _fee, _memo, _funds); + }; +} \ No newline at end of file diff --git a/packages/contracts-sdk/src/Zapper.types.ts b/packages/contracts-sdk/src/Zapper.types.ts new file mode 100644 index 00000000..a0c9246e --- /dev/null +++ b/packages/contracts-sdk/src/Zapper.types.ts @@ -0,0 +1,99 @@ +export type Addr = string; +export interface InstantiateMsg { + admin: Addr; + dex_v3: Addr; + mixed_router: Addr; +} +export type ExecuteMsg = { + update_config: { + admin?: Addr | null; + dex_v3?: Addr | null; + mixed_router?: Addr | null; + }; +} | { + zap_in_liquidity: { + asset_in: Asset; + minimum_liquidity?: Liquidity | null; + pool_key: PoolKey; + routes: Route[]; + tick_lower_index: number; + tick_upper_index: number; + }; +} | { + zap_out_liquidity: { + position_index: number; + routes: Route[]; + }; +} | { + register_protocol_fee: { + fee_receiver: Addr; + percent: Decimal; + }; +}; +export type Uint128 = string; +export type AssetInfo = { + token: { + contract_addr: Addr; + }; +} | { + native_token: { + denom: string; + }; +}; +export type Liquidity = string; +export type Percentage = number; +export type SwapOperation = { + orai_swap: { + ask_asset_info: AssetInfo2; + offer_asset_info: AssetInfo2; + }; +} | { + swap_v3: { + pool_key: PoolKey; + x_to_y: boolean; + }; +}; +export type AssetInfo2 = { + token: { + contract_addr: Addr; + }; +} | { + native_token: { + denom: string; + }; +}; +export type Decimal = string; +export interface Asset { + amount: Uint128; + info: AssetInfo; +} +export interface PoolKey { + fee_tier: FeeTier; + token_x: string; + token_y: string; +} +export interface FeeTier { + fee: Percentage; + tick_spacing: number; +} +export interface Route { + minimum_receive?: Uint128 | null; + offer_amount: Uint128; + operations: SwapOperation[]; + token_in: string; +} +export type QueryMsg = { + config: {}; +} | { + protocol_fee: {}; +}; +export interface MigrateMsg {} +export interface Config { + admin: Addr; + dex_v3: Addr; + mixed_router: Addr; +} +export interface ProtocolFee { + fee_receiver: Addr; + percent: Decimal; +} \ No newline at end of file diff --git a/packages/contracts-sdk/src/index.ts b/packages/contracts-sdk/src/index.ts index 8c2e0a81..8d981df6 100644 --- a/packages/contracts-sdk/src/index.ts +++ b/packages/contracts-sdk/src/index.ts @@ -30,4 +30,6 @@ export * as OraiswapV3Types from "./OraiswapV3.types"; export * from "./OraiswapV3.client"; export * as OraiswapMixedRouterTypes from "./OraiswapMixedRouter.types"; export * from "./OraiswapMixedRouter.client"; +export * as ZapperTypes from "./Zapper.types"; +export * from "./Zapper.client"; export * from "./types"; diff --git a/packages/oraidex-common/package.json b/packages/oraidex-common/package.json index 90937475..e8f1b588 100644 --- a/packages/oraidex-common/package.json +++ b/packages/oraidex-common/package.json @@ -1,6 +1,6 @@ { "name": "@oraichain/oraidex-common", - "version": "1.1.6", + "version": "1.1.8", "main": "build/index.js", "files": [ "build/" diff --git a/packages/oraidex-common/src/constant.ts b/packages/oraidex-common/src/constant.ts index 2bdd0c32..cacdd8c0 100644 --- a/packages/oraidex-common/src/constant.ts +++ b/packages/oraidex-common/src/constant.ts @@ -144,6 +144,7 @@ export const MULTICALL_CONTRACT = "orai1q7x644gmf7h8u8y6y8t9z9nnwl8djkmspypr6mxa export const AMM_V3_CONTRACT = "orai10s0c75gw5y5eftms5ncfknw6lzmx0dyhedn75uz793m8zwz4g8zq4d9x9a"; export const AMM_V3_TEST_CONTRACT = "orai1wsemv2wuyfeesh3afcxy02lh8sy4yz2wjj6cxgzmcxklpdyyxjfs5qzl7q"; +export const ZAPPER_CONTRACT = "orai19r5wlt3ruc5xmkfvkwx5l3pul5h8kslexptyqyk5u6acue0ly9yqqpwmtp"; export const BASE_API_URL = "https://api.oraidex.io"; diff --git a/packages/oraiswap-v3/package.json b/packages/oraiswap-v3/package.json index ba6dd44b..ffada211 100644 --- a/packages/oraiswap-v3/package.json +++ b/packages/oraiswap-v3/package.json @@ -1,19 +1,18 @@ { "name": "@oraichain/oraiswap-v3", - "version": "0.1.6", + "version": "0.1.8", "main": "build/index.js", "files": [ "build/" ], "scripts": { "build": "tsc -p tsconfig.json", - "build:test": "tsc --project tsconfig.json" + "build:test": "tsc --project tsconfig.test.json" }, "license": "MIT", "dependencies": { "@cosmjs/cosmwasm-stargate": "^0.31.0", - "@oraichain/oraidex-contracts-sdk": "^1.0.48", - "@oraichain/oraiswap-v3-wasm": "^0.1.0", - "@oraichain/oraidex-common": "latest" + "@oraichain/oraidex-contracts-sdk": "^1.0.52", + "@oraichain/oraidex-common": "^1.1.6" } -} \ No newline at end of file +} diff --git a/packages/oraiswap-v3/src/error.ts b/packages/oraiswap-v3/src/error.ts new file mode 100644 index 00000000..43ece874 --- /dev/null +++ b/packages/oraiswap-v3/src/error.ts @@ -0,0 +1,5 @@ +export class RouteNotFoundError extends Error { + constructor(route: string) { + super(`Route not found: ${route}`); + } +} \ No newline at end of file diff --git a/packages/oraiswap-v3/src/handler.ts b/packages/oraiswap-v3/src/handler.ts index 3638f05d..511c4dd6 100644 --- a/packages/oraiswap-v3/src/handler.ts +++ b/packages/oraiswap-v3/src/handler.ts @@ -1,4 +1,5 @@ -import { Asset, OraiswapV3QueryClient } from "@oraichain/oraidex-contracts-sdk"; +import { Asset } from "@oraichain/oraidex-contracts-sdk/build/OraiswapV3.types"; +import { OraiswapV3QueryClient } from "@oraichain/oraidex-contracts-sdk/build/OraiswapV3.client"; import { AllNftInfoResponse, Approval, @@ -13,11 +14,13 @@ import { QuoteResult, Tick } from "@oraichain/oraidex-contracts-sdk/build/OraiswapV3.types"; -import { CHUNK_QUERY, LIQUIDITY_TICKS_LIMIT, ORAISWAP_V3_CONTRACT, POSITION_TICKS_LIMIT } from "./const"; +import { CHUNK_QUERY, CHUNK_SIZE, LIQUIDITY_TICKS_LIMIT, ORAISWAP_V3_CONTRACT, POSITION_TICKS_LIMIT } from "./const"; import { calculateTokenAmounts, parsePoolKey, poolKeyToString } from "./helpers"; import { CosmWasmClient, fromBinary, toBinary } from "@cosmjs/cosmwasm-stargate"; -import { MulticallQueryClient } from "@oraichain/common-contracts-sdk"; import { MULTICALL_CONTRACT } from "@oraichain/oraidex-common"; +import { MulticallQueryClient } from "@oraichain/common-contracts-sdk/build/Multicall.client"; +import { Tickmap } from "./types"; +import { getMaxTick, getMinTick, positionToTick } from "./wasm/oraiswap_v3_wasm"; export class OraiswapV3Handler { private _client: OraiswapV3QueryClient; @@ -333,4 +336,32 @@ export class OraiswapV3Handler { return { liquidityX, liquidityY }; } + + public async getAllLiquidityTicks(poolKey: PoolKey, tickmap: Tickmap): Promise { + const tickIndexes: number[] = []; + for (const [chunkIndex, chunk] of tickmap.bitmap.entries()) { + for (let bit = 0; bit < CHUNK_SIZE; bit++) { + const checkedBit = chunk & (1n << BigInt(bit)); + if (checkedBit !== 0n) { + const tickIndex = positionToTick(Number(chunkIndex), bit, poolKey.fee_tier.tick_spacing); + tickIndexes.push(tickIndex); + } + } + } + + const tickResults = await this.liquidityTicks(poolKey, tickIndexes); + + return tickResults; + } + + public async getFullTickmap(poolKey: PoolKey): Promise { + const minTick = getMinTick(poolKey.fee_tier.tick_spacing); + const maxTick = getMaxTick(poolKey.fee_tier.tick_spacing); + const tickmap = await this.tickMap(poolKey, minTick, maxTick, true); + const bitmap = new Map(); + tickmap.forEach((t) => { + bitmap.set(BigInt(t[0].toString()), BigInt(t[1].toString())); + }); + return { bitmap }; + } } diff --git a/packages/oraiswap-v3/src/helpers.ts b/packages/oraiswap-v3/src/helpers.ts index e7578e73..61d308bb 100644 --- a/packages/oraiswap-v3/src/helpers.ts +++ b/packages/oraiswap-v3/src/helpers.ts @@ -1,9 +1,35 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { calculateAmountDelta, calculateSqrtPrice } from "./wasm/oraiswap_v3_wasm"; -import { AmountDeltaResult, LiquidityTick, PoolKey, PoolSnapshot, PoolStatsData, PositionLiquidInfo, TokenData, VirtualRange } from "./types"; +import { + calculateAmountDelta, + calculateSqrtPrice, + getLiquidityByX, + getLiquidityByY, + getMaxSqrtPrice, + getMinSqrtPrice, + simulateSwap +} from "./wasm/oraiswap_v3_wasm"; +import { + ActionRoute, + AmountDeltaResult, + LiquidityTick, + PoolKey, + PoolSnapshot, + PoolStatsData, + PositionLiquidInfo, + RouteResponse, + SmartRouteResponse, + Tickmap, + TokenData, + VirtualRange, + ZapInLiquidityResponse, + ZapInResult, + ZapOutLiquidityResponse, + ZapOutResult +} from "./types"; import { DENOMINATOR, LIQUIDITY_DENOMINATOR, PRICE_DENOMINATOR } from "./const"; import { Pool, PoolWithPoolKey, Position } from "@oraichain/oraidex-contracts-sdk/build/OraiswapV3.types"; -import { BigDecimal, oraichainTokens, TokenItemType } from "@oraichain/oraidex-common"; +import { BigDecimal, parseAssetInfoFromContractAddrOrDenom, TokenItemType } from "@oraichain/oraidex-common"; +import { Asset, Route, SwapOperation } from "@oraichain/oraidex-contracts-sdk/build/Zapper.types"; export const getVolume = (pool: PoolWithPoolKey, protocolFee: number): { volumeX: bigint; volumeY: bigint } => { const feeDenominator = (BigInt(protocolFee) * BigInt(pool.pool_key.fee_tier.fee)) / DENOMINATOR; @@ -242,11 +268,7 @@ export const calculateTokenAmounts = (pool: Pool, position: Position): AmountDel return _calculateTokenAmounts(pool, position, false); }; -export const _calculateTokenAmounts = ( - pool: Pool, - position: Position, - sign: boolean -): AmountDeltaResult => { +export const _calculateTokenAmounts = (pool: Pool, position: Position, sign: boolean): AmountDeltaResult => { return calculateAmountDelta( pool.current_tick_index, BigInt(pool.sqrt_price), @@ -256,3 +278,272 @@ export const _calculateTokenAmounts = ( position.lower_tick_index ); }; + +export const shiftDecimal = (value: bigint, decimals: number): BigDecimal => { + const valueStr = value.toString().padStart(decimals + 1, "0"); // Pad with leading zeros if needed + const intStr = valueStr.slice(0, -decimals) || "0"; // Retrieve integral part or default to "0" + const decStr = valueStr.slice(-decimals); // Retrieve decimal part + return new BigDecimal(`${intStr}.${decStr}`, decimals); +}; + +export const parseAsset = (token: TokenItemType, amount: string): Asset => { + const info = token.contractAddress + ? { token: { contract_addr: token.contractAddress } } + : { native_token: { denom: token.denom } }; + return { + amount, + info + }; +}; + +export const generateMessageSwapOperation = (responses: SmartRouteResponse[], slippage: number): Route[] => { + const flattenRoutes: Route[] = []; + + for (const response of responses) { + if (!response.routes) continue; + if (response.routes.length === 0) continue; + + const { routes, returnAmount, swapAmount } = response; + + for (const route of routes) { + const { swapAmount, returnAmount, paths } = route; + const operations: SwapOperation[] = []; + for (const path of paths) { + const { actions, chainId, tokenIn, tokenInAmount, tokenOut, tokenOutAmount, tokenOutChainId } = path; + for (const action of actions) { + const { protocol, swapInfo, tokenIn, tokenInAmount, tokenOut, tokenOutAmount, type } = action; + let currTokenIn = parseAssetInfoFromContractAddrOrDenom(tokenIn); + for (const swap of swapInfo) { + const { poolId } = swap; + const [tokenX, tokenY, fee, tickSpacing] = poolId.split("-"); + const tokenOut = parseAssetInfoFromContractAddrOrDenom(swap.tokenOut); + if (tokenX && tokenY && fee && tickSpacing) { + operations.push({ + swap_v3: { + pool_key: { + token_x: tokenX, + token_y: tokenY, + fee_tier: { + fee: Number(fee), + tick_spacing: Number(tickSpacing) + } + }, + x_to_y: tokenY === swap.tokenOut + } + }); + } else { + operations.push({ + orai_swap: { + offer_asset_info: currTokenIn, + ask_asset_info: tokenOut + } + }); + } + currTokenIn = tokenOut; + } + } + } + flattenRoutes.push({ + offer_amount: swapAmount, + operations, + token_in: paths[0].tokenIn, + minimum_receive: Math.round((Number(returnAmount) * (100 - slippage)) / 100).toString() + }); + } + } + + return flattenRoutes; +}; + +export const getFeeRate = (operation: SwapOperation): number => { + if ("orai_swap" in operation) { + return 0.003; + } else { + return operation.swap_v3.pool_key.fee_tier.fee / 10 ** 12; + } +}; + +export const calculatePriceImpact = (startingSqrtPrice: bigint, endingSqrtPrice: bigint): bigint => { + const startingPrice = startingSqrtPrice * startingSqrtPrice; + const endingPrice = endingSqrtPrice * endingSqrtPrice; + let priceQuotient: bigint; + if (endingPrice >= startingPrice) { + priceQuotient = (DENOMINATOR * startingPrice) / endingPrice; + } else { + priceQuotient = (DENOMINATOR * endingPrice) / startingPrice; + } + return DENOMINATOR - priceQuotient; +}; + +// TODO: current work for only dexV3 +export const getPriceImpactAfterSwap = ({ + route, + allPools, + allTickMaps, + allTicks +}: { + route: Route; + allPools: Record; + allTickMaps: Record; + allTicks: Record; +}): number => { + const { offer_amount, operations, token_in, minimum_receive } = route; + + let totalPriceImpact = 0n; + let amountIn = BigInt(offer_amount); + let tokenIn = token_in; + operations.forEach((operation) => { + const { swap_v3 } = operation as { + swap_v3: { + pool_key: PoolKey; + x_to_y: boolean; + }; + }; + + const pool = allPools[poolKeyToString(swap_v3.pool_key)]; + const convertPool = { + ...pool.pool, + liquidity: BigInt(pool.pool.liquidity), + sqrt_price: BigInt(pool.pool.sqrt_price), + fee_growth_global_x: BigInt(pool.pool.fee_growth_global_x), + fee_growth_global_y: BigInt(pool.pool.fee_growth_global_y), + fee_protocol_token_x: BigInt(pool.pool.fee_protocol_token_x), + fee_protocol_token_y: BigInt(pool.pool.fee_protocol_token_y) + }; + + const swapResult = simulateSwap( + allTickMaps[poolKeyToString(swap_v3.pool_key)], + allPools[poolKeyToString(swap_v3.pool_key)].pool_key.fee_tier, + convertPool, + allTicks[poolKeyToString(swap_v3.pool_key)], + swap_v3.x_to_y, + amountIn, + true, + swap_v3.x_to_y + ? getMinSqrtPrice(swap_v3.pool_key.fee_tier.tick_spacing) + : getMaxSqrtPrice(swap_v3.pool_key.fee_tier.tick_spacing) + ); + + const priceImpact = calculatePriceImpact( + BigInt(allPools[poolKeyToString(swap_v3.pool_key)].pool.sqrt_price), + swapResult.sqrtPrice + ); + totalPriceImpact += priceImpact; + amountIn = swapResult.amountOut; + }); + + return Number(totalPriceImpact / BigInt(operations.length)) / 10 ** 12; +}; + +export const calculateRewardAmounts = ( + pool: PoolWithPoolKey, + position: Position, + zapFee: number +): { amountX: bigint; amountY: bigint } => { + const res = calculateTokenAmounts(pool.pool, position); + const amountX = (res.x * BigInt(100 - zapFee * 100)) / 100n; + const amountY = (res.y * BigInt(100 - zapFee * 100)) / 100n; + return { amountX, amountY }; +}; + +export const buildZapOutMessage = ( + zapOutResult: ZapOutResult, + positionIndex: number, + xRouteInfo: SmartRouteResponse, + yRouteInfo: SmartRouteResponse, + slippage: number +): ZapOutLiquidityResponse => { + const minimumReceiveX = xRouteInfo.routes + ? Math.trunc(new BigDecimal(xRouteInfo.returnAmount).mul((100 - slippage) / 100).toNumber()).toString() + : xRouteInfo.returnAmount; + const minimumReceiveY = yRouteInfo.routes + ? Math.trunc(new BigDecimal(yRouteInfo.returnAmount).mul((100 - slippage) / 100).toNumber()).toString() + : yRouteInfo.returnAmount; + + const routes = generateMessageSwapOperation([xRouteInfo, yRouteInfo], slippage); + let swapFee = 0; + routes.forEach((route) => { + route.operations.forEach((operation) => { + swapFee += getFeeRate(operation); + }); + }); + + return { + amountToX: BigInt(xRouteInfo.returnAmount), + amountToY: BigInt(yRouteInfo.returnAmount), + positionIndex, + routes, + swapFee, + minimumReceiveX, + minimumReceiveY, + result: zapOutResult + }; +}; + +export const extractOraidexV3Actions = (routes: RouteResponse[]): ActionRoute[] => { + const routesArray: ActionRoute[] = []; + if (routes !== null) { + routes.forEach((route) => { + route.paths.forEach((path) => { + path.actions.forEach((action) => { + if (action.protocol === "OraidexV3") { + routesArray.push(action); + } + }); + }); + }); + } + return routesArray; +}; + +export const populateMessageZapIn = ( + message: ZapInLiquidityResponse, + tokenIn: TokenItemType, + amountIn: string, + amountInToX: bigint, + amountInToY: bigint, + actualAmountXReceived: SmartRouteResponse, + actualAmountYReceived: SmartRouteResponse, + poolKey: PoolKey, + pool: Pool, + lowerTick: number, + upperTick: number, + slippage: number +) => { + message.assetIn = parseAsset(tokenIn, amountIn); + message.amountToX = amountInToX.toString(); + message.amountToY = amountInToY.toString(); + message.amountX = actualAmountXReceived.returnAmount; + message.amountY = actualAmountYReceived.returnAmount; + message.poolKey = poolKey; + message.sqrtPrice = BigInt(pool.sqrt_price); + message.tickLowerIndex = lowerTick; + message.tickUpperIndex = upperTick; + message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage); +}; + +export const calculateSwapFee = (message: ZapInLiquidityResponse) => { + message.swapFee = 0; + message.routes.forEach((route) => { + route.operations.forEach((operation) => { + message.swapFee += getFeeRate(operation); + }); + }); +}; + +export const calculateMinimumLiquidity = ( + message: ZapInLiquidityResponse, + actualAmountXReceived: SmartRouteResponse, + actualAmountYReceived: SmartRouteResponse, + lowerTick: number, + upperTick: number, + sqrtPrice: bigint, + slippage: number +) => { + const res1 = getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true); + const res2 = getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true); + message.minimumLiquidity = + res1.l > res2.l + ? (BigInt(res2.l) * BigInt(100 - slippage)) / 100n + : (BigInt(res1.l) * BigInt(100 - slippage)) / 100n; +}; diff --git a/packages/oraiswap-v3/src/index.ts b/packages/oraiswap-v3/src/index.ts index 966a3796..61589145 100644 --- a/packages/oraiswap-v3/src/index.ts +++ b/packages/oraiswap-v3/src/index.ts @@ -2,4 +2,6 @@ export * from "./const"; export * from "./types"; export * from "./helpers"; export * from "./handler"; +export * from "./zap-consumer"; +export * from "./error"; export * from "./wasm/oraiswap_v3_wasm"; diff --git a/packages/oraiswap-v3/src/main.ts b/packages/oraiswap-v3/src/main.ts new file mode 100644 index 00000000..267d3b92 --- /dev/null +++ b/packages/oraiswap-v3/src/main.ts @@ -0,0 +1,72 @@ +import { + AMM_V3_CONTRACT, + MULTICALL_CONTRACT, + oraichainTokens, + ORAIX_CONTRACT, + TokenItemType, + USDT_CONTRACT +} from "@oraichain/oraidex-common"; +import { ZapConsumer } from "./zap-consumer"; +import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { extractAddress, parsePoolKey, poolKeyToString } from "./helpers"; + +async function main() { + const poolList = [ + // `orai-${USDT_CONTRACT}-3000000000-100`, + // `${ATOM_ORAICHAIN_DENOM}-orai-3000000000-100`, + // `${USDT_CONTRACT}-${USDC_CONTRACT}-500000000-10`, + // `orai-${USDC_CONTRACT}-3000000000-100`, + // `${OSMOSIS_ORAICHAIN_DENOM}-orai-3000000000-100`, + `orai-${ORAIX_CONTRACT}-3000000000-100` + ]; + const tokenIn = oraichainTokens.find((t) => extractAddress(t) === USDT_CONTRACT) as TokenItemType; + + const zapper = new ZapConsumer({ + routerApi: "https://osor.oraidex.io/smart-router/alpha-router", + client: await CosmWasmClient.connect("https://rpc.orai.io"), + dexV3Address: AMM_V3_CONTRACT, + multiCallAddress: MULTICALL_CONTRACT, + deviation: 0, + smartRouteConfig: { + swapOptions: { + protocols: ["OraidexV3"], + } + }, + }); + + // const handler = zapper.handler; + + // const pool = await handler.getPool(parsePoolKey(poolList[0])); + // console.log(pool); + // const tickMap = await zapper.getFullTickmap(parsePoolKey(poolList[0])); + // console.log(tickMap); + + //[221800, 2900, 700, 800, 1000, 1800, -5500, -4500, -221800] + //[221800, 2900, 700, 800, 1000, 1800, -5500, -4500, -221800] + + // const minTick = getMinTick(poolKey.fee_tier.tick_spacing); + // const maxTick = getMaxTick(poolKey.fee_tier.tick_spacing); + // const tickMap = await handler.tickMap(parsePoolKey(poolList[0]), minTick, maxTick, true); + // console.log(tickMap); + // const tickMap2 = await zapper.getFullTickmap(parsePoolKey(poolList[0])); + // console.log({ tickMap2 }); + + // const liquidityTick = await zapper.getAllLiquidityTicks(parsePoolKey(poolList[0]), tickMap2); + // console.log({ liquidityTick }); + const tickSpacing = parsePoolKey(poolList[0]).fee_tier.tick_spacing; + const currentTick = (await zapper.handler.getPool(parsePoolKey(poolList[0]))).pool.current_tick_index; + + const poolKey = parsePoolKey(poolList[0]); + const res = await zapper.processZapInPositionLiquidity({ + poolKey: poolKey, + tokenIn: tokenIn as TokenItemType, + amountIn: "1000000000", + lowerTick: currentTick - tickSpacing * 3, + upperTick: currentTick + tickSpacing * 3, + tokenX: oraichainTokens.find((t) => extractAddress(t) === 'orai') as TokenItemType, + tokenY: oraichainTokens.find((t) => extractAddress(t) === ORAIX_CONTRACT) as TokenItemType, + }); + console.log({ res }); +} + +main().catch(console.error); diff --git a/packages/oraiswap-v3/src/types.ts b/packages/oraiswap-v3/src/types.ts index b7d6c89c..2fa4655a 100644 --- a/packages/oraiswap-v3/src/types.ts +++ b/packages/oraiswap-v3/src/types.ts @@ -1,3 +1,7 @@ +import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { TokenItemType } from "@oraichain/oraidex-common"; +import { Asset, Route, SwapOperation, Uint128 } from "@oraichain/oraidex-contracts-sdk/build/Zapper.types"; + export interface SnapshotValueData { tokenBNFromBeginning: string; usdValue24: number; @@ -181,3 +185,121 @@ export interface CalculateSwapResult { state_outdated: boolean; max_ticks_crossed: boolean; } + +export type ZapConfig = { + routerApi: string; + client: CosmWasmClient; + dexV3Address: string; + multiCallAddress: string; + deviation: number; + smartRouteConfig: SmartRouteConfig; +}; + +export type ActionRoute = { + type: string; + protocol: Protocols; + tokenIn: string; + tokenInAmount: string; + tokenOut: string; + tokenOutAmount: string; + swapInfo: Path[]; +}; + +export type Path = { + poolId: string; + tokenOut: string; +}; + +export type RouteResponse = { + swapAmount: string; + returnAmount: string; + paths: { + chainId: string; + tokenIn: string; + tokenInAmount: string; + tokenOut: string; + tokenOutAmount: string; + tokenOutChainId: string; + actions: ActionRoute[]; + }[]; +}; + +export type SmartRouteResponse = { + swapAmount: string; + returnAmount: string; + routes: RouteResponse[]; +}; + +export type Protocols = "Oraidex" | "OraidexV3" | "Osmosis"; + +export type SmartRouteConfig = { + swapOptions: { + protocols: Protocols[]; + maxSplits?: number; + }; +}; + +export type SmartRouteReponse = { + swapAmount: string; + returnAmount: string; + routes: any[]; +}; + +export type ZapInLiquidityResponse = { + minimumLiquidity?: Liquidity; + routes: Route[]; + + amountToX: Uint128; + amountToY: Uint128; + assetIn: Asset; + minimumReceiveX?: Uint128; + minimumReceiveY?: Uint128; + poolKey: PoolKey; + tickLowerIndex: number; + tickUpperIndex: number; + amountX: Uint128; + amountY: Uint128; + sqrtPrice: bigint; + currentTick: number; + + swapFee: number; + result: ZapInResult; +}; + +export type ZapOutLiquidityResponse = { + minimumReceiveX?: Uint128; + minimumReceiveY?: Uint128; + operationFromX?: SwapOperation[]; + operationFromY?: SwapOperation[]; + positionIndex: number; + routes: Route[]; + swapFee: number; + amountToX: bigint; + amountToY: bigint; + result: ZapOutResult; +}; + +export enum ZapInResult { + // Error + NoRouteFound = "No route found to zap", + SomethingWentWrong = "Something went wrong", + + // in range + InRangeNoRouteThroughSelf = "This zap operation has no swap through this pool and the position is in range so the accurancy is good", + InRangeHasRouteThroughSelf = "This zap operation has swap through this pool and the position is in range so the accurancy is good", + InRangeHasRouteThroughSelfMayBecomeOutRange = "This zap operation has swap through this pool and the position is in range but the next tick is out of range so the accurancy is low", + + // out range + OutRangeNoRouteThroughSelf = "This zap operation has no swap through this pool and the position is out of range so the accurancy is good", + OutRangeHasRouteThroughSelf = "This zap operation has swap through this pool and the position is out of range but the next tick is not in range so the accurancy is good", + OutRangeHasRouteThroughSelfMayBecomeInRange = "This zap operation has swap through this pool and the position is out of range but the next tick is in range so the accurancy is low" +} + +export enum ZapOutResult { + // Error + NoRouteFound = "No route found to zap", + SomethingWentWrong = "Something went wrong", + + // Success + Success = "Zap out successfully" +} diff --git a/packages/oraiswap-v3/src/zap-consumer.ts b/packages/oraiswap-v3/src/zap-consumer.ts new file mode 100644 index 00000000..97281fde --- /dev/null +++ b/packages/oraiswap-v3/src/zap-consumer.ts @@ -0,0 +1,609 @@ +import { BigDecimal, oraichainTokens, parseAssetInfo, TokenItemType } from "@oraichain/oraidex-common"; +import { OraiswapV3Handler } from "./handler"; +import { + ActionRoute, + CalculateSwapResult, + LiquidityTick, + PoolKey, + SmartRouteConfig, + SmartRouteResponse, + Tickmap, + ZapConfig, + ZapInLiquidityResponse, + ZapInResult, + ZapOutLiquidityResponse, + ZapOutResult +} from "./types"; +import { + getLiquidityByX, + getLiquidityByY, + getMaxSqrtPrice, + getMinSqrtPrice, + getTickAtSqrtPrice, + simulateSwap +} from "./wasm/oraiswap_v3_wasm"; +import { + buildZapOutMessage, + calculateMinimumLiquidity, + calculateRewardAmounts, + calculateSwapFee, + calculateTokenAmounts, + extractAddress, + extractOraidexV3Actions, + generateMessageSwapOperation, + getFeeRate, + parseAsset, + poolKeyToString, + populateMessageZapIn, + shiftDecimal +} from "./helpers"; +import { Pool } from "@oraichain/oraidex-contracts-sdk/build/OraiswapV3.types"; +import { RouteNotFoundError } from "./error"; + +/** Read the flow chart below to understand the process of the ZapConsumer +Flow ref: https://lucid.app/lucidchart/11f8ee36-ee71-4f46-8028-a953ac4f5e87/edit?viewport_loc=-3263%2C-2130%2C3114%2C1694%2C0_0&invitationId=inv_cbe9b842-b255-4c8a-824e-2bc78a6f3860 + */ + +export class ZapConsumer { + private _router: string; + private _handler: OraiswapV3Handler; + private _smartRouteConfig: SmartRouteConfig; + private _deviation: number; + + constructor(config: ZapConfig) { + this._router = config.routerApi; + this._handler = new OraiswapV3Handler(config.client, config.dexV3Address, config.multiCallAddress); + this._smartRouteConfig = config.smartRouteConfig; + this._deviation = config.deviation; + } + + public get handler(): OraiswapV3Handler { + return this._handler; + } + + private async getPriceInfo({ + sourceAsset, + destAsset + }: { + sourceAsset: TokenItemType; + destAsset: TokenItemType; + }): Promise { + try { + if (sourceAsset.name === destAsset.name) + return { + swapAmount: (10n ** BigInt(sourceAsset.decimals)).toString(), + returnAmount: (10n ** BigInt(sourceAsset.decimals)).toString(), + routes: null + }; + const res = await fetch(this._router, { + method: "POST", + body: JSON.stringify({ + sourceAsset: extractAddress(sourceAsset), + sourceChainId: sourceAsset.chainId, + destAsset: extractAddress(destAsset), + destChainId: destAsset.chainId, + offerAmount: (10n ** BigInt(sourceAsset.decimals)).toString(), + swapOptions: this._smartRouteConfig.swapOptions + }), + headers: { + "Content-Type": "application/json" + } + }); + + return JSON.parse(await res.text()); + } catch (e) { + console.log(`[ZapConsumer] getPriceInfo error: ${e}`); + throw new RouteNotFoundError(e); + } + } + + private async findRoute({ + sourceAsset, + destAsset, + amount + }: { + sourceAsset: TokenItemType; + destAsset: TokenItemType; + amount: bigint; + }): Promise { + try { + if (amount === 0n) { + return { + swapAmount: "0", + returnAmount: "0", + routes: null + }; + } + if (sourceAsset.name === destAsset.name) + return { + swapAmount: amount.toString(), + returnAmount: amount.toString(), + routes: null + }; + const res = await fetch(this._router, { + method: "POST", + body: JSON.stringify({ + sourceAsset: extractAddress(sourceAsset), + sourceChainId: sourceAsset.chainId, + destAsset: extractAddress(destAsset), + destChainId: destAsset.chainId, + offerAmount: amount.toString(), + swapOptions: this._smartRouteConfig.swapOptions + }), + headers: { + "Content-Type": "application/json" + } + }); + + return JSON.parse(await res.text()); + } catch (e) { + console.log(`[ZapConsumer] getPriceInfo error: ${e}`); + throw new RouteNotFoundError(e); + } + } + + private async findZapOutRoutes( + pool: any, + tokenOut: TokenItemType, + rewardAmounts: Record + ): Promise<{ + xRouteInfo: SmartRouteResponse; + yRouteInfo: SmartRouteResponse; + }> { + const xRouteInfoPromise = this.findRoute({ + sourceAsset: oraichainTokens.find((t) => extractAddress(t) === pool.pool_key.token_x), + destAsset: tokenOut, + amount: rewardAmounts[pool.pool_key.token_x] + }); + const yRouteInfoPromise = this.findRoute({ + sourceAsset: oraichainTokens.find((t) => extractAddress(t) === pool.pool_key.token_y), + destAsset: tokenOut, + amount: rewardAmounts[pool.pool_key.token_y] + }); + const [xRouteInfo, yRouteInfo] = await Promise.all([xRouteInfoPromise, yRouteInfoPromise]); + return { xRouteInfo, yRouteInfo }; + } + + private async findZapInRoutes( + tokenIn: TokenItemType, + tokenX: TokenItemType, + tokenY: TokenItemType, + amountInToX: bigint, + amountInToY: bigint + ) { + const xRouteInfoPromise = this.findRoute({ + sourceAsset: tokenIn, + destAsset: tokenX, + amount: amountInToX + }); + const yRouteInfoPromise = this.findRoute({ + sourceAsset: tokenIn, + destAsset: tokenY, + amount: amountInToY + }); + const [xRouteInfo, yRouteInfo] = await Promise.all([xRouteInfoPromise, yRouteInfoPromise]); + return { xRouteInfo, yRouteInfo }; + } + + private async simulateSwapOffChain(poolKey: PoolKey, pool: Pool, route: ActionRoute): Promise { + const isXToY = route.tokenOut === poolKey.token_x ? false : true; + const amountOut = route.tokenOutAmount; + const tickMap = await this._handler.getFullTickmap(poolKey); + const liquidityTicks = await this._handler.getAllLiquidityTicks(poolKey, tickMap); + const convertLiquidityTicks = liquidityTicks.map((tick) => { + return { + ...tick, + liquidity_change: BigInt(tick.liquidity_change), + } + }); + const convertPool = { + ...pool, + liquidity: BigInt(pool.liquidity), + sqrt_price: BigInt(pool.sqrt_price), + fee_growth_global_x: BigInt(pool.fee_growth_global_x), + fee_growth_global_y: BigInt(pool.fee_growth_global_y), + fee_protocol_token_x: BigInt(pool.fee_protocol_token_x), + fee_protocol_token_y: BigInt(pool.fee_protocol_token_y) + }; + const swapResult = simulateSwap( + tickMap, + poolKey.fee_tier, + convertPool, + convertLiquidityTicks, + isXToY, + BigInt(amountOut), + false, + isXToY ? getMinSqrtPrice(poolKey.fee_tier.tick_spacing) : getMaxSqrtPrice(poolKey.fee_tier.tick_spacing) + ); + return swapResult; + } + + private async processZapInWithSingleSide({ + poolKey, + pool, + sqrtPrice, + tokenIn, + amountIn, + lowerTick, + upperTick, + tokenX, + tokenY, + slippage = 1 + }: { + poolKey: PoolKey; + pool: Pool; + sqrtPrice: bigint; + tokenIn: TokenItemType; + amountIn: string; + lowerTick: number; + upperTick: number; + tokenX: TokenItemType; + tokenY: TokenItemType; + slippage?: number; + }): Promise { + try { + let tokenNeed: TokenItemType; + let isTokenX: boolean = true; + if (upperTick < pool.current_tick_index) { + tokenNeed = tokenY; + isTokenX = false; + } else { + tokenNeed = tokenX; + } + + const actualReceive = await this.findRoute({ + sourceAsset: tokenIn, + destAsset: tokenNeed, + amount: BigInt(amountIn) + }); + + const routes: ActionRoute[] = extractOraidexV3Actions(actualReceive.routes); + + let simulatedNextSqrtPrice = BigInt(pool.sqrt_price); + let simulateNextTick = pool.current_tick_index; + for (const route of routes) { + if (route.swapInfo.find((swap) => swap.poolId === poolKeyToString(poolKey))) { + const swapResult = await this.simulateSwapOffChain(poolKey, pool, route); + + pool.sqrt_price = ((BigInt(pool.sqrt_price) + BigInt(swapResult.target_sqrt_price)) / 2n).toString(); + const tick = getTickAtSqrtPrice(BigInt(pool.sqrt_price), poolKey.fee_tier.tick_spacing); + pool.current_tick_index = (simulateNextTick + tick) / 2; + simulatedNextSqrtPrice = BigInt(pool.sqrt_price); + simulateNextTick = pool.current_tick_index; + } + } + + let message: ZapInLiquidityResponse = {} as ZapInLiquidityResponse; + message.assetIn = parseAsset(tokenIn, amountIn); + if (isTokenX) { + message.amountToX = amountIn; + message.amountToY = "0"; + message.amountX = actualReceive.returnAmount; + message.amountY = "0"; + } else { + message.amountToX = "0"; + message.amountToY = amountIn; + message.amountX = "0"; + message.amountY = actualReceive.returnAmount; + } + message.poolKey = poolKey; + message.sqrtPrice = BigInt(pool.sqrt_price); + message.tickLowerIndex = lowerTick; + message.tickUpperIndex = upperTick; + const routesNeed = generateMessageSwapOperation([actualReceive], slippage); + message.routes = [...routesNeed]; + message.swapFee = 0; + message.routes.forEach((route) => { + route.operations.forEach((operation) => { + message.swapFee += getFeeRate(operation); + }); + }); + const res = isTokenX + ? getLiquidityByX(BigInt(actualReceive.returnAmount), lowerTick, upperTick, BigInt(pool.sqrt_price), true) + : getLiquidityByY(BigInt(actualReceive.returnAmount), lowerTick, upperTick, BigInt(pool.sqrt_price), true); + message.minimumLiquidity = res.l ? (BigInt(res.l) * BigInt(100 - slippage)) / 100n : 0n; + + if (sqrtPrice === BigInt(pool.sqrt_price)) { + message.result = ZapInResult.OutRangeNoRouteThroughSelf; + return message; + } + + if (simulateNextTick < upperTick && simulateNextTick >= lowerTick) { + message.result = ZapInResult.OutRangeHasRouteThroughSelfMayBecomeInRange; + message.currentTick = simulateNextTick; + message.sqrtPrice = simulatedNextSqrtPrice; + + return message; + } else { + message.result = ZapInResult.OutRangeHasRouteThroughSelf; + return message; + } + } catch (e) { + console.log(`[ZapConsumer] processZapInWithSingleSide error: ${e}`); + const message: ZapInLiquidityResponse = {} as ZapInLiquidityResponse; + if (e instanceof RouteNotFoundError) { + message.result = ZapInResult.NoRouteFound; + } else { + message.result = ZapInResult.SomethingWentWrong; + } + return message; + } + } + + public async processZapInPositionLiquidity({ + poolKey, + tokenIn, + tokenX, + tokenY, + amountIn, + lowerTick, + upperTick, + slippage = 1 + }: { + poolKey: PoolKey; + tokenIn: TokenItemType; + tokenX: TokenItemType; + tokenY: TokenItemType; + amountIn: string; + lowerTick: number; + upperTick: number; + slippage?: number; + }): Promise { + try { + const pool = await this.handler.getPool(poolKey); + const sqrtPrice = BigInt(pool.pool.sqrt_price); + + let zapResult: ZapInResult; + let result: ZapInLiquidityResponse; + + if (lowerTick > pool.pool.current_tick_index || upperTick <= pool.pool.current_tick_index) { + result = await this.processZapInWithSingleSide({ + poolKey, + pool: pool.pool, + sqrtPrice, + tokenIn, + amountIn, + lowerTick, + upperTick, + tokenX, + tokenY, + slippage + }); + } + + if (result) { + if (result.result !== ZapInResult.OutRangeHasRouteThroughSelfMayBecomeInRange) { + return result; + } else { + pool.pool.current_tick_index = result.currentTick; + pool.pool.sqrt_price = BigInt(pool.pool.sqrt_price).toString(); + } + } + + const { amount: yPerX, l: liquidity } = getLiquidityByX( + 10n ** BigInt(tokenX.decimals), + lowerTick, + upperTick, + sqrtPrice, + true + ); + let m3 = shiftDecimal(BigInt(yPerX.toString()), tokenY.decimals); + let m1 = new BigDecimal(1); + let m2 = new BigDecimal(1); + const getXPriceByTokenInPromise = this.getPriceInfo({ + sourceAsset: tokenX, + destAsset: tokenIn + }); + const getYPriceByTokenInPromise = this.getPriceInfo({ + sourceAsset: tokenY, + destAsset: tokenIn + }); + const [getXPriceByTokenIn, getYPriceByTokenIn] = await Promise.all([ + getXPriceByTokenInPromise, + getYPriceByTokenInPromise + ]); + if (![poolKey.token_x, poolKey.token_y].includes(extractAddress(tokenIn))) { + m1 = shiftDecimal(BigInt(getXPriceByTokenIn.returnAmount), tokenIn.decimals); + m2 = shiftDecimal(BigInt(getYPriceByTokenIn.returnAmount), tokenIn.decimals); + } else { + if (extractAddress(tokenIn) === poolKey.token_x) { + m2 = shiftDecimal(BigInt(getYPriceByTokenIn.returnAmount), tokenIn.decimals); + } else { + m1 = shiftDecimal(BigInt(getXPriceByTokenIn.returnAmount), tokenIn.decimals); + } + } + let x = new BigDecimal(amountIn).div(m1.add(m2.mul(m3))); + let y = x.mul(m3); + let amountX = Math.round(x.toNumber()); + let amountY = Math.round(y.toNumber()); + let amountInToX = BigInt(Math.round(x.mul(m1).toNumber())); + let amountInToY = BigInt(amountIn) - amountInToX; + + const actualAmountXReceivedPromise = this.findRoute({ + sourceAsset: tokenIn, + destAsset: tokenX, + amount: amountInToX + }); + const actualAmountYReceivedPromise = this.findRoute({ + sourceAsset: tokenIn, + destAsset: tokenY, + amount: amountInToY + }); + const [actualAmountXReceived, actualAmountYReceived] = await Promise.all([ + actualAmountXReceivedPromise, + actualAmountYReceivedPromise + ]); + const routes: ActionRoute[] = extractOraidexV3Actions([ + ...actualAmountXReceived.routes, + ...actualAmountYReceived.routes + ]); + + zapResult = ZapInResult.InRangeNoRouteThroughSelf; + let simulatedNextSqrtPrice = BigInt(pool.pool.sqrt_price); + let simulatedNextTick = pool.pool.current_tick_index; + for (const route of routes) { + if (route.swapInfo.find((swap) => swap.poolId === poolKeyToString(poolKey))) { + const swapResult = await this.simulateSwapOffChain(poolKey, pool.pool, route); + + pool.pool.sqrt_price = ( + (BigInt(pool.pool.sqrt_price) + BigInt(swapResult.target_sqrt_price)) / + 2n + ).toString(); + const tick = getTickAtSqrtPrice(BigInt(pool.pool.sqrt_price), poolKey.fee_tier.tick_spacing); + pool.pool.current_tick_index = (simulatedNextTick + tick) / 2; + simulatedNextTick = pool.pool.current_tick_index; + simulatedNextSqrtPrice = BigInt(pool.pool.sqrt_price); + } + } + + let liquidityAfter = liquidity; + if (sqrtPrice !== BigInt(pool.pool.sqrt_price)) { + zapResult = ZapInResult.InRangeHasRouteThroughSelf; + if (simulatedNextTick > upperTick || simulatedNextTick < lowerTick) { + zapResult = ZapInResult.InRangeHasRouteThroughSelfMayBecomeOutRange; + + const message: ZapInLiquidityResponse = {} as ZapInLiquidityResponse; + message.result = zapResult; + populateMessageZapIn( + message, + tokenIn, + amountIn, + amountInToX, + amountInToY, + actualAmountXReceived, + actualAmountYReceived, + poolKey, + pool.pool, + lowerTick, + upperTick, + slippage + ); + calculateSwapFee(message); + calculateMinimumLiquidity( + message, + actualAmountXReceived, + actualAmountYReceived, + lowerTick, + upperTick, + sqrtPrice, + slippage + ); + return message; + } + + const { amount: yPerXAfter, liquidityAfter: l } = await getLiquidityByX( + 10n ** BigInt(tokenX.decimals), + lowerTick, + upperTick, + BigInt(pool.pool.sqrt_price), + true + ); + liquidityAfter = l; + m3 = shiftDecimal(BigInt(yPerXAfter.toString()), tokenY.decimals); + x = new BigDecimal(amountIn).div(m1.add(m2.mul(m3))); + y = x.mul(m3); + amountX = Math.round(x.toNumber()); + amountY = Math.round(y.toNumber()); + amountInToX = BigInt(Math.round(x.mul(m1).toNumber())); + amountInToY = BigInt(amountIn) - amountInToX; + } + + const diffX = Math.abs(Number(actualAmountXReceived.returnAmount) - amountX) / amountX; + const diffY = Math.abs(Number(actualAmountYReceived.returnAmount) - amountY) / amountY; + if (diffX > this._deviation || diffY > this._deviation) { + const x1 = new BigDecimal(actualAmountXReceived.returnAmount); + const y1 = new BigDecimal(actualAmountYReceived.returnAmount); + const xPriceByY = await this.getPriceInfo({ + sourceAsset: tokenX, + destAsset: tokenY + }); + const m4 = shiftDecimal(BigInt(xPriceByY.returnAmount), tokenY.decimals); + const deltaX = y1.sub(m3.mul(x1)).div(m3.add(m4)); + amountInToX += BigInt(Math.round(deltaX.mul(m1).toNumber())); + amountInToY = BigInt(amountIn) - amountInToX; + } + + const { xRouteInfo, yRouteInfo } = await this.findZapInRoutes(tokenIn, tokenX, tokenY, amountInToX, amountInToY); + + const messages: ZapInLiquidityResponse = {} as ZapInLiquidityResponse; + messages.result = result ? result.result : zapResult; + + populateMessageZapIn( + messages, + tokenIn, + amountIn, + amountInToX, + amountInToY, + xRouteInfo, + yRouteInfo, + poolKey, + pool.pool, + lowerTick, + upperTick, + slippage + ); + calculateSwapFee(messages); + calculateMinimumLiquidity( + messages, + xRouteInfo, + yRouteInfo, + lowerTick, + upperTick, + BigInt(pool.pool.sqrt_price), + slippage + ); + + return messages; + } catch (e) { + console.log(`[ZapConsumer] processZapInPositionLiquidity error: ${e}`); + const message: ZapInLiquidityResponse = {} as ZapInLiquidityResponse; + if (e instanceof RouteNotFoundError) { + message.result = ZapInResult.NoRouteFound; + } else { + message.result = ZapInResult.SomethingWentWrong; + } + return message; + } + } + + public async processZapOutPositionLiquidity({ + tokenId, + owner, + tokenOut, + slippage = 1, + zapFee + }: { + tokenId: number; + owner: string; + tokenOut: TokenItemType; + slippage?: number; + zapFee: number; + }): Promise { + try { + const rewardAmounts: Record = {}; + const positions = await this._handler.getPositions(owner); + let index = 0; + const position = positions.find((p, i) => { + index = i; + return p.token_id === tokenId; + }); + const pool = await this._handler.getPool(position.pool_key); + const { amountX, amountY } = calculateRewardAmounts(pool, position, zapFee); + + rewardAmounts[pool.pool_key.token_x] = amountX; + rewardAmounts[pool.pool_key.token_y] = amountY; + + const { xRouteInfo, yRouteInfo } = await this.findZapOutRoutes(pool, tokenOut, rewardAmounts); + + return buildZapOutMessage(ZapOutResult.Success, index, xRouteInfo, yRouteInfo, slippage); + } catch (e) { + const message: ZapOutLiquidityResponse = {} as ZapOutLiquidityResponse; + console.log(`error: ${e}`); + if (e instanceof RouteNotFoundError) { + message.result = ZapOutResult.NoRouteFound; + } else { + message.result = ZapOutResult.SomethingWentWrong; + } + } + } +} diff --git a/packages/oraiswap-v3/tests/handler.spec.ts b/packages/oraiswap-v3/tests/handler.spec.ts index bedf696a..9338c7f0 100644 --- a/packages/oraiswap-v3/tests/handler.spec.ts +++ b/packages/oraiswap-v3/tests/handler.spec.ts @@ -4,10 +4,9 @@ import { bobAddress, client, createTokens, senderAddress } from "./test-common"; import fs from "fs"; import path from "path"; import { OraiswapV3Handler, poolKeyToString } from "../src"; -import { expect, afterAll, beforeAll, describe, it, beforeEach } from "vitest"; +import { expect, describe, it, beforeEach } from "vitest"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); -console.log("__filename: ", __filename); const __dirname = path.dirname(__filename); describe("test oraiswap-v3 handler functions", () => { diff --git a/packages/oraiswap-v3/tests/zap-consumer.spec.ts b/packages/oraiswap-v3/tests/zap-consumer.spec.ts new file mode 100644 index 00000000..794512b3 --- /dev/null +++ b/packages/oraiswap-v3/tests/zap-consumer.spec.ts @@ -0,0 +1,61 @@ +import path from "path"; +import { fileURLToPath } from "url"; +import { ZapConsumer } from "../src/zap-consumer"; +import { OraiswapV3Client, OraiswapV3Types } from "@oraichain/oraidex-contracts-sdk"; +import fs from "fs"; +import { describe, it, beforeEach } from "vitest"; +import { client } from "./test-common"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const admin = "orai1swus8mwu8xjulawqxdwh8hvg4gknh2c64tuc0k"; +const alice = "orai1g4h64yjt0fvzv5v2j8tyfnpe5kmnetejvfgs7g"; +const bob = "orai1602dkqjvh4s7ryajnz2uwhr8vetrwr8nekpxv5"; + +describe("ZapConsumer", () => { + // init dex + let protocolFee = 250000000000; + let dex: OraiswapV3Client; + let zapper: ZapConsumer; + + beforeEach(async () => { + const { codeId: dexCodeId } = await client.upload( + admin, + fs.readFileSync(path.resolve(__dirname, "data", "oraiswap-v3.wasm")), + "auto" + ); + + const { codeId: multicalCodeId } = await client.upload( + admin, + fs.readFileSync(path.resolve(__dirname, "data", "multicall.wasm")), + "auto" + ); + + const { contractAddress: multicallAddress } = await client.instantiate( + admin, + multicalCodeId, + {}, + "multicall", + "auto" + ); + + dex = new OraiswapV3Client( + client, + admin, + ( + await client.instantiate( + admin, + dexCodeId, + { protocol_fee: protocolFee } as OraiswapV3Types.InstantiateMsg, + "oraiswap_v3", + "auto" + ) + ).contractAddress + ); + }); + + it("work", async () => { + console.log("hello"); + }); +}); diff --git a/packages/oraiswap-v3/tsconfig.json b/packages/oraiswap-v3/tsconfig.json index bebe2ca5..1c026311 100644 --- a/packages/oraiswap-v3/tsconfig.json +++ b/packages/oraiswap-v3/tsconfig.json @@ -1,16 +1,11 @@ { - "extends": "../../tsconfig.json", - "compilerOptions": { - "baseUrl": ".", - "outDir": "build", - "declaration": true, - "rootDir": "src" - }, - "include": [ - "src/**/*.ts", - "src/**/*.js", - ], - "exclude": [ - "node_modules/", - ] -} \ No newline at end of file + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "declaration": true, + "rootDir": "src" + }, + "include": ["src/**/*.ts", "src/**/*.js"], + "exclude": ["node_modules/", "src/main.ts"] +} diff --git a/packages/oraiswap-v3/tsconfig.test.json b/packages/oraiswap-v3/tsconfig.test.json new file mode 100644 index 00000000..33df60bb --- /dev/null +++ b/packages/oraiswap-v3/tsconfig.test.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "declaration": true, + "rootDir": "src", + "module": "es2020" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules/"] +} diff --git a/packages/universal-swap/tests/index.spec.ts b/packages/universal-swap/tests/index.spec.ts index 4920c72a..a0bac85f 100644 --- a/packages/universal-swap/tests/index.spec.ts +++ b/packages/universal-swap/tests/index.spec.ts @@ -1850,7 +1850,7 @@ describe("test universal swap handler functions", () => { "0" ] ])( - "test-caculate-minimum-rceive-ibc-wasm", + "test-caculate-minimum-receive-ibc-wasm", async (originalToToken, simulateAmount, relayerFee, bridgeFee, expectResult) => { const universalSwap = new FakeUniversalSwapHandler({ ...universalSwapData, diff --git a/yarn.lock b/yarn.lock index ea6f0b20..8612f5c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1617,6 +1617,28 @@ dependencies: apache-arrow "^13.0.0" +"@emnapi/core@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.2.0.tgz#7b738e5033738132bf6af0b8fae7b05249bdcbd7" + integrity sha512-E7Vgw78I93we4ZWdYCb4DGAwRROGkMIXk7/y87UmANR+J6qsWusmC3gLt0H+O0KOt5e6O38U8oJamgbudrES/w== + dependencies: + "@emnapi/wasi-threads" "1.0.1" + tslib "^2.4.0" + +"@emnapi/runtime@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.2.0.tgz#71d018546c3a91f3b51106530edbc056b9f2f2e3" + integrity sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz#d7ae71fd2166b1c916c6cd2d0df2ef565a2e1a5b" + integrity sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw== + dependencies: + tslib "^2.4.0" + "@emotion/use-insertion-effect-with-fallbacks@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" @@ -2956,6 +2978,15 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@napi-rs/wasm-runtime@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz#d27788176f250d86e498081e3c5ff48a17606918" + integrity sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ== + dependencies: + "@emnapi/core" "^1.1.0" + "@emnapi/runtime" "^1.1.0" + "@tybys/wasm-util" "^0.9.0" + "@ndelangen/get-tarball@^3.0.7": version "3.0.9" resolved "https://registry.yarnpkg.com/@ndelangen/get-tarball/-/get-tarball-3.0.9.tgz#727ff4454e65f34707e742a59e5e6b1f525d8964" @@ -3319,14 +3350,6 @@ dependencies: "@nx/devkit" "18.1.3" -"@nrwl/tao@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-18.1.2.tgz#5a05befc9260cae8c7f38ec83669f4ffbfd83f3b" - integrity sha512-IA+osZ5TlKMwJmcP7TECW7TO0JdNNQud9Dgkh1ZfJ4GWnT7WEkE9b2Yf1IFeeB81kCTXXq8jfISa8ZY21MjRaQ== - dependencies: - nx "18.1.2" - tslib "^2.3.0" - "@nrwl/tao@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-18.1.3.tgz#118c1b27530b44d11a0bcaa17a79c69e7c36a1b2" @@ -3335,6 +3358,14 @@ nx "18.1.3" tslib "^2.3.0" +"@nrwl/tao@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-19.7.3.tgz#1771861d0f8aeedda6bc336422ab736e4351a53b" + integrity sha512-cIGhnSFPZdVTp4bI0fqwFoE9i7ToPg5jXz+hNMl/MTwcOQfKQ1JJY/ZPLM3aBUPORFIZ/GECQEycUb6+xCB56g== + dependencies: + nx "19.7.3" + tslib "^2.3.0" + "@nx/devkit@18.1.3", "@nx/devkit@>=17.1.2 < 19": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/devkit/-/devkit-18.1.3.tgz#2f59462c6436919efdcad74f3b6f44dabc061393" @@ -3349,106 +3380,106 @@ tslib "^2.3.0" yargs-parser "21.1.1" -"@nx/nx-darwin-arm64@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.1.2.tgz#8c6d020d744e52900b215d180ad29c2873dc4acd" - integrity sha512-KduC9WBmeTLP8HyTg4NOgQGLk9LEd5qd9dGuYKPU0jA4b+eJIa0rRHEjFdc5WulQrcUAvTIKfmScRCgzR96ogg== - "@nx/nx-darwin-arm64@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.1.3.tgz#a0640946fc3f5ef447018a9d5d838678659601dc" integrity sha512-h3/1ywpLa56RwBnz8Lr9yyUvPvfGvKFxIo8LNptc8fMoONuuIOeZTAmaBxKBOaKtL7g64/LKDs0Ts+mSXzmbqA== -"@nx/nx-darwin-x64@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-18.1.2.tgz#7247cbea93ea2b8c9ad7d22b1f25374454543589" - integrity sha512-mBf3X8m4P4QHoW8g/L/YoK8zkndDyIw4bojLg8Q3xc47s5JZFCqSSMeOXZ9NicM2DpPiDWSQALtQX7A8lIsoAA== +"@nx/nx-darwin-arm64@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.7.3.tgz#d48031ac741660d99c8f4499f95b6ca68268ce56" + integrity sha512-0dDK0UkMR0vBv4AP/48Q9A+OC2dvpivdt8su/4W/CPADy69M9B5O3jPiK+jTRsLshQG/soC9JG0Rll1BNWymPg== "@nx/nx-darwin-x64@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-18.1.3.tgz#67411f01a0b75c7d1dce18999b376403fb7a0510" integrity sha512-6LHe7MYrKlztLlKhYfGV3CtFPhEqcc2ZgwGVWYiAmS/glcN+Wai7RFQX/cZiJ+TbDRFzvETPPGNRP/aSAOkRnQ== -"@nx/nx-freebsd-x64@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.1.2.tgz#cddc5e345f100a8fa88ff4e39e0e253f843ef3f7" - integrity sha512-ZqzT2BTsOHhWip1PvNm7AZ4Pzn4I+IZNRvtRgpETYvIH+nqoCmi5rrEi1avnhnr6P5hyzh2mISRSyk186SbZew== +"@nx/nx-darwin-x64@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-darwin-x64/-/nx-darwin-x64-19.7.3.tgz#9e6faae8a8698b8b8fbbb10e0fc13191a6f680c8" + integrity sha512-hTdv5YY2GQTdT7GwVO7ST27ZzvCmAQvmkEapfnCdy74QsL4gapaXJFvtWLHVfG6qHNRHWXbpdegvR3VswRHZVQ== "@nx/nx-freebsd-x64@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.1.3.tgz#a0e8f27cf3d5dc3991243b6c2278fcc564ce5fad" integrity sha512-ppSkJJVKnfDWYJBKqjEM/p4qdMZsZVV++dkFN/n50p6uwHstv0Kth7dNdsu3ZyPqmg6+IYUZql7JSTeNqKne5A== -"@nx/nx-linux-arm-gnueabihf@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.1.2.tgz#4a1a5de3bc3ca2d8525259ea5c15ff1ca779cdcb" - integrity sha512-V9Dp9uuuce+/f50dXxaYz1C9ULo5+5VS35yc6gN7b6SchCWjNK+xg1YcHBTRNc2ChBtayO2z+mBQ1s6wMDNs/Q== +"@nx/nx-freebsd-x64@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.7.3.tgz#b9a0357906371c2d5ad55ebe8b59b721aad0650b" + integrity sha512-dwuB/3eoV2RbD0b0LHnagQOXa9PKAjLi7g5vNxzw6LuNT1tdaLaUZZGv2tfG0hHjsV0cOaAX41rEyOIwJyE7zg== "@nx/nx-linux-arm-gnueabihf@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.1.3.tgz#22e39addc7834b87735681a4969b834deb5a8efa" integrity sha512-1vflQE4gscHq2GJeu2L48Z8rQFcdu+gcprG1cMEf3CIDxh/nJei66bdVJYYYxPNi6rYaeONPJgBjbIih8ce8nQ== -"@nx/nx-linux-arm64-gnu@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.1.2.tgz#cbb2624d0d245242a09f90715eaabcfb4c8be804" - integrity sha512-aM860T4Hy2JCLcU56mtARIp1MdT1Ms7cGUQzE+a5irM8ZdaHsPdRnYqIgEKd3hoF6PQ6/piHFXWa4xm7pe/2KA== +"@nx/nx-linux-arm-gnueabihf@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.7.3.tgz#7d0b416c6fc7d16e7c9242256e949e05176f4cd3" + integrity sha512-X/eG3IqvIxlCfIOiCQKv7RKwra54I+SN9zj2TeSOtd/uK0paa3mYSlGUJqoP3wpzasW1+EPIGkTQqV283IA15w== "@nx/nx-linux-arm64-gnu@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.1.3.tgz#720b786a691c005df9ce17f4efc42cd8063566e5" integrity sha512-7B5YXjDzzFdEMUzhFifXgsg741Afp3v7vNdPL2joQ7xrERKYEge7eXCjp5/GYhl9J4y5BmdeV2Joqr4WQ6R7Pg== -"@nx/nx-linux-arm64-musl@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.1.2.tgz#a99fd2898030bca1be14077e2e23ec3122c369c1" - integrity sha512-BgBoOeIgCQ56xii7fKNWiE7UIP/0G+OQhdWJQmh+q6NN0kk78WsdCSq+f7f7LQIji5HiNqUUVx9fd1s6xRSb/w== +"@nx/nx-linux-arm64-gnu@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.7.3.tgz#8b7bcb5db0f4ff928d66ee1f34d8779969fc32ad" + integrity sha512-LNaX8DVcPlFVJhMf1AAAR6j1DZF9BlVhWlilRM44tIfnmvPfKIahKJIJbuikHE7q+lkvMrQUUDXKiQJlmm/qDw== "@nx/nx-linux-arm64-musl@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.1.3.tgz#9d1d3f20a8e52bc5826f4dec3d47fd9357b7477b" integrity sha512-OaAVjUli44JUTlGPmtxZDO2U88yK6/cwt1LTbTHGeabupbXR295RDn1TkR1/1oNo8grRaOi/V9DWEg9RRmGvOw== -"@nx/nx-linux-x64-gnu@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.1.2.tgz#e80bfef4f0cf8243f18dd1aa91b4b47a915e3497" - integrity sha512-WDOjtk+K2Tc9SNjGe+zmyy05VUerZpEQ5kvB6Ude0v/W2bMnmpVrLZwwTF5Yrq0ebbUlXM/9wtc1Zjjc75MU2g== +"@nx/nx-linux-arm64-musl@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.7.3.tgz#d06cc5d688e82ec100907be47cab74860982344d" + integrity sha512-TJ9PqSebhrn8NfrW+wqMXB9N65U0L0Kjt8FfahWffNKtSAEUvhurbNhqna2Rt5WJe2qaVf6zN2pOHKhF/5pL0w== "@nx/nx-linux-x64-gnu@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.1.3.tgz#787443822c70142f009d39572cd055b55304dd32" integrity sha512-qDinHpGZ9FhoOtdfO23pwN7pBCu25ElJ1InLCeCarl9CQYS1CDZNimrcSOFl20DAZqINQamPqBFJ7nKeDRBy7g== -"@nx/nx-linux-x64-musl@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.1.2.tgz#afd9a93b306c5b8f52385a0b54de2c3573e61834" - integrity sha512-I7jTmbfR5CHC3KVlU3SkqYKJnn25MbH8pdRZJY4gaHnqL9JzbHw9rxddhKBj41lez7jQZTGLnPFUV7JPLXTzKg== +"@nx/nx-linux-x64-gnu@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.7.3.tgz#24269a68c64652b65416cfa60a0f2af8e0100d57" + integrity sha512-YMb4WGGovwgxsP6VvAEnyWvLoUwsDrdE5CxFQ2yoThD2BixmSHUKLtx6dtPDHz25nOE3v1ZzM0xTwYXBhPaeRQ== "@nx/nx-linux-x64-musl@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-18.1.3.tgz#a04a3de19b1e7579316a8fdab758f1bb4b095f31" integrity sha512-E28Q0v9N7LrV+0uu4ytrcCHfF1MPYwNL2NLZN3yCPgulGHe3NwCuMnbC974+uOZ+MTqua7KnVOQ5VYA5sL1LIw== -"@nx/nx-win32-arm64-msvc@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.1.2.tgz#490f04af286894a3e1b33fb83cd9ce1466166280" - integrity sha512-KQobKvkrdkmaJmx0Pyt2lzHkNugO0gE7q9F4h22KIECyGW1tC3nSPAB4F3mmdE2KuWKgYG5WLafvzusysLsR7g== +"@nx/nx-linux-x64-musl@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.7.3.tgz#86dab17ac802120f86fbe2de58c169e83b6d480b" + integrity sha512-zkjgDSvw2eDN+KuJBPPAPhU/lOdiMvJU0UMthJFw85dhQIYfAO8+UgiFg/qBsKo0kQ0MkhntnIPBPF8bH40qWg== "@nx/nx-win32-arm64-msvc@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.1.3.tgz#83bda8f8ee26b93ce94519ca9c150a2bb43a4a40" integrity sha512-EYHPIcanVn6ZWkELnW4wW+gl8Itulmpi7f7s83CFrYxRW0U8SAG2sW4JrlvZgrK2CMyluiCGqZGHDUJZST4CVA== -"@nx/nx-win32-x64-msvc@18.1.2": - version "18.1.2" - resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.1.2.tgz#e6587d71e529cc30376d250da0af3095300c259f" - integrity sha512-uvJvROSwHBwkTOoOPkb56jEsKJjr4LnZ3fCHmEbrtGhAUC0gAUL+dWJUDHoatrGzN+bM2VqrvgNCGkityK96hw== +"@nx/nx-win32-arm64-msvc@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.7.3.tgz#9bb07b15194ed4309dd5361fdb173216860ddc51" + integrity sha512-qCTFG6VxNvEe5JfoAELGZsjWDL4G+2NVSoSS3tByJYwVX256qgALcVoUHMjpxBn9FeOvUW9w5PL4Am4PKDdXLw== "@nx/nx-win32-x64-msvc@18.1.3": version "18.1.3" resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.1.3.tgz#cca2a2de07edb1023ef32ac5598b2f65fc2905ee" integrity sha512-1tBViAG9VQ3arKoKFOrkBzYUAGgGsVqYbifng+stb5TPWOj0jjhQpwbsk0u3ROmEBw9crWRwzRt1qh/ZE7SfQQ== +"@nx/nx-win32-x64-msvc@19.7.3": + version "19.7.3" + resolved "https://registry.yarnpkg.com/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.7.3.tgz#c5059f2cdcdccf21e103c1ab745e2781f68b8f2c" + integrity sha512-ULNf73gLgB5cU/O4dlQe6tetbRIROTmaUNYTUUCCAC0BqVwZwPDxn4u9C5LgiErVyfPwwAhlserCGei5taLASQ== + "@octokit/auth-token@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.4.tgz#70e941ba742bdd2b49bdb7393e821dea8520a3db" @@ -3626,28 +3657,6 @@ resolved "https://registry.yarnpkg.com/@oraichain/immutable/-/immutable-4.3.9.tgz#ff8d5a7b39b5b01f3f72a902cffbfea32ccb20c3" integrity sha512-INpHnhL970OCkR7I71Kssb2aLl2l4Y/x8W6FlyRO0KmC8GHjxc/hlNB1t44BiI7lkOYmcWMRQoC8dwParsp1RQ== -"@oraichain/oraidex-common@latest": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@oraichain/oraidex-common/-/oraidex-common-1.1.1.tgz#f2fe0a9509715d1875decfea3f5d2db2e11d8bca" - integrity sha512-4RznGAv3xk1gSCPOaqiq3q0cBQuHNsHMJAB0skvYpLGy14gnCMDQp9QdSPMtAIIuZVX97V/12N7NarqQ0AwIMQ== - dependencies: - "@cosmjs/amino" "0.31.3" - "@cosmjs/cosmwasm-stargate" "0.31.3" - "@cosmjs/crypto" "0.31.3" - "@cosmjs/proto-signing" "0.31.3" - "@cosmjs/stargate" "0.31.3" - "@cosmjs/tendermint-rpc" "0.31.3" - "@ethersproject/providers" "^5.0.10" - "@injectivelabs/sdk-ts" "1.12.1" - "@keplr-wallet/types" "^0.11.38" - "@oraichain/oraidex-contracts-sdk" latest - axios "1.7.2" - axios-extensions "3.1.7" - bignumber.js "^9.1.2" - cosmjs-types "0.8.0" - ethers "^5.0.15" - tronweb "6.0.0-beta.4" - "@oraichain/oraidex-contracts-sdk@latest": version "1.0.44" resolved "https://registry.yarnpkg.com/@oraichain/oraidex-contracts-sdk/-/oraidex-contracts-sdk-1.0.44.tgz#9ff41ec388dd92ba112c2eef545d11fd6e18c684" @@ -3664,11 +3673,6 @@ ethers "^5.0.15" tronweb "5.3.0" -"@oraichain/oraiswap-v3-wasm@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@oraichain/oraiswap-v3-wasm/-/oraiswap-v3-wasm-0.1.0.tgz#aff12c614635ad2c4343ef62d8497e41d52408f4" - integrity sha512-87YMqhBVgVJoX5BM+AeGc13I0dTR/hIHg6sIh+j9M/T0OecaCZR4O3h+CiaBKrK9Eej0gccv9zI02FwjAggAfw== - "@oraichain/wasm-json-toolkit@^1.0.24": version "1.0.24" resolved "https://registry.yarnpkg.com/@oraichain/wasm-json-toolkit/-/wasm-json-toolkit-1.0.24.tgz#e9a431560e8e946fbb7ec257e5f13d9320ffd23a" @@ -5239,6 +5243,13 @@ "@tufjs/canonical-json" "2.0.0" minimatch "^9.0.3" +"@tybys/wasm-util@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" + integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== + dependencies: + tslib "^2.4.0" + "@typechain/ethers-v6@^0.5.1": version "0.5.1" resolved "https://registry.yarnpkg.com/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz#42fe214a19a8b687086c93189b301e2b878797ea" @@ -6109,6 +6120,13 @@ dependencies: argparse "^2.0.1" +"@zkochan/js-yaml@0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz#4b0cb785220d7c28ce0ec4d0804deb5d821eae89" + integrity sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ== + dependencies: + argparse "^2.0.1" + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -6637,6 +6655,15 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" +axios@^1.7.4: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" @@ -8537,7 +8564,14 @@ dotenv-expand@^10.0.0, dotenv-expand@~10.0.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== -dotenv@^16.0.0, dotenv@^16.3.1, dotenv@^16.4.5: +dotenv-expand@~11.0.6: + version "11.0.6" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-11.0.6.tgz#f2c840fd924d7c77a94eff98f153331d876882d3" + integrity sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g== + dependencies: + dotenv "^16.4.4" + +dotenv@^16.0.0, dotenv@^16.3.1, dotenv@^16.4.4, dotenv@^16.4.5, dotenv@~16.4.5: version "16.4.5" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== @@ -9857,6 +9891,13 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +front-matter@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-4.0.2.tgz#b14e54dc745cfd7293484f3210d15ea4edd7f4d5" + integrity sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg== + dependencies: + js-yaml "^3.13.1" + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -12152,6 +12193,11 @@ lilconfig@^3.1.1: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.1.tgz#9d8a246fa753106cfc205fd2d77042faca56e5e3" integrity sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ== +lines-and-columns@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b" + integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -13405,12 +13451,12 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nx@18.1.2: - version "18.1.2" - resolved "https://registry.yarnpkg.com/nx/-/nx-18.1.2.tgz#e193111cbc6162e1e0afad07b24b01a960649423" - integrity sha512-E414xp6lVtiTGdDUMVo72G96G66t7oJMqmcHRMEZ/mVq5ZpNWUhfMuRq5Fh8orXPtrM3xk5SHokmmFvo5PKC+g== +nx@18.1.3, "nx@>=17.1.2 < 19": + version "18.1.3" + resolved "https://registry.yarnpkg.com/nx/-/nx-18.1.3.tgz#3ff2a6cc6f8d898793bc12ce0d731a8e1b809a8d" + integrity sha512-Ade/BZxK8kf98pBPHVJXRkxRTpBYJceL1YD9LBMP5TwmsVdG5ZbmmpTkCBorCGmCZ8L5WZN3gwoikvPKGs8q5w== dependencies: - "@nrwl/tao" "18.1.2" + "@nrwl/tao" "18.1.3" "@yarnpkg/lockfile" "^1.1.0" "@yarnpkg/parsers" "3.0.0-rc.46" "@zkochan/js-yaml" "0.0.6" @@ -13445,42 +13491,43 @@ nx@18.1.2: yargs "^17.6.2" yargs-parser "21.1.1" optionalDependencies: - "@nx/nx-darwin-arm64" "18.1.2" - "@nx/nx-darwin-x64" "18.1.2" - "@nx/nx-freebsd-x64" "18.1.2" - "@nx/nx-linux-arm-gnueabihf" "18.1.2" - "@nx/nx-linux-arm64-gnu" "18.1.2" - "@nx/nx-linux-arm64-musl" "18.1.2" - "@nx/nx-linux-x64-gnu" "18.1.2" - "@nx/nx-linux-x64-musl" "18.1.2" - "@nx/nx-win32-arm64-msvc" "18.1.2" - "@nx/nx-win32-x64-msvc" "18.1.2" + "@nx/nx-darwin-arm64" "18.1.3" + "@nx/nx-darwin-x64" "18.1.3" + "@nx/nx-freebsd-x64" "18.1.3" + "@nx/nx-linux-arm-gnueabihf" "18.1.3" + "@nx/nx-linux-arm64-gnu" "18.1.3" + "@nx/nx-linux-arm64-musl" "18.1.3" + "@nx/nx-linux-x64-gnu" "18.1.3" + "@nx/nx-linux-x64-musl" "18.1.3" + "@nx/nx-win32-arm64-msvc" "18.1.3" + "@nx/nx-win32-x64-msvc" "18.1.3" -nx@18.1.3, "nx@>=17.1.2 < 19": - version "18.1.3" - resolved "https://registry.yarnpkg.com/nx/-/nx-18.1.3.tgz#3ff2a6cc6f8d898793bc12ce0d731a8e1b809a8d" - integrity sha512-Ade/BZxK8kf98pBPHVJXRkxRTpBYJceL1YD9LBMP5TwmsVdG5ZbmmpTkCBorCGmCZ8L5WZN3gwoikvPKGs8q5w== +nx@19.7.3: + version "19.7.3" + resolved "https://registry.yarnpkg.com/nx/-/nx-19.7.3.tgz#ca76e9b9fcca9a61a1a65179daef1a3914121b0e" + integrity sha512-8F4CzKavSuOFv+uKVwXHc00Px0q40CWAYCW6NC5IgU3AMaJVumyHzgB8Sn+yfkaVgfVnZVqznOsyrbZUWuj/VA== dependencies: - "@nrwl/tao" "18.1.3" + "@napi-rs/wasm-runtime" "0.2.4" + "@nrwl/tao" "19.7.3" "@yarnpkg/lockfile" "^1.1.0" "@yarnpkg/parsers" "3.0.0-rc.46" - "@zkochan/js-yaml" "0.0.6" - axios "^1.6.0" + "@zkochan/js-yaml" "0.0.7" + axios "^1.7.4" chalk "^4.1.0" cli-cursor "3.1.0" cli-spinners "2.6.1" cliui "^8.0.1" - dotenv "~16.3.1" - dotenv-expand "~10.0.0" + dotenv "~16.4.5" + dotenv-expand "~11.0.6" enquirer "~2.3.6" figures "3.2.0" flat "^5.0.2" + front-matter "^4.0.2" fs-extra "^11.1.0" ignore "^5.0.4" jest-diff "^29.4.1" - js-yaml "4.1.0" jsonc-parser "3.2.0" - lines-and-columns "~2.0.3" + lines-and-columns "2.0.3" minimatch "9.0.3" node-machine-id "1.1.12" npm-run-path "^4.0.1" @@ -13496,16 +13543,16 @@ nx@18.1.3, "nx@>=17.1.2 < 19": yargs "^17.6.2" yargs-parser "21.1.1" optionalDependencies: - "@nx/nx-darwin-arm64" "18.1.3" - "@nx/nx-darwin-x64" "18.1.3" - "@nx/nx-freebsd-x64" "18.1.3" - "@nx/nx-linux-arm-gnueabihf" "18.1.3" - "@nx/nx-linux-arm64-gnu" "18.1.3" - "@nx/nx-linux-arm64-musl" "18.1.3" - "@nx/nx-linux-x64-gnu" "18.1.3" - "@nx/nx-linux-x64-musl" "18.1.3" - "@nx/nx-win32-arm64-msvc" "18.1.3" - "@nx/nx-win32-x64-msvc" "18.1.3" + "@nx/nx-darwin-arm64" "19.7.3" + "@nx/nx-darwin-x64" "19.7.3" + "@nx/nx-freebsd-x64" "19.7.3" + "@nx/nx-linux-arm-gnueabihf" "19.7.3" + "@nx/nx-linux-arm64-gnu" "19.7.3" + "@nx/nx-linux-arm64-musl" "19.7.3" + "@nx/nx-linux-x64-gnu" "19.7.3" + "@nx/nx-linux-x64-musl" "19.7.3" + "@nx/nx-win32-arm64-msvc" "19.7.3" + "@nx/nx-win32-x64-msvc" "19.7.3" nypm@^0.3.8: version "0.3.8" @@ -17676,4 +17723,3 @@ zstd-codec@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/zstd-codec/-/zstd-codec-0.1.4.tgz#6abb311b63cfacbd06e72797ee6c6e1c7c65248c" integrity sha512-KYnWoFWgGtWyQEKNnUcb3u8ZtKO8dn5d8u+oGpxPlopqsPyv60U8suDyfk7Z7UtAO6Sk5i1aVcAs9RbaB1n36A== - \ No newline at end of file