From d2f34896edc4642e87ad7508a3a70361871cde95 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 26 Nov 2024 19:09:19 -0500 Subject: [PATCH 01/65] abacus-ts-types --- package.json | 3 ++- pnpm-lock.yaml | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d967170ea..f5c2f40d2 100644 --- a/package.json +++ b/package.json @@ -59,9 +59,9 @@ "@dydxprotocol/v4-client-js": "1.12.2", "@dydxprotocol/v4-localization": "^1.1.254", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", - "@funkit/connect": "^3.4.9", "@emotion/is-prop-valid": "^1.3.0", "@ethersproject/providers": "^5.7.2", + "@funkit/connect": "^3.4.9", "@hugocxl/react-to-image": "^0.0.9", "@js-joda/core": "^5.5.3", "@keplr-wallet/types": "^0.12.121", @@ -207,6 +207,7 @@ "rollup-plugin-sourcemaps": "^0.6.3", "stream-browserify": "^3.0.0", "tailwindcss": "^3.4.6", + "ts-morph": "^24.0.0", "ts-node": "^10.9.2", "tsx": "^4.7.1", "typescript": "^5.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72c6310f1..d2a5afffb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -481,6 +481,9 @@ devDependencies: tailwindcss: specifier: ^3.4.6 version: 3.4.6(ts-node@10.9.2) + ts-morph: + specifier: ^24.0.0 + version: 24.0.0 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.12.13)(typescript@5.6.3) @@ -10505,6 +10508,14 @@ packages: - supports-color dev: true + /@ts-morph/common@0.25.0: + resolution: {integrity: sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==} + dependencies: + minimatch: 9.0.4 + path-browserify: 1.0.1 + tinyglobby: 0.2.10 + dev: true + /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} @@ -14418,6 +14429,10 @@ packages: engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true + /code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + dev: true + /collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} dev: true @@ -16920,6 +16935,17 @@ packages: pend: 1.2.0 dev: true + /fdir@6.4.2(picomatch@4.0.2): + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + dependencies: + picomatch: 4.0.2 + dev: true + /fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} dev: true @@ -22098,6 +22124,11 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -24925,6 +24956,14 @@ packages: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} dev: false + /tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.4.2(picomatch@4.0.2) + picomatch: 4.0.2 + dev: true + /tinypool@0.8.4: resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} @@ -25029,6 +25068,13 @@ packages: tslib: 2.6.2 dev: false + /ts-morph@24.0.0: + resolution: {integrity: sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==} + dependencies: + '@ts-morph/common': 0.25.0 + code-block-writer: 13.0.3 + dev: true + /ts-node@10.9.2(@types/node@20.12.13)(typescript@5.6.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true From f887e6cf4c8261fdd16cc2889de54c916b9c7b07 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 26 Nov 2024 19:09:46 -0500 Subject: [PATCH 02/65] add codegen and helpers and manual types --- scripts/indexer-renames.ts | 54 + scripts/swagger_codegen.sh | 55 + src/abacus-ts/websocket.ts | 1 + src/types/indexer/chain.ts | 227 ++++ src/types/indexer/configs.ts | 33 + src/types/indexer/indexerApiGen.ts | 1939 ++++++++++++++++++++++++++++ src/types/indexer/indexerManual.ts | 117 ++ 7 files changed, 2426 insertions(+) create mode 100644 scripts/indexer-renames.ts create mode 100755 scripts/swagger_codegen.sh create mode 100644 src/abacus-ts/websocket.ts create mode 100644 src/types/indexer/chain.ts create mode 100644 src/types/indexer/configs.ts create mode 100644 src/types/indexer/indexerApiGen.ts create mode 100644 src/types/indexer/indexerManual.ts diff --git a/scripts/indexer-renames.ts b/scripts/indexer-renames.ts new file mode 100644 index 000000000..08714f31b --- /dev/null +++ b/scripts/indexer-renames.ts @@ -0,0 +1,54 @@ +import { + EnumDeclaration, + InterfaceDeclaration, + Project, + SyntaxKind, + TypeAliasDeclaration, +} from 'ts-morph'; + +// Initialize a new project +const project = new Project({ + // You can specify your tsconfig path here + tsConfigFilePath: 'tsconfig.json', +}); + +// Add source files - replace with your file path +const sourceFile = project.addSourceFileAtPath('./src/types/indexer/indexerApiGen.ts'); + +// Find all interfaces in the file +const interfaces = sourceFile.getDescendantsOfKind(SyntaxKind.InterfaceDeclaration); + +// Find all enums in the file +const enums = sourceFile.getDescendantsOfKind(SyntaxKind.EnumDeclaration); + +// Find all type aliases in the file +const types = sourceFile.getDescendantsOfKind(SyntaxKind.TypeAliasDeclaration); + +// Rename each interface +interfaces.forEach((interfaceDecl: InterfaceDeclaration) => { + const currentName = interfaceDecl.getName(); + const newName = `Indexer${currentName}`; + + // Rename the interface + interfaceDecl.rename(newName); +}); + +// Rename each enum +enums.forEach((enumDecl: EnumDeclaration) => { + const currentName = enumDecl.getName(); + const newName = `Indexer${currentName}`; + + // Rename the enum + enumDecl.rename(newName); +}); + +// Rename each type alias +types.forEach((typeDecl: TypeAliasDeclaration) => { + const currentName = typeDecl.getName(); + const newName = `Indexer${currentName}`; + // Rename the type alias + typeDecl.rename(newName); +}); + +// Save the changes +sourceFile.saveSync(); diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh new file mode 100755 index 000000000..66fffabf6 --- /dev/null +++ b/scripts/swagger_codegen.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +CURRENT_DIR=$(pwd) + +# Defining a temporary directory for cloning +TMP_DIR=$(mktemp -d) + +# Function to clean up the temporary directory +cleanup() { + echo "Cleaning up..." + rm -rf "$TMP_DIR" +} + +# Trap to clean up in case of script exit or interruption +trap cleanup EXIT + +curl -o $TMP_DIR/swagger.json https://raw.githubusercontent.com/dydxprotocol/v4-chain/main/indexer/services/comlink/public/swagger.json + +# Remove required attribute +# ${CURRENT_DIR}/json_remove_attr.sh -f $TMP_DIR/swagger.json -a required + +# Remove APIOrderStatus +# ${CURRENT_DIR}/json_remove_attr.sh -f $TMP_DIR/swagger.json -a APIOrderStatus + +# Codegen doesn't support allOf with enum, so we need to replace it with the enum directly + +# Add APIOrderStatus with content of OrderStatus and BestEffortOrderStatus +# ${CURRENT_DIR}/json_add_attr.sh $TMP_DIR/swagger.json '.components.schemas' APIOrderStatus TO_REPLACE + +# Remove "TO_REPLACE" with the content of OrderStatus and BestEffortOrderStatus +# sed -i '' "s/\"TO_REPLACE\"/{ \"enum\": [\"OPEN\",\"FILLED\",\"CANCELED\",\"BEST_EFFORT_CANCELED\",\"UNTRIGGERED\",\"BEST_EFFORT_OPENED\"],\"type\": \"string\" }/g" $TMP_DIR/swagger.json + +cd "$TMP_DIR" + +swagger-codegen generate -i swagger.json -o generated -l typescript-fetch + +sed -i '' '1,79d; /export const DefaultApiFetchParamCreator/,$d' generated/api.ts +sed -i '' -e ':a' -e '$d;N;2,4ba' -e 'P;D' generated/api.ts +line_num=$(grep -n "export interface SparklineResponseObject" generated/api.ts | cut -d: -f1) && sed -i '' "$((line_num-5)),$((line_num+3))d" generated/api.ts +line_num=$(grep -n "export interface PerpetualPositionsMap" generated/api.ts | cut -d: -f1) && sed -i '' "$((line_num-5)),$((line_num+3))d" generated/api.ts +line_num=$(grep -n "export interface AssetPositionsMap" generated/api.ts | cut -d: -f1) && sed -i '' "$((line_num-5)),$((line_num+3))d" generated/api.ts +sed -i '' '/markets: { \[key: string\]: PerpetualMarketResponseObject; };/s/;$//' generated/api.ts +sed -i '' 's/openPerpetualPositions: PerpetualPositionsMap;/openPerpetualPositions: { [market: string]: PerpetualPositionResponseObject };/' generated/api.ts +sed -i '' 's/assetPositions: AssetPositionsMap;/assetPositions: { [symbol: string]: AssetPositionResponseObject };/' generated/api.ts +sed -i '' 's/= /=/' generated/api.ts + +rm -f $CURRENT_DIR/src/types/indexer/indexerApiGen.ts +mv generated/api.ts $CURRENT_DIR/src/types/indexer/indexerApiGen.ts + +cd $CURRENT_DIR + +npx tsx scripts/indexer-renames.ts +pnpm prettier ./src/types/indexer/indexerApiGen.ts --write + + diff --git a/src/abacus-ts/websocket.ts b/src/abacus-ts/websocket.ts new file mode 100644 index 000000000..5e03da70f --- /dev/null +++ b/src/abacus-ts/websocket.ts @@ -0,0 +1 @@ +// do websocket thigns diff --git a/src/types/indexer/chain.ts b/src/types/indexer/chain.ts new file mode 100644 index 000000000..746b69115 --- /dev/null +++ b/src/types/indexer/chain.ts @@ -0,0 +1,227 @@ +// Staking Rewards +export interface OnChainStakingRewardsResponse { + rewards?: OnChainStakingReward[]; + total?: OnChainStakingRewardAmount[]; +} + +export interface OnChainStakingReward { + validatorAddress?: string; + reward?: OnChainStakingRewardAmount[]; +} + +export interface OnChainStakingRewardAmount { + denom?: string; + amount?: string; +} + +// Rewards Parameters +export interface OnChainRewardsParamsResponse { + params?: OnChainRewardsParams; +} + +export interface OnChainRewardsParams { + treasuryAccount?: string; + denom?: string; + denomExponent?: number; + marketId?: number; + feeMultiplierPpm?: number; +} + +// Equity Tiers +export interface OnChainEquityTiersResponse { + equityTierLimitConfig?: OnChainEquityTiers; +} + +export interface OnChainEquityTiers { + shortTermOrderEquityTiers?: OnChainEquityTier[]; + statefulOrderEquityTiers?: OnChainEquityTier[]; +} + +export interface OnChainEquityTier { + usdTncRequired?: string; + limit?: number; +} + +// Transactions +export interface ChainError { + message: string; + line?: number; + column?: number; + stack?: string; +} + +export interface OnChainTransactionErrorResponse { + error: ChainError; +} + +export interface ChainEvent { + type: string; + attributes: ChainEventAttribute[]; +} + +export interface ChainEventAttribute { + key: string; + value: string; +} + +export interface OnChainTransactionSuccessResponse { + height?: number; + hash?: string; + code?: number; + tx: string; + txIndex?: number; + gasUsed?: string; + gasWanted?: string; + events?: ChainEvent[]; +} + +// Vault Deposit Withdraw Slippage +export interface OnChainVaultDepositWithdrawSlippageResponse { + sharesToWithdraw: OnChainNumShares; + expectedQuoteQuantums: number; +} + +// User Fee Tier +export interface OnChainUserFeeTierResponse { + index?: number; + tier?: OnChainUserFeeTier; +} + +export interface OnChainUserFeeTier { + name?: string; + absoluteVolumeRequirement?: string; + totalVolumeShareRequirementPpm?: number; + makerVolumeShareRequirementPpm?: number; + makerFeePpm?: number; + takerFeePpm?: number; +} + +// Delegation +export interface OnChainDelegationResponse { + delegationResponses?: OnChainDelegationObject[]; + pagination?: OnChainAccountPagination; +} + +export interface OnChainDelegationObject { + delegation?: OnChainDelegationInfo; + balance?: OnChainAccountBalanceObject; +} + +export interface OnChainDelegationInfo { + delegatorAddress?: string; + validatorAddress?: string; + shares?: string; +} + +export interface OnChainAccountPagination { + nextKey?: string; + total?: string; +} + +// Fee Tiers +export interface OnChainFeeTiersResponse { + params?: OnChainFeeTierParams; +} + +export interface OnChainFeeTierParams { + tiers?: OnChainFeeTier[]; +} + +export interface OnChainFeeTier { + name?: string; + absoluteVolumeRequirement?: string; + totalVolumeShareRequirementPpm?: number; + makerVolumeShareRequirementPpm?: number; + makerFeePpm?: number; + takerFeePpm?: number; +} + +// Token Price +export interface OnChainTokenPriceResponse { + marketPrice?: OnChainTokenPrice; +} + +export interface OnChainTokenPrice { + price?: string; + id?: number; + exponent?: number; +} + +// Account Balance +export interface OnChainAccountBalanceObject { + denom?: string; + amount?: string; +} + +// Withdrawal Capacity +export interface OnChainWithdrawalCapacityResponse { + limiterCapacityList?: OnChainLimiterCapacity[]; +} + +export interface OnChainLimiterCapacity { + limiter?: OnChainLimiter; + capacity?: string; +} + +export interface OnChainLimiter { + period?: OnChainLimiterPeriod; + baselineMinimum?: string; + baselineTvlPpm?: number; +} + +export interface OnChainLimiterPeriod { + seconds?: string; + nanos?: number; +} + +// Unbonding +export interface OnChainUnbondingResponse { + unbondingResponses?: OnChainUnbondingObject[]; + pagination?: OnChainAccountPagination; +} + +export interface OnChainUnbondingObject { + delegatorAddress?: string; + validatorAddress?: string; + entries?: OnChainUnbondingEntry[]; +} + +export interface OnChainUnbondingEntry { + creationHeight?: string; + completionTime?: string; + initialBalance?: string; + balance?: string; + unbondingId?: string; + unbondingOnHoldRefCount?: string; +} + +// Account Vault +export interface OnChainShareUnlock { + shares?: OnChainNumShares; + unlockBlockHeight?: number; +} + +export interface OnChainNumShares { + numShares?: number; +} + +export interface OnChainAccountVaultResponse { + address?: string; + shares?: OnChainNumShares; + shareUnlocks?: OnChainShareUnlock[]; + equity?: number; + withdrawableEquity?: number; +} + +// Withdrawal And Transfer Gating Status +export interface OnChainWithdrawalAndTransferGatingStatusResponse { + negativeTncSubaccountSeenAtBlock?: number; + chainOutageSeenAtBlock?: number; + withdrawalsAndTransfersUnblockedAtBlock?: number; +} + +// User Stats +export interface OnChainUserStatsResponse { + takerNotional?: string; + makerNotional?: string; +} diff --git a/src/types/indexer/configs.ts b/src/types/indexer/configs.ts new file mode 100644 index 000000000..73150f7c4 --- /dev/null +++ b/src/types/indexer/configs.ts @@ -0,0 +1,33 @@ +export interface ConfigsLaunchIncentiveResponse { + data?: ConfigsLaunchIncentiveData; +} + +export interface ConfigsLaunchIncentiveData { + tradingSeasons?: ConfigsLaunchIncentiveSeason[]; +} + +export interface ConfigsLaunchIncentiveSeason { + label?: string; + startTimestamp?: number; +} + +export interface ConfigsLaunchIncentivePoints { + incentivePoints?: number; + marketMakingIncentivePoints?: number; + dydxRewards?: number; +} + +export interface ConfigsMarketAsset { + name: string; + websiteLink?: string; + whitepaperLink?: string; + coinMarketCapsLink?: string; + tags?: string[]; +} + +export interface ConfigsAssetMetadata { + name: string; + logo: string; + urls: Record; + sector_tags?: string[]; +} diff --git a/src/types/indexer/indexerApiGen.ts b/src/types/indexer/indexerApiGen.ts new file mode 100644 index 000000000..319d09f2c --- /dev/null +++ b/src/types/indexer/indexerApiGen.ts @@ -0,0 +1,1939 @@ +/** + * + * @export + * @interface APIOrderStatus + */ +export interface IndexerAPIOrderStatus {} +/** + * + * @export + * @enum {string} + */ +export enum IndexerAPITimeInForce { + GTT = 'GTT', + FOK = 'FOK', + IOC = 'IOC', +} +/** + * + * @export + * @interface AddressRegisterTokenBody + */ +export interface IndexerAddressRegisterTokenBody { + /** + * + * @type {string} + * @memberof AddressRegisterTokenBody + */ + language: string; + /** + * + * @type {string} + * @memberof AddressRegisterTokenBody + */ + token: string; +} +/** + * + * @export + * @interface AddressResponse + */ +export interface IndexerAddressResponse { + /** + * + * @type {Array} + * @memberof AddressResponse + */ + subaccounts: Array; + /** + * + * @type {string} + * @memberof AddressResponse + */ + totalTradingRewards: string; +} +/** + * + * @export + * @interface AffiliateAddressResponse + */ +export interface IndexerAffiliateAddressResponse { + /** + * + * @type {string} + * @memberof AffiliateAddressResponse + */ + address: string; +} +/** + * + * @export + * @interface AffiliateMetadataResponse + */ +export interface IndexerAffiliateMetadataResponse { + /** + * + * @type {string} + * @memberof AffiliateMetadataResponse + */ + referralCode: string; + /** + * + * @type {boolean} + * @memberof AffiliateMetadataResponse + */ + isVolumeEligible: boolean; + /** + * + * @type {boolean} + * @memberof AffiliateMetadataResponse + */ + isAffiliate: boolean; +} +/** + * + * @export + * @interface AffiliateSnapshotResponse + */ +export interface IndexerAffiliateSnapshotResponse { + /** + * + * @type {Array} + * @memberof AffiliateSnapshotResponse + */ + affiliateList: Array; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponse + */ + total: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponse + */ + currentOffset: number; +} +/** + * + * @export + * @interface AffiliateSnapshotResponseObject + */ +export interface IndexerAffiliateSnapshotResponseObject { + /** + * + * @type {string} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateAddress: string; + /** + * + * @type {string} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferralCode: string; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateEarnings: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredTrades: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateTotalReferredFees: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredUsers: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredNetProtocolEarnings: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredTotalVolume: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredMakerFees: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredTakerFees: number; + /** + * + * @type {number} + * @memberof AffiliateSnapshotResponseObject + */ + affiliateReferredMakerRebates: number; +} +/** + * + * @export + * @interface AffiliateTotalVolumeResponse + */ +export interface IndexerAffiliateTotalVolumeResponse { + /** + * + * @type {number} + * @memberof AffiliateTotalVolumeResponse + */ + totalVolume: number; +} +/** + * + * @export + * @interface AssetPositionResponse + */ +export interface IndexerAssetPositionResponse { + /** + * + * @type {Array} + * @memberof AssetPositionResponse + */ + positions: Array; +} +/** + * + * @export + * @interface AssetPositionResponseObject + */ +export interface IndexerAssetPositionResponseObject { + /** + * + * @type {string} + * @memberof AssetPositionResponseObject + */ + symbol: string; + /** + * + * @type {IndexerPositionSide} + * @memberof AssetPositionResponseObject + */ + side: IndexerPositionSide; + /** + * + * @type {string} + * @memberof AssetPositionResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof AssetPositionResponseObject + */ + assetId: string; + /** + * + * @type {number} + * @memberof AssetPositionResponseObject + */ + subaccountNumber: number; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerBestEffortOpenedStatus { + BESTEFFORTOPENED = 'BEST_EFFORT_OPENED', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerCandleResolution { + _1MIN = '1MIN', + _5MINS = '5MINS', + _15MINS = '15MINS', + _30MINS = '30MINS', + _1HOUR = '1HOUR', + _4HOURS = '4HOURS', + _1DAY = '1DAY', +} +/** + * + * @export + * @interface CandleResponse + */ +export interface IndexerCandleResponse { + /** + * + * @type {Array} + * @memberof CandleResponse + */ + candles: Array; +} +/** + * + * @export + * @interface CandleResponseObject + */ +export interface IndexerCandleResponseObject { + /** + * + * @type {IndexerIsoString} + * @memberof CandleResponseObject + */ + startedAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + ticker: string; + /** + * + * @type {IndexerCandleResolution} + * @memberof CandleResponseObject + */ + resolution: IndexerCandleResolution; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + low: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + high: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + open: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + close: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + baseTokenVolume: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + usdVolume: string; + /** + * + * @type {number} + * @memberof CandleResponseObject + */ + trades: number; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + startingOpenInterest: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + orderbookMidPriceOpen?: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + orderbookMidPriceClose?: string; + /** + * + * @type {string} + * @memberof CandleResponseObject + */ + id: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerComplianceReason { + MANUAL = 'MANUAL', + USGEO = 'US_GEO', + CAGEO = 'CA_GEO', + GBGEO = 'GB_GEO', + SANCTIONEDGEO = 'SANCTIONED_GEO', + COMPLIANCEPROVIDER = 'COMPLIANCE_PROVIDER', +} +/** + * + * @export + * @interface ComplianceResponse + */ +export interface IndexerComplianceResponse { + /** + * + * @type {boolean} + * @memberof ComplianceResponse + */ + restricted: boolean; + /** + * + * @type {string} + * @memberof ComplianceResponse + */ + reason?: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerComplianceStatus { + COMPLIANT = 'COMPLIANT', + FIRSTSTRIKECLOSEONLY = 'FIRST_STRIKE_CLOSE_ONLY', + FIRSTSTRIKE = 'FIRST_STRIKE', + CLOSEONLY = 'CLOSE_ONLY', + BLOCKED = 'BLOCKED', +} +/** + * + * @export + * @interface ComplianceV2Response + */ +export interface IndexerComplianceV2Response { + /** + * + * @type {IndexerComplianceStatus} + * @memberof ComplianceV2Response + */ + status: IndexerComplianceStatus; + /** + * + * @type {IndexerComplianceReason} + * @memberof ComplianceV2Response + */ + reason?: IndexerComplianceReason; + /** + * + * @type {string} + * @memberof ComplianceV2Response + */ + updatedAt?: string; +} +/** + * + * @export + * @interface FillResponse + */ +export interface IndexerFillResponse { + /** + * + * @type {number} + * @memberof FillResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof FillResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof FillResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof FillResponse + */ + fills: Array; +} +/** + * + * @export + * @interface FillResponseObject + */ +export interface IndexerFillResponseObject { + /** + * + * @type {string} + * @memberof FillResponseObject + */ + id: string; + /** + * + * @type {IndexerOrderSide} + * @memberof FillResponseObject + */ + side: IndexerOrderSide; + /** + * + * @type {IndexerLiquidity} + * @memberof FillResponseObject + */ + liquidity: IndexerLiquidity; + /** + * + * @type {IndexerFillType} + * @memberof FillResponseObject + */ + type: IndexerFillType; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + market: string; + /** + * + * @type {IndexerMarketType} + * @memberof FillResponseObject + */ + marketType: IndexerMarketType; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + price: string; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + fee: string; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + affiliateRevShare: string; + /** + * + * @type {IndexerIsoString} + * @memberof FillResponseObject + */ + createdAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + createdAtHeight: string; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + orderId?: string; + /** + * + * @type {string} + * @memberof FillResponseObject + */ + clientMetadata?: string; + /** + * + * @type {number} + * @memberof FillResponseObject + */ + subaccountNumber: number; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerFillType { + LIMIT = 'LIMIT', + LIQUIDATED = 'LIQUIDATED', + LIQUIDATION = 'LIQUIDATION', + DELEVERAGED = 'DELEVERAGED', + OFFSETTING = 'OFFSETTING', +} +/** + * + * @export + * @interface HeightResponse + */ +export interface IndexerHeightResponse { + /** + * + * @type {string} + * @memberof HeightResponse + */ + height: string; + /** + * + * @type {IndexerIsoString} + * @memberof HeightResponse + */ + time: IndexerIsoString; +} +/** + * + * @export + * @interface HistoricalBlockTradingReward + */ +export interface IndexerHistoricalBlockTradingReward { + /** + * + * @type {string} + * @memberof HistoricalBlockTradingReward + */ + tradingReward: string; + /** + * + * @type {IndexerIsoString} + * @memberof HistoricalBlockTradingReward + */ + createdAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof HistoricalBlockTradingReward + */ + createdAtHeight: string; +} +/** + * + * @export + * @interface HistoricalBlockTradingRewardsResponse + */ +export interface IndexerHistoricalBlockTradingRewardsResponse { + /** + * + * @type {Array} + * @memberof HistoricalBlockTradingRewardsResponse + */ + rewards: Array; +} +/** + * + * @export + * @interface HistoricalFundingResponse + */ +export interface IndexerHistoricalFundingResponse { + /** + * + * @type {Array} + * @memberof HistoricalFundingResponse + */ + historicalFunding: Array; +} +/** + * + * @export + * @interface HistoricalFundingResponseObject + */ +export interface IndexerHistoricalFundingResponseObject { + /** + * + * @type {string} + * @memberof HistoricalFundingResponseObject + */ + ticker: string; + /** + * + * @type {string} + * @memberof HistoricalFundingResponseObject + */ + rate: string; + /** + * + * @type {string} + * @memberof HistoricalFundingResponseObject + */ + price: string; + /** + * + * @type {IndexerIsoString} + * @memberof HistoricalFundingResponseObject + */ + effectiveAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof HistoricalFundingResponseObject + */ + effectiveAtHeight: string; +} +/** + * + * @export + * @interface HistoricalPnlResponse + */ +export interface IndexerHistoricalPnlResponse { + /** + * + * @type {number} + * @memberof HistoricalPnlResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof HistoricalPnlResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof HistoricalPnlResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof HistoricalPnlResponse + */ + historicalPnl: Array; +} +/** + * + * @export + * @interface HistoricalTradingRewardAggregation + */ +export interface IndexerHistoricalTradingRewardAggregation { + /** + * + * @type {string} + * @memberof HistoricalTradingRewardAggregation + */ + tradingReward: string; + /** + * + * @type {IndexerIsoString} + * @memberof HistoricalTradingRewardAggregation + */ + startedAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof HistoricalTradingRewardAggregation + */ + startedAtHeight: string; + /** + * + * @type {IndexerIsoString} + * @memberof HistoricalTradingRewardAggregation + */ + endedAt?: IndexerIsoString; + /** + * + * @type {string} + * @memberof HistoricalTradingRewardAggregation + */ + endedAtHeight?: string; + /** + * + * @type {IndexerTradingRewardAggregationPeriod} + * @memberof HistoricalTradingRewardAggregation + */ + period: IndexerTradingRewardAggregationPeriod; +} +/** + * + * @export + * @interface HistoricalTradingRewardAggregationsResponse + */ +export interface IndexerHistoricalTradingRewardAggregationsResponse { + /** + * + * @type {Array} + * @memberof HistoricalTradingRewardAggregationsResponse + */ + rewards: Array; +} +/** + * + * @export + */ +export type IndexerIsoString = string; +/** + * + * @export + * @enum {string} + */ +export enum IndexerLiquidity { + TAKER = 'TAKER', + MAKER = 'MAKER', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerMarketType { + PERPETUAL = 'PERPETUAL', + SPOT = 'SPOT', +} +/** + * + * @export + * @interface MegavaultHistoricalPnlResponse + */ +export interface IndexerMegavaultHistoricalPnlResponse { + /** + * + * @type {Array} + * @memberof MegavaultHistoricalPnlResponse + */ + megavaultPnl: Array; +} +/** + * + * @export + * @interface MegavaultPositionResponse + */ +export interface IndexerMegavaultPositionResponse { + /** + * + * @type {Array} + * @memberof MegavaultPositionResponse + */ + positions: Array; +} +/** + * + * @export + * @interface OrderResponseObject + */ +export interface IndexerOrderResponseObject { + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + id: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + subaccountId: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + clientId: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + clobPairId: string; + /** + * + * @type {IndexerOrderSide} + * @memberof OrderResponseObject + */ + side: IndexerOrderSide; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + totalFilled: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + price: string; + /** + * + * @type {IndexerOrderType} + * @memberof OrderResponseObject + */ + type: IndexerOrderType; + /** + * + * @type {boolean} + * @memberof OrderResponseObject + */ + reduceOnly: boolean; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + orderFlags: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + goodTilBlock?: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + goodTilBlockTime?: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + createdAtHeight?: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + clientMetadata: string; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + triggerPrice?: string; + /** + * + * @type {IndexerAPITimeInForce} + * @memberof OrderResponseObject + */ + timeInForce: IndexerAPITimeInForce; + /** + * + * @type {IndexerAPIOrderStatus} + * @memberof OrderResponseObject + */ + status: IndexerAPIOrderStatus; + /** + * + * @type {boolean} + * @memberof OrderResponseObject + */ + postOnly: boolean; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + ticker: string; + /** + * + * @type {IndexerIsoString} + * @memberof OrderResponseObject + */ + updatedAt?: IndexerIsoString; + /** + * + * @type {string} + * @memberof OrderResponseObject + */ + updatedAtHeight?: string; + /** + * + * @type {number} + * @memberof OrderResponseObject + */ + subaccountNumber: number; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerOrderSide { + BUY = 'BUY', + SELL = 'SELL', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerOrderStatus { + OPEN = 'OPEN', + FILLED = 'FILLED', + CANCELED = 'CANCELED', + BESTEFFORTCANCELED = 'BEST_EFFORT_CANCELED', + UNTRIGGERED = 'UNTRIGGERED', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerOrderType { + LIMIT = 'LIMIT', + MARKET = 'MARKET', + STOPLIMIT = 'STOP_LIMIT', + STOPMARKET = 'STOP_MARKET', + TRAILINGSTOP = 'TRAILING_STOP', + TAKEPROFIT = 'TAKE_PROFIT', + TAKEPROFITMARKET = 'TAKE_PROFIT_MARKET', +} +/** + * + * @export + * @interface OrderbookResponseObject + */ +export interface IndexerOrderbookResponseObject { + /** + * + * @type {Array} + * @memberof OrderbookResponseObject + */ + bids: Array; + /** + * + * @type {Array} + * @memberof OrderbookResponseObject + */ + asks: Array; +} +/** + * + * @export + * @interface OrderbookResponsePriceLevel + */ +export interface IndexerOrderbookResponsePriceLevel { + /** + * + * @type {string} + * @memberof OrderbookResponsePriceLevel + */ + price: string; + /** + * + * @type {string} + * @memberof OrderbookResponsePriceLevel + */ + size: string; +} +/** + * + * @export + * @interface ParentSubaccountResponse + */ +export interface IndexerParentSubaccountResponse { + /** + * + * @type {string} + * @memberof ParentSubaccountResponse + */ + address: string; + /** + * + * @type {number} + * @memberof ParentSubaccountResponse + */ + parentSubaccountNumber: number; + /** + * + * @type {string} + * @memberof ParentSubaccountResponse + */ + equity: string; + /** + * + * @type {string} + * @memberof ParentSubaccountResponse + */ + freeCollateral: string; + /** + * + * @type {Array} + * @memberof ParentSubaccountResponse + */ + childSubaccounts: Array; +} +/** + * + * @export + * @interface ParentSubaccountTransferResponse + */ +export interface IndexerParentSubaccountTransferResponse { + /** + * + * @type {number} + * @memberof ParentSubaccountTransferResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof ParentSubaccountTransferResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof ParentSubaccountTransferResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof ParentSubaccountTransferResponse + */ + transfers: Array; +} +/** + * + * @export + * @interface PerpetualMarketResponse + */ +export interface IndexerPerpetualMarketResponse { + /** + * + * @type {{ [key: string]: IndexerPerpetualMarketResponseObject; }} + * @memberof PerpetualMarketResponse + */ + markets: { [key: string]: IndexerPerpetualMarketResponseObject }; +} +/** + * + * @export + * @interface PerpetualMarketResponseObject + */ +export interface IndexerPerpetualMarketResponseObject { + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + clobPairId: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + ticker: string; + /** + * + * @type {IndexerPerpetualMarketStatus} + * @memberof PerpetualMarketResponseObject + */ + status: IndexerPerpetualMarketStatus; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + oraclePrice: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + priceChange24H: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + volume24H: string; + /** + * + * @type {number} + * @memberof PerpetualMarketResponseObject + */ + trades24H: number; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + nextFundingRate: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + initialMarginFraction: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + maintenanceMarginFraction: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + openInterest: string; + /** + * + * @type {number} + * @memberof PerpetualMarketResponseObject + */ + atomicResolution: number; + /** + * + * @type {number} + * @memberof PerpetualMarketResponseObject + */ + quantumConversionExponent: number; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + tickSize: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + stepSize: string; + /** + * + * @type {number} + * @memberof PerpetualMarketResponseObject + */ + stepBaseQuantums: number; + /** + * + * @type {number} + * @memberof PerpetualMarketResponseObject + */ + subticksPerTick: number; + /** + * + * @type {IndexerPerpetualMarketType} + * @memberof PerpetualMarketResponseObject + */ + marketType: IndexerPerpetualMarketType; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + openInterestLowerCap?: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + openInterestUpperCap?: string; + /** + * + * @type {string} + * @memberof PerpetualMarketResponseObject + */ + baseOpenInterest: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerPerpetualMarketStatus { + ACTIVE = 'ACTIVE', + PAUSED = 'PAUSED', + CANCELONLY = 'CANCEL_ONLY', + POSTONLY = 'POST_ONLY', + INITIALIZING = 'INITIALIZING', + FINALSETTLEMENT = 'FINAL_SETTLEMENT', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerPerpetualMarketType { + CROSS = 'CROSS', + ISOLATED = 'ISOLATED', +} +/** + * + * @export + * @interface PerpetualPositionResponse + */ +export interface IndexerPerpetualPositionResponse { + /** + * + * @type {Array} + * @memberof PerpetualPositionResponse + */ + positions: Array; +} +/** + * + * @export + * @interface PerpetualPositionResponseObject + */ +export interface IndexerPerpetualPositionResponseObject { + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + market: string; + /** + * + * @type {IndexerPerpetualPositionStatus} + * @memberof PerpetualPositionResponseObject + */ + status: IndexerPerpetualPositionStatus; + /** + * + * @type {IndexerPositionSide} + * @memberof PerpetualPositionResponseObject + */ + side: IndexerPositionSide; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + maxSize: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + entryPrice: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + realizedPnl: string; + /** + * + * @type {IndexerIsoString} + * @memberof PerpetualPositionResponseObject + */ + createdAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + createdAtHeight: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + sumOpen: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + sumClose: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + netFunding: string; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + unrealizedPnl: string; + /** + * + * @type {IndexerIsoString} + * @memberof PerpetualPositionResponseObject + */ + closedAt?: IndexerIsoString; + /** + * + * @type {string} + * @memberof PerpetualPositionResponseObject + */ + exitPrice?: string; + /** + * + * @type {number} + * @memberof PerpetualPositionResponseObject + */ + subaccountNumber: number; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerPerpetualPositionStatus { + OPEN = 'OPEN', + CLOSED = 'CLOSED', + LIQUIDATED = 'LIQUIDATED', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerPnlTickInterval { + Hour = 'hour', + Day = 'day', +} +/** + * + * @export + * @interface PnlTicksResponseObject + */ +export interface IndexerPnlTicksResponseObject { + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + id: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + subaccountId: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + equity: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + totalPnl: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + netTransfers: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + createdAt: string; + /** + * + * @type {string} + * @memberof PnlTicksResponseObject + */ + blockHeight: string; + /** + * + * @type {IndexerIsoString} + * @memberof PnlTicksResponseObject + */ + blockTime: IndexerIsoString; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerPositionSide { + LONG = 'LONG', + SHORT = 'SHORT', +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerSparklineTimePeriod { + ONEDAY = 'ONE_DAY', + SEVENDAYS = 'SEVEN_DAYS', +} +/** + * + * @export + * @interface SubaccountResponseObject + */ +export interface IndexerSubaccountResponseObject { + /** + * + * @type {string} + * @memberof SubaccountResponseObject + */ + address: string; + /** + * + * @type {number} + * @memberof SubaccountResponseObject + */ + subaccountNumber: number; + /** + * + * @type {string} + * @memberof SubaccountResponseObject + */ + equity: string; + /** + * + * @type {string} + * @memberof SubaccountResponseObject + */ + freeCollateral: string; + /** + * + * @type {PerpetualPositionsMap} + * @memberof SubaccountResponseObject + */ + openPerpetualPositions: { [market: string]: IndexerPerpetualPositionResponseObject }; + /** + * + * @type {AssetPositionsMap} + * @memberof SubaccountResponseObject + */ + assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; + /** + * + * @type {boolean} + * @memberof SubaccountResponseObject + */ + marginEnabled: boolean; + /** + * + * @type {string} + * @memberof SubaccountResponseObject + */ + updatedAtHeight: string; + /** + * + * @type {string} + * @memberof SubaccountResponseObject + */ + latestProcessedBlockHeight: string; +} +/** + * + * @export + * @interface TimeResponse + */ +export interface IndexerTimeResponse { + /** + * + * @type {IndexerIsoString} + * @memberof TimeResponse + */ + iso: IndexerIsoString; + /** + * + * @type {number} + * @memberof TimeResponse + */ + epoch: number; +} +/** + * + * @export + * @interface TradeResponse + */ +export interface IndexerTradeResponse { + /** + * + * @type {number} + * @memberof TradeResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof TradeResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof TradeResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof TradeResponse + */ + trades: Array; +} +/** + * + * @export + * @interface TradeResponseObject + */ +export interface IndexerTradeResponseObject { + /** + * + * @type {string} + * @memberof TradeResponseObject + */ + id: string; + /** + * + * @type {IndexerOrderSide} + * @memberof TradeResponseObject + */ + side: IndexerOrderSide; + /** + * + * @type {string} + * @memberof TradeResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof TradeResponseObject + */ + price: string; + /** + * + * @type {IndexerTradeType} + * @memberof TradeResponseObject + */ + type: IndexerTradeType; + /** + * + * @type {IndexerIsoString} + * @memberof TradeResponseObject + */ + createdAt: IndexerIsoString; + /** + * + * @type {string} + * @memberof TradeResponseObject + */ + createdAtHeight: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerTradeType { + LIMIT = 'LIMIT', + LIQUIDATED = 'LIQUIDATED', + DELEVERAGED = 'DELEVERAGED', +} +/** + * + * @export + * @interface TraderSearchResponse + */ +export interface IndexerTraderSearchResponse { + /** + * + * @type {IndexerTraderSearchResponseObject} + * @memberof TraderSearchResponse + */ + result?: IndexerTraderSearchResponseObject; +} +/** + * + * @export + * @interface TraderSearchResponseObject + */ +export interface IndexerTraderSearchResponseObject { + /** + * + * @type {string} + * @memberof TraderSearchResponseObject + */ + address: string; + /** + * + * @type {number} + * @memberof TraderSearchResponseObject + */ + subaccountNumber: number; + /** + * + * @type {string} + * @memberof TraderSearchResponseObject + */ + subaccountId: string; + /** + * + * @type {string} + * @memberof TraderSearchResponseObject + */ + username: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerTradingRewardAggregationPeriod { + DAILY = 'DAILY', + WEEKLY = 'WEEKLY', + MONTHLY = 'MONTHLY', +} +/** + * + * @export + * @interface TransferBetweenResponse + */ +export interface IndexerTransferBetweenResponse { + /** + * + * @type {number} + * @memberof TransferBetweenResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof TransferBetweenResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof TransferBetweenResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof TransferBetweenResponse + */ + transfersSubset: Array; + /** + * + * @type {string} + * @memberof TransferBetweenResponse + */ + totalNetTransfers: string; +} +/** + * + * @export + * @interface TransferResponse + */ +export interface IndexerTransferResponse { + /** + * + * @type {number} + * @memberof TransferResponse + */ + pageSize?: number; + /** + * + * @type {number} + * @memberof TransferResponse + */ + totalResults?: number; + /** + * + * @type {number} + * @memberof TransferResponse + */ + offset?: number; + /** + * + * @type {Array} + * @memberof TransferResponse + */ + transfers: Array; +} +/** + * + * @export + * @interface TransferResponseObject + */ +export interface IndexerTransferResponseObject { + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + id: string; + /** + * + * @type {IndexerTransferResponseObjectSender} + * @memberof TransferResponseObject + */ + sender: IndexerTransferResponseObjectSender; + /** + * + * @type {IndexerTransferResponseObjectSender} + * @memberof TransferResponseObject + */ + recipient: IndexerTransferResponseObjectSender; + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + size: string; + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + createdAt: string; + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + createdAtHeight: string; + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + symbol: string; + /** + * + * @type {IndexerTransferType} + * @memberof TransferResponseObject + */ + type: IndexerTransferType; + /** + * + * @type {string} + * @memberof TransferResponseObject + */ + transactionHash: string; +} +/** + * + * @export + * @interface TransferResponseObjectSender + */ +export interface IndexerTransferResponseObjectSender { + /** + * + * @type {number} + * @memberof TransferResponseObjectSender + */ + subaccountNumber?: number; + /** + * + * @type {string} + * @memberof TransferResponseObjectSender + */ + address: string; +} +/** + * + * @export + * @enum {string} + */ +export enum IndexerTransferType { + TRANSFERIN = 'TRANSFER_IN', + TRANSFEROUT = 'TRANSFER_OUT', + DEPOSIT = 'DEPOSIT', + WITHDRAWAL = 'WITHDRAWAL', +} +/** + * + * @export + * @interface VaultHistoricalPnl + */ +export interface IndexerVaultHistoricalPnl { + /** + * + * @type {string} + * @memberof VaultHistoricalPnl + */ + ticker: string; + /** + * + * @type {Array} + * @memberof VaultHistoricalPnl + */ + historicalPnl: Array; +} +/** + * + * @export + * @interface VaultPosition + */ +export interface IndexerVaultPosition { + /** + * + * @type {string} + * @memberof VaultPosition + */ + ticker: string; + /** + * + * @type {IndexerAssetPositionResponseObject} + * @memberof VaultPosition + */ + assetPosition: IndexerAssetPositionResponseObject; + /** + * + * @type {IndexerPerpetualPositionResponseObject} + * @memberof VaultPosition + */ + perpetualPosition?: IndexerPerpetualPositionResponseObject; + /** + * + * @type {string} + * @memberof VaultPosition + */ + equity: string; +} +/** + * + * @export + * @interface VaultsHistoricalPnlResponse + */ +export interface IndexerVaultsHistoricalPnlResponse { + /** + * + * @type {Array} + * @memberof VaultsHistoricalPnlResponse + */ + vaultsPnl: Array; +} diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts new file mode 100644 index 000000000..4223eae9a --- /dev/null +++ b/src/types/indexer/indexerManual.ts @@ -0,0 +1,117 @@ +import { + IndexerAPIOrderStatus, + IndexerAPITimeInForce, + IndexerFillType, + IndexerIsoString, + IndexerLiquidity, + IndexerMarketType, + IndexerOrderSide, + IndexerOrderType, + IndexerPerpetualMarketStatus, + IndexerPerpetualMarketType, +} from './indexerApiGen'; + +export interface IndexerCompositeFillResponse { + pageSize?: number; + totalResults?: number; + offset?: number; + fills?: IndexerCompositeFillObject[]; +} + +export interface IndexerCompositeOrderObject { + id?: string; + subaccountId?: string; + clientId?: string; + clobPairId?: string; + side?: IndexerOrderSide; + size?: string; + totalFilled?: string; + price?: string; + type?: IndexerOrderType; + reduceOnly?: boolean; + orderFlags?: string; + goodTilBlock?: string; + goodTilBlockTime?: string; + createdAtHeight?: string; + clientMetadata?: string; + triggerPrice?: string; + timeInForce?: IndexerAPITimeInForce; + status?: IndexerAPIOrderStatus; + postOnly?: boolean; + ticker?: string; + updatedAt?: IndexerIsoString; + updatedAtHeight?: string; + subaccountNumber?: number; + removalReason?: string; + totalOptimisticFilled?: string; +} + +export interface IndexerCompositeMarketObject { + clobPairId?: string; + ticker?: string; + status?: IndexerPerpetualMarketStatus; + oraclePrice?: string; + priceChange24H?: string; + volume24H?: string; + trades24H?: number; + nextFundingRate?: string; + initialMarginFraction?: string; + maintenanceMarginFraction?: string; + openInterest?: string; + atomicResolution?: number; + quantumConversionExponent?: number; + tickSize?: string; + stepSize?: string; + stepBaseQuantums?: number; + subticksPerTick?: number; + marketType?: IndexerPerpetualMarketType; + openInterestLowerCap?: string; + openInterestUpperCap?: string; + baseOpenInterest?: string; + id?: string; + marketId?: number; + baseAsset?: string; + quoteAsset?: string; + basePositionSize?: string; + incrementalPositionSize?: string; + maxPositionSize?: string; + incrementalInitialMarginFraction?: string; +} + +export interface IndexerWsOrderbookUpdateResponse { + asks?: IndexerWsOrderbookUpdateItem[]; + bids?: IndexerWsOrderbookUpdateItem[]; +} + +export type IndexerWsOrderbookUpdateItem = string[]; + +export interface IndexerWsMarketUpdateResponse { + trading?: { [key: string]: IndexerCompositeMarketObject }; + oraclePrices?: { [key: string]: IndexerWsMarketOraclePriceObject }; +} + +export interface IndexerWsMarketOraclePriceObject { + oraclePrice?: string; + effectiveAt?: IndexerIsoString; + effectiveAtHeight?: string; + marketId?: number; +} + +export interface IndexerCompositeFillObject { + id?: string; + side?: IndexerOrderSide; + liquidity?: IndexerLiquidity; + type?: IndexerFillType; + market?: string; + marketType?: IndexerMarketType; + price?: string; + size?: string; + fee?: string; + affiliateRevShare?: string; + createdAt?: IndexerIsoString; + createdAtHeight?: string; + orderId?: string; + clientMetadata?: string; + subaccountNumber?: number; + ticker?: string; +} From 71f8dd85ae33492fea46d5740529b075cf2a6329 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 27 Nov 2024 14:57:31 -0500 Subject: [PATCH 03/65] fixes --- scripts/swagger_codegen.sh | 12 +----------- src/types/indexer/indexerApiGen.ts | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh index 66fffabf6..b2e7e281f 100755 --- a/scripts/swagger_codegen.sh +++ b/scripts/swagger_codegen.sh @@ -19,17 +19,6 @@ curl -o $TMP_DIR/swagger.json https://raw.githubusercontent.com/dydxprotocol/v4- # Remove required attribute # ${CURRENT_DIR}/json_remove_attr.sh -f $TMP_DIR/swagger.json -a required -# Remove APIOrderStatus -# ${CURRENT_DIR}/json_remove_attr.sh -f $TMP_DIR/swagger.json -a APIOrderStatus - -# Codegen doesn't support allOf with enum, so we need to replace it with the enum directly - -# Add APIOrderStatus with content of OrderStatus and BestEffortOrderStatus -# ${CURRENT_DIR}/json_add_attr.sh $TMP_DIR/swagger.json '.components.schemas' APIOrderStatus TO_REPLACE - -# Remove "TO_REPLACE" with the content of OrderStatus and BestEffortOrderStatus -# sed -i '' "s/\"TO_REPLACE\"/{ \"enum\": [\"OPEN\",\"FILLED\",\"CANCELED\",\"BEST_EFFORT_CANCELED\",\"UNTRIGGERED\",\"BEST_EFFORT_OPENED\"],\"type\": \"string\" }/g" $TMP_DIR/swagger.json - cd "$TMP_DIR" swagger-codegen generate -i swagger.json -o generated -l typescript-fetch @@ -51,5 +40,6 @@ cd $CURRENT_DIR npx tsx scripts/indexer-renames.ts pnpm prettier ./src/types/indexer/indexerApiGen.ts --write +sed -i '' 's/export interface IndexerAPIOrderStatus {}/export type APIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus;/' ./src/types/indexer/indexerApiGen.ts diff --git a/src/types/indexer/indexerApiGen.ts b/src/types/indexer/indexerApiGen.ts index 319d09f2c..8367d6076 100644 --- a/src/types/indexer/indexerApiGen.ts +++ b/src/types/indexer/indexerApiGen.ts @@ -3,7 +3,7 @@ * @export * @interface APIOrderStatus */ -export interface IndexerAPIOrderStatus {} +export type APIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus; /** * * @export From e0e05ff331b61574c9bbf83d2bf24db1e4bcc28a Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 27 Nov 2024 15:02:21 -0500 Subject: [PATCH 04/65] fix --- scripts/swagger_codegen.sh | 2 +- src/types/indexer/indexerApiGen.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh index b2e7e281f..32c2536af 100755 --- a/scripts/swagger_codegen.sh +++ b/scripts/swagger_codegen.sh @@ -40,6 +40,6 @@ cd $CURRENT_DIR npx tsx scripts/indexer-renames.ts pnpm prettier ./src/types/indexer/indexerApiGen.ts --write -sed -i '' 's/export interface IndexerAPIOrderStatus {}/export type APIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus;/' ./src/types/indexer/indexerApiGen.ts +sed -i '' 's/export interface IndexerAPIOrderStatus {}/export type IndexerAPIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus;/' ./src/types/indexer/indexerApiGen.ts diff --git a/src/types/indexer/indexerApiGen.ts b/src/types/indexer/indexerApiGen.ts index 8367d6076..01db031a0 100644 --- a/src/types/indexer/indexerApiGen.ts +++ b/src/types/indexer/indexerApiGen.ts @@ -3,7 +3,7 @@ * @export * @interface APIOrderStatus */ -export type APIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus; +export type IndexerAPIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus; /** * * @export From 6ddeb688400e01130e4a28f601c2a766db4d8a49 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 2 Dec 2024 17:58:00 -0500 Subject: [PATCH 05/65] add websocket layer --- src/abacus-ts/indexerWebsocket.ts | 172 +++++++++++++++++++++++++ src/abacus-ts/reconnectingWebsocket.ts | 128 ++++++++++++++++++ src/abacus-ts/websocket.ts | 1 - 3 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 src/abacus-ts/indexerWebsocket.ts create mode 100644 src/abacus-ts/reconnectingWebsocket.ts delete mode 100644 src/abacus-ts/websocket.ts diff --git a/src/abacus-ts/indexerWebsocket.ts b/src/abacus-ts/indexerWebsocket.ts new file mode 100644 index 000000000..ebd49d705 --- /dev/null +++ b/src/abacus-ts/indexerWebsocket.ts @@ -0,0 +1,172 @@ +// do websocket thigns +import { assertNever } from '@/lib/assertNever'; +import { isTruthy } from '@/lib/isTruthy'; + +import { ReconnectingWebSocket } from './reconnectingWebsocket'; + +const NO_ID_SPECIAL_STRING_ID = '____EMPTY_ID______'; +export class IndexerWebsocket { + private socket: ReconnectingWebSocket | null = null; + + private subscriptions: { + [channel: string]: { + [id: string]: { + channel: string; + id: string | undefined; + batched: boolean; + handleBaseData: (data: any) => void; + handleUpdates: (updates: any[]) => void; + }; + }; + } = {}; + + constructor(url: string) { + this.socket = new ReconnectingWebSocket({ + url, + handleFreshConnect: this._handleFreshConnect, + handleMessage: this._handleMessage, + }); + } + + teardown(): void { + this.socket?.teardown(); + this.socket = null; + } + + // returns the unsubscribe function + addChannelSubscription({ + channel, + id, + batched = true, + handleUpdates, + handleBaseData, + }: { + channel: string; + id: string | undefined; + batched?: boolean; + handleBaseData: (data: any) => void; + handleUpdates: (data: any[]) => void; + }): () => void { + this.subscriptions[channel] ??= {}; + if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] != null) { + throw new Error(`IndexerWebsocket error: this subscription already exists. ${channel}/${id}`); + } + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] = { + channel, + id, + batched, + handleBaseData, + handleUpdates, + }; + if (this.socket != null && this.socket.isActive()) { + this.socket.send({ + batched, + channel, + id, + type: 'subscribe', + }); + } + + return () => { + if (this.subscriptions[channel] == null) { + return; + } + if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { + return; + } + if (this.socket != null && this.socket.isActive()) { + this.socket.send({ + channel, + id, + type: 'unsubscribe', + }); + } + delete this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]; + }; + } + + private _handleMessage = (message: IndexerWebsocketMessageType) => { + if (message.type === 'error') { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket encountered server side error:', message.message); + } else if (message.type === 'connected') { + // do nothing + } else if ( + message.type === 'subscribed' || + message.type === 'channel_batch_data' || + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + message.type === 'channel_data' + ) { + const channel = message.channel; + const id = message.id; + if (this.subscriptions[channel] == null) { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket encountered message with unknown target', channel, id); + return; + } + if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket encountered message with unknown target', channel, id); + return; + } + if (message.type === 'subscribed') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleBaseData( + message.contents + ); + } else if (message.type === 'channel_data') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates([ + message.contents, + ]); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if (message.type === 'channel_batch_data') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates(message.contents); + } else { + assertNever(message); + } + } else { + assertNever(message); + } + }; + + // when websocket churns, reconnect all known subscribers + private _handleFreshConnect = () => { + if (this.socket != null && this.socket.isActive()) { + Object.values(this.subscriptions) + .filter(isTruthy) + .flatMap((o) => Object.values(o)) + .filter(isTruthy) + .forEach(({ batched, channel, id }) => { + this.socket!.send({ + batched, + channel, + id, + type: 'subscribe', + }); + }); + } else { + // eslint-disable-next-line no-console + console.error( + "IndexerWebsocket error: handle fresh connect called when websocket isn't ready." + ); + } + }; +} + +type IndexerWebsocketMessageType = + | { type: 'error'; message: string } + | { type: 'connected' } + | { + type: 'channel_batch_data'; + channel: string; + id: string | undefined; + version: string; + contents: any[]; + } + | { + type: 'channel_data'; + channel: string; + id: string | undefined; + version: string; + contents: any; + } + | { type: 'subscribed'; channel: string; id: string | undefined; contents: any }; diff --git a/src/abacus-ts/reconnectingWebsocket.ts b/src/abacus-ts/reconnectingWebsocket.ts new file mode 100644 index 000000000..1e75b02e7 --- /dev/null +++ b/src/abacus-ts/reconnectingWebsocket.ts @@ -0,0 +1,128 @@ +interface WebSocketConfig { + url: string; + handleMessage: (data: any) => void; + handleFreshConnect: () => void; + initialReconnectInterval?: number; + maxReconnectInterval?: number; + backoffMultiplier?: number; +} + +export class ReconnectingWebSocket { + private ws: WebSocket | null = null; + + private readonly url: string; + + private readonly handleMessage: (data: any) => void; + + private readonly handleFreshConnect: () => void; + + private readonly initialReconnectInterval: number; + + private readonly maxReconnectInterval: number; + + private readonly backoffMultiplier: number; + + private isDead: boolean = false; + + private currentReconnectInterval: number; + + private reconnectTimeout: NodeJS.Timeout | null = null; + + constructor(config: WebSocketConfig) { + this.url = config.url; + this.handleMessage = config.handleMessage; + this.handleFreshConnect = config.handleFreshConnect; + + this.initialReconnectInterval = config.initialReconnectInterval ?? 1_000; + this.maxReconnectInterval = config.maxReconnectInterval ?? 60_000; + this.backoffMultiplier = config.backoffMultiplier ?? 1.5; + this.currentReconnectInterval = this.initialReconnectInterval; + + this.connect(); + } + + private connect(): void { + try { + this.ws = new WebSocket(this.url); + + this.ws.onmessage = (event) => { + try { + const data = JSON.parse(event.data); + this.handleMessage(data); + } catch (e) { + // eslint-disable-next-line no-console + console.error('ReconnectingWebSocket: error in handler', e); + } + }; + + this.ws.onclose = () => { + this.ws = null; + this.handleReconnect(); + }; + + this.ws.onerror = (error) => { + // eslint-disable-next-line no-console + console.error('ReconnectingWebSocket error:', error); + this.ws?.close(); + }; + + this.ws.onopen = () => { + this.currentReconnectInterval = this.initialReconnectInterval; + this.handleFreshConnect(); + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error('ReconnectingWebSocket connection error:', error); + this.ws?.close(); + this.ws = null; + this.handleReconnect(); + } + } + + private handleReconnect(): void { + if (this.isDead) { + return; + } + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + } + + this.reconnectTimeout = setTimeout(() => { + // eslint-disable-next-line no-console + console.log( + `ReconnectingWebSocket: Attempting to reconnect after ${this.currentReconnectInterval / 1000}s...` + ); + + // Calculate next interval with exponential backoff + this.currentReconnectInterval = Math.min( + this.currentReconnectInterval * this.backoffMultiplier, + this.maxReconnectInterval + ); + + this.connect(); + }, this.currentReconnectInterval); + } + + public isActive(): boolean { + return this.ws?.readyState === WebSocket.OPEN; + } + + public send(data: any): void { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + throw new Error('ReconnectingWebSocket: WebSocket is not connected'); + } + + const message = typeof data === 'string' ? data : JSON.stringify(data); + this.ws.send(message); + } + + public teardown(): void { + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + this.reconnectTimeout = null; + } + this.isDead = true; + this.ws?.close(); + this.ws = null; + } +} diff --git a/src/abacus-ts/websocket.ts b/src/abacus-ts/websocket.ts deleted file mode 100644 index 5e03da70f..000000000 --- a/src/abacus-ts/websocket.ts +++ /dev/null @@ -1 +0,0 @@ -// do websocket thigns From 7c25ca71363bd6256316344e321c6ff4bca3a894 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 2 Dec 2024 17:59:52 -0500 Subject: [PATCH 06/65] fix --- src/abacus-ts/indexerWebsocket.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/abacus-ts/indexerWebsocket.ts b/src/abacus-ts/indexerWebsocket.ts index ebd49d705..cdd5af687 100644 --- a/src/abacus-ts/indexerWebsocket.ts +++ b/src/abacus-ts/indexerWebsocket.ts @@ -1,4 +1,3 @@ -// do websocket thigns import { assertNever } from '@/lib/assertNever'; import { isTruthy } from '@/lib/isTruthy'; From 8305f2e7cef580b6e79441c85268cc2e1200832c Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 2 Dec 2024 18:00:15 -0500 Subject: [PATCH 07/65] fix --- src/abacus-ts/indexerWebsocket.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abacus-ts/indexerWebsocket.ts b/src/abacus-ts/indexerWebsocket.ts index cdd5af687..3459d05bb 100644 --- a/src/abacus-ts/indexerWebsocket.ts +++ b/src/abacus-ts/indexerWebsocket.ts @@ -4,6 +4,7 @@ import { isTruthy } from '@/lib/isTruthy'; import { ReconnectingWebSocket } from './reconnectingWebsocket'; const NO_ID_SPECIAL_STRING_ID = '____EMPTY_ID______'; + export class IndexerWebsocket { private socket: ReconnectingWebSocket | null = null; From 202f1696fb311246176c4c8a95a0d2ea878b65db Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 3 Dec 2024 18:14:56 -0500 Subject: [PATCH 08/65] add market tracker and helpers --- src/abacus-ts/loadable.ts | 12 ++ .../{ => websocket}/indexerWebsocket.ts | 12 +- .../websocket/indexerWebsocketManager.ts | 25 ++++ src/abacus-ts/websocket/markets.ts | 109 ++++++++++++++++++ src/abacus-ts/websocket/orderbook.ts | 0 src/abacus-ts/websocket/parentSubaccount.ts | 0 .../{ => websocket}/reconnectingWebsocket.ts | 0 src/abacus-ts/websocket/subscribableValue.ts | 41 +++++++ src/abacus-ts/websocket/trades.ts | 0 src/hooks/useEndpointsConfig.ts | 2 +- 10 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 src/abacus-ts/loadable.ts rename src/abacus-ts/{ => websocket}/indexerWebsocket.ts (91%) create mode 100644 src/abacus-ts/websocket/indexerWebsocketManager.ts create mode 100644 src/abacus-ts/websocket/markets.ts create mode 100644 src/abacus-ts/websocket/orderbook.ts create mode 100644 src/abacus-ts/websocket/parentSubaccount.ts rename src/abacus-ts/{ => websocket}/reconnectingWebsocket.ts (100%) create mode 100644 src/abacus-ts/websocket/subscribableValue.ts create mode 100644 src/abacus-ts/websocket/trades.ts diff --git a/src/abacus-ts/loadable.ts b/src/abacus-ts/loadable.ts new file mode 100644 index 000000000..1117596e6 --- /dev/null +++ b/src/abacus-ts/loadable.ts @@ -0,0 +1,12 @@ +export type Loadable = + | { status: 'success'; data: T } + | { status: 'pending'; data?: T } + | { status: 'error'; error: any; data?: T }; + +export function loadablePending() { + return { status: 'pending' } as const; +} + +export function loadableLoaded(value: T) { + return { status: 'success', data: value } as const; +} diff --git a/src/abacus-ts/indexerWebsocket.ts b/src/abacus-ts/websocket/indexerWebsocket.ts similarity index 91% rename from src/abacus-ts/indexerWebsocket.ts rename to src/abacus-ts/websocket/indexerWebsocket.ts index 3459d05bb..206e01eb2 100644 --- a/src/abacus-ts/indexerWebsocket.ts +++ b/src/abacus-ts/websocket/indexerWebsocket.ts @@ -3,7 +3,7 @@ import { isTruthy } from '@/lib/isTruthy'; import { ReconnectingWebSocket } from './reconnectingWebsocket'; -const NO_ID_SPECIAL_STRING_ID = '____EMPTY_ID______'; +const NO_ID_SPECIAL_STRING_ID = '______EMPTY_ID______'; export class IndexerWebsocket { private socket: ReconnectingWebSocket | null = null; @@ -16,6 +16,7 @@ export class IndexerWebsocket { batched: boolean; handleBaseData: (data: any) => void; handleUpdates: (updates: any[]) => void; + sentSubMessage: boolean; }; }; } = {}; @@ -57,8 +58,10 @@ export class IndexerWebsocket { batched, handleBaseData, handleUpdates, + sentSubMessage: false, }; if (this.socket != null && this.socket.isActive()) { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.sentSubMessage = true; this.socket.send({ batched, channel, @@ -74,7 +77,11 @@ export class IndexerWebsocket { if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { return; } - if (this.socket != null && this.socket.isActive()) { + if ( + this.socket != null && + this.socket.isActive() && + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.sentSubMessage + ) { this.socket.send({ channel, id, @@ -136,6 +143,7 @@ export class IndexerWebsocket { .flatMap((o) => Object.values(o)) .filter(isTruthy) .forEach(({ batched, channel, id }) => { + this.subscriptions[channel]![id ?? NO_ID_SPECIAL_STRING_ID]!.sentSubMessage = true; this.socket!.send({ batched, channel, diff --git a/src/abacus-ts/websocket/indexerWebsocketManager.ts b/src/abacus-ts/websocket/indexerWebsocketManager.ts new file mode 100644 index 000000000..b25a2e48d --- /dev/null +++ b/src/abacus-ts/websocket/indexerWebsocketManager.ts @@ -0,0 +1,25 @@ +import { IndexerWebsocket } from './indexerWebsocket'; + +const cachedWebsockets: { [url: string]: IndexerWebsocket } = {}; + +function getIndexerWs(url: string) { + if (cachedWebsockets[url] == null) { + // eslint-disable-next-line no-console + console.log('IndexerWsManager: spinning up @ ', url); + } + cachedWebsockets[url] ??= new IndexerWebsocket(url); + return cachedWebsockets[url]; +} + +function destroyIndexerWs(url: string) { + // eslint-disable-next-line no-console + console.log('IndexerWsManager: tearing down @ ', url); + + cachedWebsockets[url]?.teardown(); + delete cachedWebsockets[url]; +} + +export const IndexerWebsocketManager = { + get: getIndexerWs, + teardown: destroyIndexerWs, +}; diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts new file mode 100644 index 000000000..4d026841c --- /dev/null +++ b/src/abacus-ts/websocket/markets.ts @@ -0,0 +1,109 @@ +import { + IndexerPerpetualMarketResponse, + IndexerPerpetualMarketResponseObject, +} from '@/types/indexer/indexerApiGen'; +import { IndexerWsMarketUpdateResponse } from '@/types/indexer/indexerManual'; + +import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; + +import { EndpointsConfig } from '@/hooks/useEndpointsConfig'; + +import { RootStore } from '@/state/_store'; +import { getSelectedNetwork } from '@/state/appSelectors'; +import { createAppSelector } from '@/state/appTypes'; + +import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { IndexerWebsocket } from './indexerWebsocket'; +import { IndexerWebsocketManager } from './indexerWebsocketManager'; +import { SubscribableValue } from './subscribableValue'; + +type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; + +class MarketsTracker { + private state = new SubscribableValue>(loadablePending()); + + private unsub: (() => void) | undefined; + + constructor(private websocket: IndexerWebsocket) { + this.unsub = this.websocket.addChannelSubscription({ + channel: 'v4_markets', + id: undefined, + handleBaseData: this._handleBase, + handleUpdates: this._handleUpdates, + }); + } + + public addSubscriber(handle: (val: Loadable) => void): () => void { + return this.state.addSubscriber(handle); + } + + public teardown() { + this.unsub?.(); + this.state.clearSubs(); + this.unsub = undefined; + } + + private _handleBase = (baseMessage: any) => { + const message = baseMessage as IndexerPerpetualMarketResponse; + this.state.setValue(loadableLoaded(message.markets)); + }; + + private _handleUpdates = (baseUpdates: any[]) => { + const updates = baseUpdates as IndexerWsMarketUpdateResponse[]; + let startingValue = this.state.getValue().data; + if (startingValue == null) { + // eslint-disable-next-line no-console + console.log('MarketsTracker found unexpectedly null base data in update'); + return; + } + startingValue = { ...startingValue }; + updates.forEach((update) => { + if (update.oraclePrices != null) { + Object.entries(update.oraclePrices).forEach(([marketId, oraclePriceObj]) => { + if (startingValue[marketId] != null && oraclePriceObj.oraclePrice != null) { + startingValue[marketId] = { + ...startingValue[marketId], + oraclePrice: oraclePriceObj.oraclePrice, + }; + } + }); + } + if (update.trading != null) { + Object.entries(update.trading).forEach(([marketId, updateObj]) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (startingValue[marketId] != null && updateObj != null) { + startingValue[marketId] = { + ...startingValue[marketId], + ...updateObj, + }; + } + }); + } + }); + this.state.setValue({ ...this.state.getValue(), data: startingValue }); + }; +} + +let lastTracker: MarketsTracker | undefined; +let lastUrl: string | undefined; + +const selectWebsocketUrl = createAppSelector(getSelectedNetwork, (network) => { + const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; + return endpointsConfig.indexers[0]!.socket; +}); + +export function setUpMarkets(store: RootStore) { + return store.subscribe(() => { + const newUrl = selectWebsocketUrl(store.getState()); + if (newUrl !== lastUrl) { + lastTracker?.teardown(); + // let the manager know we're not using it anymore either + // but this is getting to be a lot of bookkeeping + lastUrl = undefined; + lastTracker = undefined; + } + lastUrl = newUrl; + lastTracker = new MarketsTracker(IndexerWebsocketManager.get(newUrl)); + lastTracker.addSubscriber((val) => store.dispatch(SetRawMarkets(val))); + }); +} diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/abacus-ts/reconnectingWebsocket.ts b/src/abacus-ts/websocket/reconnectingWebsocket.ts similarity index 100% rename from src/abacus-ts/reconnectingWebsocket.ts rename to src/abacus-ts/websocket/reconnectingWebsocket.ts diff --git a/src/abacus-ts/websocket/subscribableValue.ts b/src/abacus-ts/websocket/subscribableValue.ts new file mode 100644 index 000000000..a71e037a5 --- /dev/null +++ b/src/abacus-ts/websocket/subscribableValue.ts @@ -0,0 +1,41 @@ +type Subscriber = (value: T) => void; +type Unsubscribe = () => void; + +export class SubscribableValue { + private value: T; + + private subscribers: Set> = new Set(); + + constructor(initialValue: T) { + this.value = initialValue; + } + + getValue(): T { + return this.value; + } + + setValue(newValue: T): void { + // todo shallow equal option + if (newValue !== this.value) { + this.value = newValue; + this.subscribers.forEach((subscriber) => { + subscriber(this.value); + }); + } + } + + addSubscriber(subscriber: Subscriber): Unsubscribe { + this.subscribers.add(subscriber); + + // Immediately notify new subscriber of current value + subscriber(this.value); + + return () => { + this.subscribers.delete(subscriber); + }; + } + + clearSubs() { + this.subscribers = new Set(); + } +} diff --git a/src/abacus-ts/websocket/trades.ts b/src/abacus-ts/websocket/trades.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/hooks/useEndpointsConfig.ts b/src/hooks/useEndpointsConfig.ts index 53e76922d..92cdaf322 100644 --- a/src/hooks/useEndpointsConfig.ts +++ b/src/hooks/useEndpointsConfig.ts @@ -3,7 +3,7 @@ import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { getSelectedNetwork } from '@/state/appSelectors'; import { useAppSelector } from '@/state/appTypes'; -interface EndpointsConfig { +export interface EndpointsConfig { indexers: { api: string; socket: string; From 27acae512b2945bfe084cf13b6ae4d32c8b73073 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 3 Dec 2024 18:16:16 -0500 Subject: [PATCH 09/65] fix --- src/abacus-ts/websocket/markets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index 4d026841c..ba925ffb8 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -97,7 +97,7 @@ export function setUpMarkets(store: RootStore) { const newUrl = selectWebsocketUrl(store.getState()); if (newUrl !== lastUrl) { lastTracker?.teardown(); - // let the manager know we're not using it anymore either + // todo: let the manager know we're not using it anymore either // but this is getting to be a lot of bookkeeping lastUrl = undefined; lastTracker = undefined; From 7cd5506e44475c80288414f5f4641652192146cb Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 3 Dec 2024 18:19:26 -0500 Subject: [PATCH 10/65] fix --- src/abacus-ts/websocket/markets.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index ba925ffb8..f7914c75b 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -99,11 +99,9 @@ export function setUpMarkets(store: RootStore) { lastTracker?.teardown(); // todo: let the manager know we're not using it anymore either // but this is getting to be a lot of bookkeeping - lastUrl = undefined; - lastTracker = undefined; + lastUrl = newUrl; + lastTracker = new MarketsTracker(IndexerWebsocketManager.get(newUrl)); + lastTracker.addSubscriber((val) => store.dispatch(SetRawMarkets(val))); } - lastUrl = newUrl; - lastTracker = new MarketsTracker(IndexerWebsocketManager.get(newUrl)); - lastTracker.addSubscriber((val) => store.dispatch(SetRawMarkets(val))); }); } From 595e1a0cfa44cf029f92063575e884f54fc63141 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 4 Dec 2024 18:32:06 -0500 Subject: [PATCH 11/65] bunch of fixes and refactors --- src/abacus-ts/createStoreEffect.ts | 21 +++ src/abacus-ts/loadable.ts | 11 +- src/abacus-ts/socketSelectors.ts | 12 ++ src/abacus-ts/storeLifecycles.ts | 3 + src/abacus-ts/types.ts | 41 +++++ .../websocket/indexerWebsocketManager.ts | 35 +++- src/abacus-ts/websocket/markets.ts | 152 +++++++----------- src/abacus-ts/websocket/parentSubaccount.ts | 71 ++++++++ src/abacus-ts/websocket/subscribableValue.ts | 41 ----- .../websocket/websocketDerivedValue.ts | 44 +++++ src/state/_store.ts | 9 ++ src/state/raw.ts | 28 ++++ src/types/indexer/indexerManual.ts | 22 +++ 13 files changed, 350 insertions(+), 140 deletions(-) create mode 100644 src/abacus-ts/createStoreEffect.ts create mode 100644 src/abacus-ts/socketSelectors.ts create mode 100644 src/abacus-ts/storeLifecycles.ts create mode 100644 src/abacus-ts/types.ts delete mode 100644 src/abacus-ts/websocket/subscribableValue.ts create mode 100644 src/abacus-ts/websocket/websocketDerivedValue.ts create mode 100644 src/state/raw.ts diff --git a/src/abacus-ts/createStoreEffect.ts b/src/abacus-ts/createStoreEffect.ts new file mode 100644 index 000000000..8d4f66226 --- /dev/null +++ b/src/abacus-ts/createStoreEffect.ts @@ -0,0 +1,21 @@ +import { type RootState, type RootStore } from '@/state/_store'; + +type CleanupFn = () => void; + +export function createStoreEffect( + store: RootStore, + selector: (state: RootState) => T, + handleChange: (val: NoInfer) => CleanupFn | undefined +): CleanupFn { + let lastValue = selector(store.getState()); + let lastCleanup = handleChange(lastValue); + + return store.subscribe(() => { + const thisValue = selector(store.getState()); + if (thisValue !== lastValue) { + lastCleanup?.(); + lastValue = thisValue; + lastCleanup = handleChange(thisValue); + } + }); +} diff --git a/src/abacus-ts/loadable.ts b/src/abacus-ts/loadable.ts index 1117596e6..59528c3fe 100644 --- a/src/abacus-ts/loadable.ts +++ b/src/abacus-ts/loadable.ts @@ -1,10 +1,15 @@ export type Loadable = + | { status: 'idle'; data: undefined } | { status: 'success'; data: T } | { status: 'pending'; data?: T } - | { status: 'error'; error: any; data?: T }; + | { status: 'error'; data?: T; error: any }; -export function loadablePending() { - return { status: 'pending' } as const; +export function loadablePending() { + return { status: 'pending' } as { status: 'pending'; data?: T }; +} + +export function loadableIdle() { + return { status: 'idle', data: undefined } as const; } export function loadableLoaded(value: T) { diff --git a/src/abacus-ts/socketSelectors.ts b/src/abacus-ts/socketSelectors.ts new file mode 100644 index 000000000..acccce51c --- /dev/null +++ b/src/abacus-ts/socketSelectors.ts @@ -0,0 +1,12 @@ +import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; + +import { EndpointsConfig } from '@/hooks/useEndpointsConfig'; + +import { getSelectedNetwork } from '@/state/appSelectors'; +import { createAppSelector } from '@/state/appTypes'; + +const suffix = '/v4/ws'; +export const selectWebsocketUrl = createAppSelector(getSelectedNetwork, (network) => { + const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; + return `${endpointsConfig.indexers[0]!.socket}${suffix}`; +}); diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts new file mode 100644 index 000000000..375b16892 --- /dev/null +++ b/src/abacus-ts/storeLifecycles.ts @@ -0,0 +1,3 @@ +import { setUpMarkets } from './websocket/markets'; + +export const storeLifecycles = [setUpMarkets] as const; diff --git a/src/abacus-ts/types.ts b/src/abacus-ts/types.ts new file mode 100644 index 000000000..8767aad1e --- /dev/null +++ b/src/abacus-ts/types.ts @@ -0,0 +1,41 @@ +import { + IndexerAssetPositionResponseObject, + IndexerHistoricalBlockTradingReward, + IndexerPerpetualMarketResponseObject, + IndexerPerpetualPositionResponseObject, + IndexerTransferResponseObject, +} from '@/types/indexer/indexerApiGen'; +import { + IndexerCompositeFillObject, + IndexerCompositeOrderObject, +} from '@/types/indexer/indexerManual'; + +export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; + +export interface ParentSubaccountData { + address: string; + parentSubaccount: number; + + childSubaccounts: { [subaccountNumber: string]: ChildSubaccountData }; + + // this data is lost on websocket reconnect, should never be trusted as the ONLY source for this information + // it should be used to trigger a rest call refresh (debounced) and merged with the rest call result until the refresh completes + ephemeral: { + tradingRewards?: IndexerHistoricalBlockTradingReward[]; + fills?: IndexerCompositeFillObject[]; + orders?: IndexerCompositeOrderObject[]; + transfers?: IndexerTransferResponseObject[]; + }; +} + +export interface ChildSubaccountData { + address: string; + + subaccountNumber: number; + + openPerpetualPositions: { [market: string]: IndexerPerpetualPositionResponseObject }; + + assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; + + marginEnabled: boolean; +} diff --git a/src/abacus-ts/websocket/indexerWebsocketManager.ts b/src/abacus-ts/websocket/indexerWebsocketManager.ts index b25a2e48d..6b7a94f41 100644 --- a/src/abacus-ts/websocket/indexerWebsocketManager.ts +++ b/src/abacus-ts/websocket/indexerWebsocketManager.ts @@ -1,25 +1,48 @@ import { IndexerWebsocket } from './indexerWebsocket'; -const cachedWebsockets: { [url: string]: IndexerWebsocket } = {}; +const cachedWebsockets: { + [url: string]: { + ws: IndexerWebsocket; + count: number; + destroyTimeout?: NodeJS.Timeout | undefined; + }; +} = {}; function getIndexerWs(url: string) { if (cachedWebsockets[url] == null) { // eslint-disable-next-line no-console console.log('IndexerWsManager: spinning up @ ', url); } - cachedWebsockets[url] ??= new IndexerWebsocket(url); - return cachedWebsockets[url]; + cachedWebsockets[url] ??= { ws: new IndexerWebsocket(url), count: 0 }; + cachedWebsockets[url].count += 1; + clearTimeout(cachedWebsockets[url].destroyTimeout); + return cachedWebsockets[url].ws; +} + +function martkDoneUsingIndexerWs(url: string) { + if (cachedWebsockets[url] == null) { + // eslint-disable-next-line no-console + console.log('IndexerWsManager: marking done non existent websocket ', url); + return; + } + cachedWebsockets[url].count -= 1; + + // destroy after 1s with no users + clearTimeout(cachedWebsockets[url].destroyTimeout); + if (cachedWebsockets[url].count === 0) { + cachedWebsockets[url].destroyTimeout = setTimeout(() => destroyIndexerWs(url), 1000); + } } function destroyIndexerWs(url: string) { // eslint-disable-next-line no-console console.log('IndexerWsManager: tearing down @ ', url); - cachedWebsockets[url]?.teardown(); + cachedWebsockets[url]?.ws.teardown(); delete cachedWebsockets[url]; } export const IndexerWebsocketManager = { - get: getIndexerWs, - teardown: destroyIndexerWs, + use: getIndexerWs, + markDone: martkDoneUsingIndexerWs, }; diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index f7914c75b..d1d2d53d0 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -1,107 +1,79 @@ -import { - IndexerPerpetualMarketResponse, - IndexerPerpetualMarketResponseObject, -} from '@/types/indexer/indexerApiGen'; +import { IndexerPerpetualMarketResponse } from '@/types/indexer/indexerApiGen'; import { IndexerWsMarketUpdateResponse } from '@/types/indexer/indexerManual'; -import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; - -import { EndpointsConfig } from '@/hooks/useEndpointsConfig'; - -import { RootStore } from '@/state/_store'; -import { getSelectedNetwork } from '@/state/appSelectors'; -import { createAppSelector } from '@/state/appTypes'; +import { type RootStore } from '@/state/_store'; +import { setAllMarketsRaw } from '@/state/raw'; +import { createStoreEffect } from '../createStoreEffect'; import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { selectWebsocketUrl } from '../socketSelectors'; +import { MarketsData } from '../types'; import { IndexerWebsocket } from './indexerWebsocket'; import { IndexerWebsocketManager } from './indexerWebsocketManager'; -import { SubscribableValue } from './subscribableValue'; - -type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; - -class MarketsTracker { - private state = new SubscribableValue>(loadablePending()); +import { WebsocketDerivedValue } from './websocketDerivedValue'; - private unsub: (() => void) | undefined; - - constructor(private websocket: IndexerWebsocket) { - this.unsub = this.websocket.addChannelSubscription({ +function marketsWebsocketValue( + websocket: IndexerWebsocket, + onChange: (val: Loadable) => void +) { + return new WebsocketDerivedValue>( + websocket, + { channel: 'v4_markets', id: undefined, - handleBaseData: this._handleBase, - handleUpdates: this._handleUpdates, - }); - } - - public addSubscriber(handle: (val: Loadable) => void): () => void { - return this.state.addSubscriber(handle); - } - - public teardown() { - this.unsub?.(); - this.state.clearSubs(); - this.unsub = undefined; - } - - private _handleBase = (baseMessage: any) => { - const message = baseMessage as IndexerPerpetualMarketResponse; - this.state.setValue(loadableLoaded(message.markets)); - }; - - private _handleUpdates = (baseUpdates: any[]) => { - const updates = baseUpdates as IndexerWsMarketUpdateResponse[]; - let startingValue = this.state.getValue().data; - if (startingValue == null) { - // eslint-disable-next-line no-console - console.log('MarketsTracker found unexpectedly null base data in update'); - return; - } - startingValue = { ...startingValue }; - updates.forEach((update) => { - if (update.oraclePrices != null) { - Object.entries(update.oraclePrices).forEach(([marketId, oraclePriceObj]) => { - if (startingValue[marketId] != null && oraclePriceObj.oraclePrice != null) { - startingValue[marketId] = { - ...startingValue[marketId], - oraclePrice: oraclePriceObj.oraclePrice, - }; + handleBaseData: (baseMessage) => { + const message = baseMessage as IndexerPerpetualMarketResponse; + return loadableLoaded(message.markets); + }, + handleUpdates: (baseUpdates, value) => { + const updates = baseUpdates as IndexerWsMarketUpdateResponse[]; + let startingValue = value.data; + if (startingValue == null) { + // eslint-disable-next-line no-console + console.log('MarketsTracker found unexpectedly null base data in update'); + return value; + } + startingValue = { ...startingValue }; + updates.forEach((update) => { + if (update.oraclePrices != null) { + Object.entries(update.oraclePrices).forEach(([marketId, oraclePriceObj]) => { + if (startingValue[marketId] != null && oraclePriceObj.oraclePrice != null) { + startingValue[marketId] = { + ...startingValue[marketId], + oraclePrice: oraclePriceObj.oraclePrice, + }; + } + }); } - }); - } - if (update.trading != null) { - Object.entries(update.trading).forEach(([marketId, updateObj]) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (startingValue[marketId] != null && updateObj != null) { - startingValue[marketId] = { - ...startingValue[marketId], - ...updateObj, - }; + if (update.trading != null) { + Object.entries(update.trading).forEach(([marketId, updateObj]) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (startingValue[marketId] != null && updateObj != null) { + startingValue[marketId] = { + ...startingValue[marketId], + ...updateObj, + }; + } + }); } }); - } - }); - this.state.setValue({ ...this.state.getValue(), data: startingValue }); - }; + return loadableLoaded(startingValue); + }, + }, + loadablePending(), + onChange + ); } -let lastTracker: MarketsTracker | undefined; -let lastUrl: string | undefined; - -const selectWebsocketUrl = createAppSelector(getSelectedNetwork, (network) => { - const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; - return endpointsConfig.indexers[0]!.socket; -}); - export function setUpMarkets(store: RootStore) { - return store.subscribe(() => { - const newUrl = selectWebsocketUrl(store.getState()); - if (newUrl !== lastUrl) { - lastTracker?.teardown(); - // todo: let the manager know we're not using it anymore either - // but this is getting to be a lot of bookkeeping - lastUrl = newUrl; - lastTracker = new MarketsTracker(IndexerWebsocketManager.get(newUrl)); - lastTracker.addSubscriber((val) => store.dispatch(SetRawMarkets(val))); - } + return createStoreEffect(store, selectWebsocketUrl, (wsUrl) => { + const thisTracker = marketsWebsocketValue(IndexerWebsocketManager.use(wsUrl), (val) => + store.dispatch(setAllMarketsRaw(val)) + ); + + return () => { + thisTracker.teardown(); + IndexerWebsocketManager.markDone(wsUrl); + }; }); } diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index e69de29bb..00fa0a40c 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -0,0 +1,71 @@ +import { + IndexerWsParentSubaccountSubscribedResponse, + IndexerWsParentSubaccountUpdateObject, +} from '@/types/indexer/indexerManual'; + +import { RootState, RootStore } from '@/state/_store'; +import { createAppSelector } from '@/state/appTypes'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { createStoreEffect } from '../createStoreEffect'; +import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { selectWebsocketUrl } from '../socketSelectors'; +import { MarketsData } from '../types'; +import { IndexerWebsocket } from './indexerWebsocket'; +import { IndexerWebsocketManager } from './indexerWebsocketManager'; +import { WebsocketDerivedValue } from './websocketDerivedValue'; + +function accountWebsocketValue( + websocket: IndexerWebsocket, + address: string, + subaccount: string, + onChange: (val: Loadable) => void +) { + return new WebsocketDerivedValue>( + websocket, + { + channel: 'v4_parent_subaccount', + id: `${address}/${subaccount}`, + handleBaseData: (baseMessage) => { + const message = baseMessage as IndexerWsParentSubaccountSubscribedResponse; + return loadableLoaded(message.markets); + }, + handleUpdates: (baseUpdates, value) => { + const updates = baseUpdates as IndexerWsParentSubaccountUpdateObject[]; + let startingValue = value.data; + return { ...value }; + }, + }, + loadablePending(), + onChange + ); +} + +const getUserWalletAddress = (state: RootState) => state.account.wallet?.walletAddress; +const getUserSubaccount = (state: RootState) => state.account.subaccount?.subaccountNumber; +const selectParentSubaccountInfo = createAppSelector( + selectWebsocketUrl, + getUserWalletAddress, + getUserSubaccount, + (wsUrl, wallet, subaccount) => ({ wsUrl, wallet, subaccount }) +); + +export function setUpAccount(store: RootStore) { + return createStoreEffect(store, selectParentSubaccountInfo, ({ subaccount, wallet, wsUrl }) => { + if (!isTruthy(wallet) || subaccount == null) { + return undefined; + } + const thisTracker = accountWebsocketValue( + IndexerWebsocketManager.use(wsUrl), + wallet, + subaccount.toString(), + (val) => store.dispatch(SetRawAccount(val)) + ); + + return () => { + thisTracker.teardown(); + IndexerWebsocketManager.markDone(wsUrl); + }; + }); +} diff --git a/src/abacus-ts/websocket/subscribableValue.ts b/src/abacus-ts/websocket/subscribableValue.ts deleted file mode 100644 index a71e037a5..000000000 --- a/src/abacus-ts/websocket/subscribableValue.ts +++ /dev/null @@ -1,41 +0,0 @@ -type Subscriber = (value: T) => void; -type Unsubscribe = () => void; - -export class SubscribableValue { - private value: T; - - private subscribers: Set> = new Set(); - - constructor(initialValue: T) { - this.value = initialValue; - } - - getValue(): T { - return this.value; - } - - setValue(newValue: T): void { - // todo shallow equal option - if (newValue !== this.value) { - this.value = newValue; - this.subscribers.forEach((subscriber) => { - subscriber(this.value); - }); - } - } - - addSubscriber(subscriber: Subscriber): Unsubscribe { - this.subscribers.add(subscriber); - - // Immediately notify new subscriber of current value - subscriber(this.value); - - return () => { - this.subscribers.delete(subscriber); - }; - } - - clearSubs() { - this.subscribers = new Set(); - } -} diff --git a/src/abacus-ts/websocket/websocketDerivedValue.ts b/src/abacus-ts/websocket/websocketDerivedValue.ts new file mode 100644 index 000000000..0c9ea3dc8 --- /dev/null +++ b/src/abacus-ts/websocket/websocketDerivedValue.ts @@ -0,0 +1,44 @@ +import { IndexerWebsocket } from './indexerWebsocket'; + +type Unsubscribe = () => void; + +export class WebsocketDerivedValue { + private unsubFromWs: Unsubscribe | undefined; + + constructor( + websocket: IndexerWebsocket, + // subscriptions must be unique, we are trusing whoever is constructing us is ensuring uniqueness + sub: { + channel: string; + id: string | undefined; + handleBaseData: (data: any, value: T) => T; + handleUpdates: (updates: any[], value: T) => T; + }, + private value: T, + private changeHandler: ((val: T) => void) | undefined + ) { + this.unsubFromWs = websocket.addChannelSubscription({ + channel: sub.channel, + id: sub.id, + handleBaseData: (data) => this._setValue(sub.handleBaseData(data, this.value)), + handleUpdates: (updates) => this._setValue(sub.handleUpdates(updates, this.value)), + }); + } + + getValue(): T { + return this.value; + } + + teardown() { + this.changeHandler = undefined; + this.unsubFromWs?.(); + this.unsubFromWs = undefined; + } + + private _setValue = (newValue: T): void => { + if (newValue !== this.value) { + this.value = newValue; + this.changeHandler?.(this.value); + } + }; +} diff --git a/src/state/_store.ts b/src/state/_store.ts index 29e79bf86..1a016a50d 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -1,3 +1,4 @@ +import { storeLifecycles } from '@/abacus-ts/storeLifecycles'; import { Middleware, combineReducers, configureStore } from '@reduxjs/toolkit'; import { persistReducer, persistStore } from 'redux-persist'; import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; @@ -23,6 +24,7 @@ import localizationMiddleware from './localizationMiddleware'; import { customCreateMigrate } from './migrations'; import { notificationsSlice } from './notifications'; import { perpetualsSlice } from './perpetuals'; +import { rawSlice } from './raw'; import { tradingViewSlice } from './tradingView'; import { vaultsSlice } from './vaults'; import { walletSlice } from './wallet'; @@ -46,6 +48,7 @@ const reducers = { tradingView: tradingViewSlice.reducer, vaults: vaultsSlice.reducer, wallet: walletSlice.reducer, + raw: rawSlice.reducer, } as const; const rootReducer = combineReducers(reducers); @@ -91,6 +94,12 @@ export const persistor = persistStore(store); // Set store so (Abacus & v4-Client) classes can getState and dispatch abacusStateManager.setStore(store); +const useAbacusTs: boolean = true; +if (useAbacusTs) { + // we ignore the cleanups for now since we want these running forever + storeLifecycles.forEach((fn) => fn(store)); +} + export type RootStore = typeof store; export type RootState = ReturnType; export type AppDispatch = RootStore['dispatch']; diff --git a/src/state/raw.ts b/src/state/raw.ts new file mode 100644 index 000000000..6405b5ccb --- /dev/null +++ b/src/state/raw.ts @@ -0,0 +1,28 @@ +import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; +import { MarketsData } from '@/abacus-ts/types'; +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +export interface RawDataState { + markets: { + allMarkets: Loadable; + }; + account: {}; +} + +const initialState: RawDataState = { + markets: { allMarkets: loadableIdle() }, + account: {}, +}; + +export const rawSlice = createSlice({ + name: 'Raw data', + initialState, + reducers: { + setAllMarketsRaw: (state: RawDataState, action: PayloadAction>) => ({ + ...state, + markets: { ...state.markets, allMarkets: action.payload }, + }), + }, +}); + +export const { setAllMarketsRaw } = rawSlice.actions; diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 4223eae9a..1783f7196 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -1,14 +1,20 @@ import { IndexerAPIOrderStatus, IndexerAPITimeInForce, + IndexerAssetPositionResponseObject, IndexerFillType, + IndexerHistoricalBlockTradingReward, IndexerIsoString, IndexerLiquidity, IndexerMarketType, + IndexerOrderResponseObject, IndexerOrderSide, IndexerOrderType, + IndexerParentSubaccountResponse, IndexerPerpetualMarketStatus, IndexerPerpetualMarketType, + IndexerPerpetualPositionResponseObject, + IndexerTransferResponseObject, } from './indexerApiGen'; export interface IndexerCompositeFillResponse { @@ -115,3 +121,19 @@ export interface IndexerCompositeFillObject { subaccountNumber?: number; ticker?: string; } + +export interface IndexerWsParentSubaccountSubscribedResponse { + subaccount: IndexerParentSubaccountResponse; + blockHeight: string; + orders: IndexerOrderResponseObject[]; +} + +export interface IndexerWsParentSubaccountUpdateObject { + blockHeight: string; + assetPositions?: IndexerAssetPositionResponseObject[]; + perpetualPositions?: IndexerPerpetualPositionResponseObject[]; + tradingReward?: IndexerHistoricalBlockTradingReward; + fills?: IndexerCompositeFillObject[]; + orders?: IndexerCompositeOrderObject[]; + transfers?: IndexerTransferResponseObject[] | IndexerTransferResponseObject; +} From 306b31b71430fcc435b4b507dce90ad1bbb77e49 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 5 Dec 2024 15:56:02 -0500 Subject: [PATCH 12/65] fix --- src/abacus-ts/storeLifecycles.ts | 3 +- src/abacus-ts/types.ts | 6 +- src/abacus-ts/websocket/indexerWebsocket.ts | 23 +-- src/abacus-ts/websocket/parentSubaccount.ts | 142 ++++++++++++++++-- .../websocket/reconnectingWebsocket.ts | 3 + .../websocket/websocketDerivedValue.ts | 10 +- src/state/raw.ts | 22 ++- src/types/indexer/indexerManual.ts | 2 +- 8 files changed, 173 insertions(+), 38 deletions(-) diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index 375b16892..ec4f05d00 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -1,3 +1,4 @@ import { setUpMarkets } from './websocket/markets'; +import { setUpParentSubaccount } from './websocket/parentSubaccount'; -export const storeLifecycles = [setUpMarkets] as const; +export const storeLifecycles = [setUpMarkets, setUpParentSubaccount] as const; diff --git a/src/abacus-ts/types.ts b/src/abacus-ts/types.ts index 8767aad1e..80e269ae3 100644 --- a/src/abacus-ts/types.ts +++ b/src/abacus-ts/types.ts @@ -16,14 +16,14 @@ export interface ParentSubaccountData { address: string; parentSubaccount: number; - childSubaccounts: { [subaccountNumber: string]: ChildSubaccountData }; + childSubaccounts: { [subaccountNumber: string]: ChildSubaccountData | undefined }; // this data is lost on websocket reconnect, should never be trusted as the ONLY source for this information // it should be used to trigger a rest call refresh (debounced) and merged with the rest call result until the refresh completes ephemeral: { tradingRewards?: IndexerHistoricalBlockTradingReward[]; fills?: IndexerCompositeFillObject[]; - orders?: IndexerCompositeOrderObject[]; + orders?: { [orderId: string]: IndexerCompositeOrderObject }; transfers?: IndexerTransferResponseObject[]; }; } @@ -36,6 +36,4 @@ export interface ChildSubaccountData { openPerpetualPositions: { [market: string]: IndexerPerpetualPositionResponseObject }; assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; - - marginEnabled: boolean; } diff --git a/src/abacus-ts/websocket/indexerWebsocket.ts b/src/abacus-ts/websocket/indexerWebsocket.ts index 206e01eb2..5879df9a8 100644 --- a/src/abacus-ts/websocket/indexerWebsocket.ts +++ b/src/abacus-ts/websocket/indexerWebsocket.ts @@ -14,8 +14,8 @@ export class IndexerWebsocket { channel: string; id: string | undefined; batched: boolean; - handleBaseData: (data: any) => void; - handleUpdates: (updates: any[]) => void; + handleBaseData: (data: any, fullMessage: any) => void; + handleUpdates: (updates: any[], fullMessage: any) => void; sentSubMessage: boolean; }; }; @@ -45,8 +45,8 @@ export class IndexerWebsocket { channel: string; id: string | undefined; batched?: boolean; - handleBaseData: (data: any) => void; - handleUpdates: (data: any[]) => void; + handleBaseData: (data: any, fullMessage: any) => void; + handleUpdates: (data: any[], fullMessage: any) => void; }): () => void { this.subscriptions[channel] ??= {}; if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] != null) { @@ -118,15 +118,20 @@ export class IndexerWebsocket { } if (message.type === 'subscribed') { this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleBaseData( - message.contents + message.contents, + message ); } else if (message.type === 'channel_data') { - this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates([ - message.contents, - ]); + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( + [message.contents], + message + ); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition } else if (message.type === 'channel_batch_data') { - this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates(message.contents); + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( + message.contents, + message + ); } else { assertNever(message); } diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 00fa0a40c..8ded1b14e 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -1,40 +1,160 @@ +import { IndexerSubaccountResponseObject } from '@/types/indexer/indexerApiGen'; import { IndexerWsParentSubaccountSubscribedResponse, IndexerWsParentSubaccountUpdateObject, } from '@/types/indexer/indexerManual'; +import { keyBy } from 'lodash'; -import { RootState, RootStore } from '@/state/_store'; +import { type RootState, type RootStore } from '@/state/_store'; import { createAppSelector } from '@/state/appTypes'; +import { setParentSubaccountRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { createStoreEffect } from '../createStoreEffect'; import { Loadable, loadableLoaded, loadablePending } from '../loadable'; import { selectWebsocketUrl } from '../socketSelectors'; -import { MarketsData } from '../types'; +import { ChildSubaccountData, ParentSubaccountData } from '../types'; import { IndexerWebsocket } from './indexerWebsocket'; import { IndexerWebsocketManager } from './indexerWebsocketManager'; import { WebsocketDerivedValue } from './websocketDerivedValue'; +function isValidSubaccount(childSubaccount: IndexerSubaccountResponseObject) { + return ( + Object.keys(childSubaccount.assetPositions).length > 0 || + Object.keys(childSubaccount.openPerpetualPositions).length > 0 + ); +} + +function convertToStoredChildSubaccount({ + address, + subaccountNumber, + assetPositions, + openPerpetualPositions, +}: IndexerSubaccountResponseObject): ChildSubaccountData { + return { + address, + subaccountNumber, + assetPositions, + openPerpetualPositions, + }; +} + +function freshChildSubaccount({ + address, + subaccountNumber, +}: { + address: string; + subaccountNumber: number; +}): ChildSubaccountData { + return { + address, + subaccountNumber, + assetPositions: {}, + openPerpetualPositions: {}, + }; +} + function accountWebsocketValue( websocket: IndexerWebsocket, address: string, subaccount: string, - onChange: (val: Loadable) => void + onChange: (val: Loadable) => void ) { - return new WebsocketDerivedValue>( + return new WebsocketDerivedValue>( websocket, { - channel: 'v4_parent_subaccount', + channel: 'v4_parent_subaccounts', id: `${address}/${subaccount}`, handleBaseData: (baseMessage) => { const message = baseMessage as IndexerWsParentSubaccountSubscribedResponse; - return loadableLoaded(message.markets); + return loadableLoaded({ + address: message.subaccount.address, + parentSubaccount: message.subaccount.parentSubaccountNumber, + childSubaccounts: keyBy( + message.subaccount.childSubaccounts + .filter(isValidSubaccount) + .map(convertToStoredChildSubaccount), + (c) => c.subaccountNumber + ), + ephemeral: { + orders: keyBy(message.orders, (o) => o.id), + }, + }); }, - handleUpdates: (baseUpdates, value) => { + handleUpdates: (baseUpdates, value, fullMessage) => { const updates = baseUpdates as IndexerWsParentSubaccountUpdateObject[]; - let startingValue = value.data; - return { ...value }; + const subaccountNumber = fullMessage?.subaccountNumber as number | undefined; + if (value.data == null || updates.length === 0 || subaccountNumber == null) { + return value; + } + const returnValue = { ...value.data }; + updates.forEach((update) => { + if (update.assetPositions != null) { + update.assetPositions.forEach((positionUpdate) => { + returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= + freshChildSubaccount({ + address, + subaccountNumber: positionUpdate.subaccountNumber, + }); + + returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.assetPositions[ + positionUpdate.assetId + ] = { + ...(returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.assetPositions[ + positionUpdate.assetId + ] ?? {}), + ...positionUpdate, + }; + }); + } + if (update.perpetualPositions != null) { + update.perpetualPositions.forEach((positionUpdate) => { + returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= + freshChildSubaccount({ + address, + subaccountNumber: positionUpdate.subaccountNumber, + }); + + returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.openPerpetualPositions[ + positionUpdate.market + ] = { + ...(returnValue.childSubaccounts[positionUpdate.subaccountNumber]! + .openPerpetualPositions[positionUpdate.market] ?? {}), + ...positionUpdate, + }; + }); + } + if (update.tradingReward != null) { + returnValue.ephemeral.tradingRewards ??= []; + returnValue.ephemeral.tradingRewards = [ + ...returnValue.ephemeral.tradingRewards, + update.tradingReward, + ]; + } + if (update.fills != null) { + returnValue.ephemeral.fills ??= []; + returnValue.ephemeral.fills = [ + ...returnValue.ephemeral.fills, + ...update.fills.map((f) => ({ ...f, subaccountNumber })), + ]; + } + if (update.orders != null) { + returnValue.ephemeral.orders ??= {}; + returnValue.ephemeral.orders = { + ...returnValue.ephemeral.orders, + ...keyBy(update.orders, (o) => o.id ?? ''), + }; + } + if (update.transfers != null) { + returnValue.ephemeral.transfers ??= []; + returnValue.ephemeral.transfers = [ + ...returnValue.ephemeral.transfers, + update.transfers, + ]; + } + }); + return { ...value, data: returnValue }; }, }, loadablePending(), @@ -51,7 +171,7 @@ const selectParentSubaccountInfo = createAppSelector( (wsUrl, wallet, subaccount) => ({ wsUrl, wallet, subaccount }) ); -export function setUpAccount(store: RootStore) { +export function setUpParentSubaccount(store: RootStore) { return createStoreEffect(store, selectParentSubaccountInfo, ({ subaccount, wallet, wsUrl }) => { if (!isTruthy(wallet) || subaccount == null) { return undefined; @@ -60,7 +180,7 @@ export function setUpAccount(store: RootStore) { IndexerWebsocketManager.use(wsUrl), wallet, subaccount.toString(), - (val) => store.dispatch(SetRawAccount(val)) + (val) => store.dispatch(setParentSubaccountRaw(val)) ); return () => { diff --git a/src/abacus-ts/websocket/reconnectingWebsocket.ts b/src/abacus-ts/websocket/reconnectingWebsocket.ts index 1e75b02e7..6056f2b86 100644 --- a/src/abacus-ts/websocket/reconnectingWebsocket.ts +++ b/src/abacus-ts/websocket/reconnectingWebsocket.ts @@ -68,6 +68,9 @@ export class ReconnectingWebSocket { this.ws.onopen = () => { this.currentReconnectInterval = this.initialReconnectInterval; + // eslint-disable-next-line no-console + console.log('ReconnectingWebsocket: Connected to ', this.url); + this.handleFreshConnect(); }; } catch (error) { diff --git a/src/abacus-ts/websocket/websocketDerivedValue.ts b/src/abacus-ts/websocket/websocketDerivedValue.ts index 0c9ea3dc8..a39ec4352 100644 --- a/src/abacus-ts/websocket/websocketDerivedValue.ts +++ b/src/abacus-ts/websocket/websocketDerivedValue.ts @@ -11,8 +11,8 @@ export class WebsocketDerivedValue { sub: { channel: string; id: string | undefined; - handleBaseData: (data: any, value: T) => T; - handleUpdates: (updates: any[], value: T) => T; + handleBaseData: (data: any, value: T, fullMessage: any) => T; + handleUpdates: (updates: any[], value: T, fullMessage: any) => T; }, private value: T, private changeHandler: ((val: T) => void) | undefined @@ -20,8 +20,10 @@ export class WebsocketDerivedValue { this.unsubFromWs = websocket.addChannelSubscription({ channel: sub.channel, id: sub.id, - handleBaseData: (data) => this._setValue(sub.handleBaseData(data, this.value)), - handleUpdates: (updates) => this._setValue(sub.handleUpdates(updates, this.value)), + handleBaseData: (data, fullMessage) => + this._setValue(sub.handleBaseData(data, this.value, fullMessage)), + handleUpdates: (updates, fullMessage) => + this._setValue(sub.handleUpdates(updates, this.value, fullMessage)), }); } diff --git a/src/state/raw.ts b/src/state/raw.ts index 6405b5ccb..4ac701f3a 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,28 +1,34 @@ import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; -import { MarketsData } from '@/abacus-ts/types'; +import { MarketsData, ParentSubaccountData } from '@/abacus-ts/types'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; export interface RawDataState { markets: { allMarkets: Loadable; }; - account: {}; + account: { + parentSubaccount: Loadable; + }; } const initialState: RawDataState = { markets: { allMarkets: loadableIdle() }, - account: {}, + account: { + parentSubaccount: loadableIdle(), + }, }; export const rawSlice = createSlice({ name: 'Raw data', initialState, reducers: { - setAllMarketsRaw: (state: RawDataState, action: PayloadAction>) => ({ - ...state, - markets: { ...state.markets, allMarkets: action.payload }, - }), + setAllMarketsRaw: (state, action: PayloadAction>) => { + state.markets.allMarkets = action.payload; + }, + setParentSubaccountRaw: (state, action: PayloadAction>) => { + state.account.parentSubaccount = action.payload; + }, }, }); -export const { setAllMarketsRaw } = rawSlice.actions; +export const { setAllMarketsRaw, setParentSubaccountRaw } = rawSlice.actions; diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 1783f7196..286f13712 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -135,5 +135,5 @@ export interface IndexerWsParentSubaccountUpdateObject { tradingReward?: IndexerHistoricalBlockTradingReward; fills?: IndexerCompositeFillObject[]; orders?: IndexerCompositeOrderObject[]; - transfers?: IndexerTransferResponseObject[] | IndexerTransferResponseObject; + transfers?: IndexerTransferResponseObject; } From 91f1196768385d679bf864f707c84d893fb1f4a8 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 5 Dec 2024 19:37:05 -0500 Subject: [PATCH 13/65] fix --- package.json | 2 +- pnpm-lock.yaml | 8 +-- src/abacus-ts/socketSelectors.ts | 5 ++ src/abacus-ts/storeLifecycles.ts | 9 +++- .../websocket/indexerWebsocketManager.ts | 52 +++---------------- src/abacus-ts/websocket/markets.ts | 9 +++- src/abacus-ts/websocket/parentSubaccount.ts | 15 ++++-- src/state/accountSelectors.ts | 5 ++ src/state/raw.ts | 20 ++++++- 9 files changed, 66 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index 182a7aef3..390c33ddb 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@cosmjs/tendermint-rpc": "^0.32.1", "@datadog/browser-logs": "^5.23.3", "@dydxprotocol/v4-abacus": "1.13.39", - "@dydxprotocol/v4-client-js": "1.12.2", + "@dydxprotocol/v4-client-js": "1.15.0", "@dydxprotocol/v4-localization": "^1.1.254", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", "@emotion/is-prop-valid": "^1.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 116b093e7..30994c37b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ dependencies: specifier: 1.13.39 version: 1.13.39 '@dydxprotocol/v4-client-js': - specifier: 1.12.2 - version: 1.12.2 + specifier: 1.15.0 + version: 1.15.0 '@dydxprotocol/v4-localization': specifier: ^1.1.254 version: 1.1.254 @@ -3294,8 +3294,8 @@ packages: format-util: 1.0.5 dev: false - /@dydxprotocol/v4-client-js@1.12.2: - resolution: {integrity: sha512-iW1HoOx8XcFzsGfldVyh64Tdy3GRDfeaEWQvy1KT4KWZ6xINMyqs5i6E7Wl8IHtkPQzkzWMN1Exw3JPkXJfGXA==} + /@dydxprotocol/v4-client-js@1.15.0: + resolution: {integrity: sha512-ROQFcv8+dkDMzJzFscNRzE+MGbaDW+KwoBqKl7e/P0lnLZ0tuvVhQPNlz2ArouInyL93+aKjJJNQ6hAMOoijJQ==} dependencies: '@cosmjs/amino': 0.32.4 '@cosmjs/encoding': 0.32.4 diff --git a/src/abacus-ts/socketSelectors.ts b/src/abacus-ts/socketSelectors.ts index acccce51c..cf3f0d976 100644 --- a/src/abacus-ts/socketSelectors.ts +++ b/src/abacus-ts/socketSelectors.ts @@ -10,3 +10,8 @@ export const selectWebsocketUrl = createAppSelector(getSelectedNetwork, (network const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; return `${endpointsConfig.indexers[0]!.socket}${suffix}`; }); + +export const selectIndexerUrl = createAppSelector(getSelectedNetwork, (network) => { + const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; + return `${endpointsConfig.indexers[0]!.api}`; +}); diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index ec4f05d00..83f57b1c0 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -1,4 +1,11 @@ +import { setUpFillsQuery } from './rest/fills'; +import { setUpOrdersQuery } from './rest/orders'; import { setUpMarkets } from './websocket/markets'; import { setUpParentSubaccount } from './websocket/parentSubaccount'; -export const storeLifecycles = [setUpMarkets, setUpParentSubaccount] as const; +export const storeLifecycles = [ + setUpMarkets, + setUpParentSubaccount, + setUpFillsQuery, + setUpOrdersQuery, +] as const; diff --git a/src/abacus-ts/websocket/indexerWebsocketManager.ts b/src/abacus-ts/websocket/indexerWebsocketManager.ts index 6b7a94f41..1087e6c56 100644 --- a/src/abacus-ts/websocket/indexerWebsocketManager.ts +++ b/src/abacus-ts/websocket/indexerWebsocketManager.ts @@ -1,48 +1,8 @@ +import { ResourceCacheManager } from '../resourceCacheManager'; import { IndexerWebsocket } from './indexerWebsocket'; -const cachedWebsockets: { - [url: string]: { - ws: IndexerWebsocket; - count: number; - destroyTimeout?: NodeJS.Timeout | undefined; - }; -} = {}; - -function getIndexerWs(url: string) { - if (cachedWebsockets[url] == null) { - // eslint-disable-next-line no-console - console.log('IndexerWsManager: spinning up @ ', url); - } - cachedWebsockets[url] ??= { ws: new IndexerWebsocket(url), count: 0 }; - cachedWebsockets[url].count += 1; - clearTimeout(cachedWebsockets[url].destroyTimeout); - return cachedWebsockets[url].ws; -} - -function martkDoneUsingIndexerWs(url: string) { - if (cachedWebsockets[url] == null) { - // eslint-disable-next-line no-console - console.log('IndexerWsManager: marking done non existent websocket ', url); - return; - } - cachedWebsockets[url].count -= 1; - - // destroy after 1s with no users - clearTimeout(cachedWebsockets[url].destroyTimeout); - if (cachedWebsockets[url].count === 0) { - cachedWebsockets[url].destroyTimeout = setTimeout(() => destroyIndexerWs(url), 1000); - } -} - -function destroyIndexerWs(url: string) { - // eslint-disable-next-line no-console - console.log('IndexerWsManager: tearing down @ ', url); - - cachedWebsockets[url]?.ws.teardown(); - delete cachedWebsockets[url]; -} - -export const IndexerWebsocketManager = { - use: getIndexerWs, - markDone: martkDoneUsingIndexerWs, -}; +export const IndexerWebsocketManager = new ResourceCacheManager({ + constructor: (wsUrl: string) => new IndexerWebsocket(wsUrl), + destroyer: (obj) => obj.teardown(), + keySerializer: (str) => str, +}); diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index d1d2d53d0..1c6ad9d46 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -1,5 +1,8 @@ import { IndexerPerpetualMarketResponse } from '@/types/indexer/indexerApiGen'; import { IndexerWsMarketUpdateResponse } from '@/types/indexer/indexerManual'; +import { throttle } from 'lodash'; + +import { timeUnits } from '@/constants/time'; import { type RootStore } from '@/state/_store'; import { setAllMarketsRaw } from '@/state/raw'; @@ -66,9 +69,13 @@ function marketsWebsocketValue( } export function setUpMarkets(store: RootStore) { + const throttledSetMarkets = throttle((val: Loadable) => { + store.dispatch(setAllMarketsRaw(val)); + }, 2 * timeUnits.second); + return createStoreEffect(store, selectWebsocketUrl, (wsUrl) => { const thisTracker = marketsWebsocketValue(IndexerWebsocketManager.use(wsUrl), (val) => - store.dispatch(setAllMarketsRaw(val)) + throttledSetMarkets(val) ); return () => { diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 8ded1b14e..ab636f405 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -5,14 +5,16 @@ import { } from '@/types/indexer/indexerManual'; import { keyBy } from 'lodash'; -import { type RootState, type RootStore } from '@/state/_store'; +import { type RootStore } from '@/state/_store'; +import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; import { createAppSelector } from '@/state/appTypes'; import { setParentSubaccountRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; +import { accountRefreshSignal } from '../accountRefreshSignal'; import { createStoreEffect } from '../createStoreEffect'; -import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../loadable'; import { selectWebsocketUrl } from '../socketSelectors'; import { ChildSubaccountData, ParentSubaccountData } from '../types'; import { IndexerWebsocket } from './indexerWebsocket'; @@ -68,6 +70,8 @@ function accountWebsocketValue( id: `${address}/${subaccount}`, handleBaseData: (baseMessage) => { const message = baseMessage as IndexerWsParentSubaccountSubscribedResponse; + accountRefreshSignal.notify(); + return loadableLoaded({ address: message.subaccount.address, parentSubaccount: message.subaccount.parentSubaccountNumber, @@ -162,18 +166,19 @@ function accountWebsocketValue( ); } -const getUserWalletAddress = (state: RootState) => state.account.wallet?.walletAddress; -const getUserSubaccount = (state: RootState) => state.account.subaccount?.subaccountNumber; const selectParentSubaccountInfo = createAppSelector( selectWebsocketUrl, getUserWalletAddress, - getUserSubaccount, + getUserSubaccountNumber, (wsUrl, wallet, subaccount) => ({ wsUrl, wallet, subaccount }) ); export function setUpParentSubaccount(store: RootStore) { return createStoreEffect(store, selectParentSubaccountInfo, ({ subaccount, wallet, wsUrl }) => { if (!isTruthy(wallet) || subaccount == null) { + if (store.getState().raw.account.parentSubaccount.data != null) { + store.dispatch(setParentSubaccountRaw(loadableIdle())); + } return undefined; } const thisTracker = accountWebsocketValue( diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index c0ff08c5b..baba7393a 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -682,3 +682,8 @@ export const getComplianceUpdatedAt = (state: RootState) => state.account.compli * @returns compliance geo of the current session */ export const getGeo = (state: RootState) => state.account.compliance?.geo; + +export const getUserWalletAddress = (state: RootState) => state.account.wallet?.walletAddress; + +export const getUserSubaccountNumber = (state: RootState) => + state.account.subaccount?.subaccountNumber; diff --git a/src/state/raw.ts b/src/state/raw.ts index 4ac701f3a..8519d0c99 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,5 +1,9 @@ import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; import { MarketsData, ParentSubaccountData } from '@/abacus-ts/types'; +import { + IndexerCompositeFillResponse, + IndexerCompositeOrderObject, +} from '@/types/indexer/indexerManual'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; export interface RawDataState { @@ -8,6 +12,8 @@ export interface RawDataState { }; account: { parentSubaccount: Loadable; + fills: Loadable; + orders: Loadable<{ [id: string]: IndexerCompositeOrderObject }>; }; } @@ -15,6 +21,8 @@ const initialState: RawDataState = { markets: { allMarkets: loadableIdle() }, account: { parentSubaccount: loadableIdle(), + fills: loadableIdle(), + orders: loadableIdle(), }, }; @@ -28,7 +36,17 @@ export const rawSlice = createSlice({ setParentSubaccountRaw: (state, action: PayloadAction>) => { state.account.parentSubaccount = action.payload; }, + setAccountFillsRaw: (state, action: PayloadAction>) => { + state.account.fills = action.payload; + }, + setAccountOrdersRaw: ( + state, + action: PayloadAction> + ) => { + state.account.orders = action.payload; + }, }, }); -export const { setAllMarketsRaw, setParentSubaccountRaw } = rawSlice.actions; +export const { setAllMarketsRaw, setParentSubaccountRaw, setAccountFillsRaw, setAccountOrdersRaw } = + rawSlice.actions; From 15621c1ac27eb9336a16105e4a0f8195efb0728e Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 5 Dec 2024 19:37:56 -0500 Subject: [PATCH 14/65] add all new --- src/abacus-ts/accountRefreshSignal.ts | 5 ++ src/abacus-ts/resourceCacheManager.ts | 65 ++++++++++++++++ src/abacus-ts/rest/fills.ts | 41 ++++++++++ src/abacus-ts/rest/indexerClientManager.ts | 10 +++ src/abacus-ts/rest/indexerQueryStoreEffect.ts | 74 +++++++++++++++++++ src/abacus-ts/rest/orders.ts | 54 ++++++++++++++ src/abacus-ts/rest/transfers.ts | 0 src/abacus-ts/signal.ts | 16 ++++ 8 files changed, 265 insertions(+) create mode 100644 src/abacus-ts/accountRefreshSignal.ts create mode 100644 src/abacus-ts/resourceCacheManager.ts create mode 100644 src/abacus-ts/rest/fills.ts create mode 100644 src/abacus-ts/rest/indexerClientManager.ts create mode 100644 src/abacus-ts/rest/indexerQueryStoreEffect.ts create mode 100644 src/abacus-ts/rest/orders.ts create mode 100644 src/abacus-ts/rest/transfers.ts create mode 100644 src/abacus-ts/signal.ts diff --git a/src/abacus-ts/accountRefreshSignal.ts b/src/abacus-ts/accountRefreshSignal.ts new file mode 100644 index 000000000..ac1fcf5cb --- /dev/null +++ b/src/abacus-ts/accountRefreshSignal.ts @@ -0,0 +1,5 @@ +import { Signal } from './signal'; + +// triggers when we got fresh parent subaccount data from the websocket for any reason +// mostly network reconnects, refreshes, page visibility changes, etc +export const accountRefreshSignal = new Signal(); diff --git a/src/abacus-ts/resourceCacheManager.ts b/src/abacus-ts/resourceCacheManager.ts new file mode 100644 index 000000000..daafd5d2a --- /dev/null +++ b/src/abacus-ts/resourceCacheManager.ts @@ -0,0 +1,65 @@ +type CacheEntry = { + resource: T; + count: number; + destroyTimeout?: NodeJS.Timeout; +}; + +type Cache = { + [key: string]: CacheEntry; +}; + +export class ResourceCacheManager { + private cache: Cache = {}; + + constructor( + private options: { + constructor: (key: U) => T; + destroyer: (resource: NoInfer) => void; + keySerializer: (key: NoInfer) => string; + destroyDelayMs?: number; + } + ) {} + + use(key: U): T { + const serializedKey = this.options.keySerializer(key); + + this.cache[serializedKey] ??= { + resource: this.options.constructor(key), + count: 0, + }; + + const entry = this.cache[serializedKey]; + entry.count += 1; + + if (entry.destroyTimeout) { + clearTimeout(entry.destroyTimeout); + entry.destroyTimeout = undefined; + } + + return entry.resource; + } + + markDone(key: U): void { + const serializedKey = this.options.keySerializer(key); + const entry = this.cache[serializedKey]; + if (!entry) return; + + entry.count -= 1; + + if (entry.destroyTimeout) { + clearTimeout(entry.destroyTimeout); + entry.destroyTimeout = undefined; + } + + if (entry.count === 0) { + const delay = this.options.destroyDelayMs ?? 1000; + entry.destroyTimeout = setTimeout(() => { + const latestVal = this.cache[serializedKey]; + if (!latestVal) return; + + this.options.destroyer(latestVal.resource); + delete this.cache[serializedKey]; + }, delay); + } + } +} diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts new file mode 100644 index 000000000..aac004ab8 --- /dev/null +++ b/src/abacus-ts/rest/fills.ts @@ -0,0 +1,41 @@ +import { type RootStore } from '@/state/_store'; +import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; +import { createAppSelector } from '@/state/appTypes'; +import { setAccountFillsRaw } from '@/state/raw'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { loadableIdle } from '../loadable'; +import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; + +export function setUpFillsQuery(store: RootStore) { + const selectParentSubaccountInfo = createAppSelector( + getUserWalletAddress, + getUserSubaccountNumber, + (wallet, subaccount) => ({ wallet, subaccount }) + ); + + return createIndexerQueryStoreEffect(store, { + selector: selectParentSubaccountInfo, + getQueryKey: (data) => ['account', 'fills', data.wallet, data.subaccount], + getQueryFn: (indexerClient, data) => { + if (!isTruthy(data.wallet) || data.subaccount == null) { + if (store.getState().raw.account.fills.data != null) { + store.dispatch(setAccountFillsRaw(loadableIdle())); + } + return null; + } + return () => + indexerClient.account.getParentSubaccountNumberFills(data.wallet!, data.subaccount!); + }, + onResult: (fills) => { + store.dispatch( + setAccountFillsRaw({ + status: fills.status, + data: fills.data, + error: fills.error, + }) + ); + }, + }); +} diff --git a/src/abacus-ts/rest/indexerClientManager.ts b/src/abacus-ts/rest/indexerClientManager.ts new file mode 100644 index 000000000..c868a1a04 --- /dev/null +++ b/src/abacus-ts/rest/indexerClientManager.ts @@ -0,0 +1,10 @@ +import { IndexerClient, IndexerConfig } from '@dydxprotocol/v4-client-js'; + +import { ResourceCacheManager } from '../resourceCacheManager'; + +export const IndexerClientManager = new ResourceCacheManager({ + constructor: ({ wsUrl, url }: { url: string; wsUrl: string }) => + new IndexerClient(new IndexerConfig(url, wsUrl)), + destroyer: () => null, + keySerializer: ({ url, wsUrl }) => `${url}/////////${wsUrl}`, +}); diff --git a/src/abacus-ts/rest/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/indexerQueryStoreEffect.ts new file mode 100644 index 000000000..52ceec25c --- /dev/null +++ b/src/abacus-ts/rest/indexerQueryStoreEffect.ts @@ -0,0 +1,74 @@ +import { IndexerClient } from '@dydxprotocol/v4-client-js'; +import { QueryObserver, QueryObserverOptions, QueryObserverResult } from '@tanstack/react-query'; + +import { type RootState, type RootStore } from '@/state/_store'; +import { appQueryClient } from '@/state/appQueryClient'; +import { createAppSelector } from '@/state/appTypes'; + +import { createStoreEffect } from '../createStoreEffect'; +import { selectIndexerUrl, selectWebsocketUrl } from '../socketSelectors'; +import { IndexerClientManager } from './indexerClientManager'; + +type QuerySetupConfig = { + selector: (state: RootState) => T; + getQueryKey: (selectorResult: NoInfer) => any[]; + getQueryFn: (client: IndexerClient, selectorResult: NoInfer) => (() => Promise) | null; + onResult: (result: NoInfer>) => void; +} & Pick< + QueryObserverOptions, + | 'staleTime' + | 'gcTime' + | 'refetchInterval' + | 'refetchOnWindowFocus' + | 'refetchIntervalInBackground' + | 'refetchOnReconnect' + | 'refetchOnMount' +>; + +export function createIndexerQueryStoreEffect( + store: RootStore, + config: QuerySetupConfig +) { + const fullSelector = createAppSelector( + selectWebsocketUrl, + selectIndexerUrl, + config.selector, + (wsUrl, indexerUrl, selectorResult) => ({ + infrastructure: { wsUrl, indexerUrl }, + queryData: selectorResult, + }) + ); + + return createStoreEffect(store, fullSelector, (fullResult) => { + const { infrastructure, queryData } = fullResult; + + const indexerClientConfig = { + url: infrastructure.indexerUrl, + wsUrl: infrastructure.wsUrl, + }; + const indexerClient = IndexerClientManager.use(indexerClientConfig); + + const queryFn = config.getQueryFn(indexerClient, queryData); + if (!queryFn) { + IndexerClientManager.markDone(indexerClientConfig); + return undefined; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { selector, getQueryKey, getQueryFn, onResult, ...otherOpts } = config; + const observer = new QueryObserver(appQueryClient, { + queryKey: ['indexer', ...config.getQueryKey(queryData), indexerClientConfig], + queryFn, + ...otherOpts, + }); + + const unsubscribe = observer.subscribe((result) => { + config.onResult(result); + }); + + return () => { + unsubscribe(); + IndexerClientManager.markDone(indexerClientConfig); + }; + }); +} diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts new file mode 100644 index 000000000..d6529b78b --- /dev/null +++ b/src/abacus-ts/rest/orders.ts @@ -0,0 +1,54 @@ +import { keyBy } from 'lodash'; + +import { type RootStore } from '@/state/_store'; +import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; +import { createAppSelector } from '@/state/appTypes'; +import { setAccountOrdersRaw } from '@/state/raw'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { loadableIdle } from '../loadable'; +import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; + +export function setUpOrdersQuery(store: RootStore) { + const selectParentSubaccountInfo = createAppSelector( + getUserWalletAddress, + getUserSubaccountNumber, + (wallet, subaccount) => ({ wallet, subaccount }) + ); + + return createIndexerQueryStoreEffect(store, { + selector: selectParentSubaccountInfo, + getQueryKey: (data) => ['account', 'orders', data.wallet, data.subaccount], + getQueryFn: (indexerClient, data) => { + if (!isTruthy(data.wallet) || data.subaccount == null) { + if (store.getState().raw.account.orders.data != null) { + store.dispatch(setAccountOrdersRaw(loadableIdle())); + } + return null; + } + return () => + indexerClient.account.getParentSubaccountNumberOrders( + data.wallet!, + data.subaccount!, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + true + ); + }, + onResult: (orders) => { + store.dispatch( + setAccountOrdersRaw({ + status: orders.status, + data: orders.data != null ? keyBy(orders.data, (o) => o.id ?? '') : orders.data, + error: orders.error, + }) + ); + }, + }); +} diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/abacus-ts/signal.ts b/src/abacus-ts/signal.ts new file mode 100644 index 000000000..208528a74 --- /dev/null +++ b/src/abacus-ts/signal.ts @@ -0,0 +1,16 @@ +export class Signal extends EventTarget { + notify() { + this.dispatchEvent(new Event('trigger')); + } + + onTrigger(callback: () => void) { + // Store the callback reference + const listener = callback.bind(null); + this.addEventListener('trigger', listener); + + // Return an unsubscribe function + return () => { + this.removeEventListener('trigger', listener); + }; + } +} From fd1a39d26119a3f4627dc3095e2e03df313d96dd Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 6 Dec 2024 13:19:05 -0500 Subject: [PATCH 15/65] fixes --- src/abacus-ts/accountRefreshSignal.ts | 8 ++++++++ src/abacus-ts/rest/fills.ts | 8 +++++++- src/abacus-ts/rest/orders.ts | 8 +++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/abacus-ts/accountRefreshSignal.ts b/src/abacus-ts/accountRefreshSignal.ts index ac1fcf5cb..c57851938 100644 --- a/src/abacus-ts/accountRefreshSignal.ts +++ b/src/abacus-ts/accountRefreshSignal.ts @@ -1,5 +1,13 @@ +import { appQueryClient } from '@/state/appQueryClient'; + import { Signal } from './signal'; // triggers when we got fresh parent subaccount data from the websocket for any reason // mostly network reconnects, refreshes, page visibility changes, etc export const accountRefreshSignal = new Signal(); + +export function refreshIndexerQueryOnAccountSocketRefresh(key: any[]) { + return accountRefreshSignal.onTrigger(() => + appQueryClient.invalidateQueries({ queryKey: ['indexer', ...key], exact: false }) + ); +} diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index aac004ab8..473b97342 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -5,6 +5,7 @@ import { setAccountFillsRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; +import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; import { loadableIdle } from '../loadable'; import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; @@ -15,7 +16,8 @@ export function setUpFillsQuery(store: RootStore) { (wallet, subaccount) => ({ wallet, subaccount }) ); - return createIndexerQueryStoreEffect(store, { + const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'fills']); + const cleanupEffect = createIndexerQueryStoreEffect(store, { selector: selectParentSubaccountInfo, getQueryKey: (data) => ['account', 'fills', data.wallet, data.subaccount], getQueryFn: (indexerClient, data) => { @@ -38,4 +40,8 @@ export function setUpFillsQuery(store: RootStore) { ); }, }); + return () => { + cleanupListener(); + cleanupEffect(); + }; } diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index d6529b78b..2eb26286b 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -7,6 +7,7 @@ import { setAccountOrdersRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; +import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; import { loadableIdle } from '../loadable'; import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; @@ -17,7 +18,8 @@ export function setUpOrdersQuery(store: RootStore) { (wallet, subaccount) => ({ wallet, subaccount }) ); - return createIndexerQueryStoreEffect(store, { + const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'orders']); + const cleanupEffect = createIndexerQueryStoreEffect(store, { selector: selectParentSubaccountInfo, getQueryKey: (data) => ['account', 'orders', data.wallet, data.subaccount], getQueryFn: (indexerClient, data) => { @@ -51,4 +53,8 @@ export function setUpOrdersQuery(store: RootStore) { ); }, }); + return () => { + cleanupListener(); + cleanupEffect(); + }; } From 0da5633e3f6f9098e21b2618b5f00e9e37af3ca5 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 6 Dec 2024 16:21:06 -0500 Subject: [PATCH 16/65] add more data --- package.json | 2 +- pnpm-lock.yaml | 22 +++--- src/abacus-ts/rest/blockTradingRewards.ts | 44 ++++++++++++ src/abacus-ts/rest/fills.ts | 9 +-- src/abacus-ts/rest/indexerQueryStoreEffect.ts | 7 ++ src/abacus-ts/rest/orders.ts | 9 +-- src/abacus-ts/rest/transfers.ts | 42 ++++++++++++ src/abacus-ts/socketSelectors.ts | 7 ++ src/abacus-ts/storeLifecycles.ts | 4 ++ src/abacus-ts/types.ts | 5 ++ src/abacus-ts/websocket/orderbook.ts | 67 +++++++++++++++++++ src/abacus-ts/websocket/parentSubaccount.ts | 12 ++-- src/state/raw.ts | 30 ++++++++- src/types/indexer/indexerManual.ts | 2 +- 14 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 src/abacus-ts/rest/blockTradingRewards.ts diff --git a/package.json b/package.json index 18efa4b3d..cbabf5ab6 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@cosmjs/tendermint-rpc": "^0.32.1", "@datadog/browser-logs": "^5.23.3", "@dydxprotocol/v4-abacus": "1.13.39", - "@dydxprotocol/v4-client-js": "1.15.0", + "@dydxprotocol/v4-client-js": "1.15.1", "@dydxprotocol/v4-localization": "^1.1.254", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", "@funkit/connect": "^4.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c93246c29..73b178341 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ dependencies: specifier: 1.13.39 version: 1.13.39 '@dydxprotocol/v4-client-js': - specifier: 1.15.0 - version: 1.15.0 + specifier: 1.15.1 + version: 1.15.1 '@dydxprotocol/v4-localization': specifier: ^1.1.254 version: 1.1.254 @@ -2640,8 +2640,8 @@ packages: - fp-ts dev: false - /@chain-registry/types@0.50.28: - resolution: {integrity: sha512-cIgnjh27j/enf1K6syZ0Q1hmqJEfmbgG2LbMnFnev4l/Kg/D3UI0BWifFsoN84TT1W8Jje7Savm4rFICxq/1+w==} + /@chain-registry/types@0.50.29: + resolution: {integrity: sha512-y/szqUT5oSKSolMQ4pM65Nh6qbiWChBfYUyUP5NqGzhpkBCXcmMoT8pzLudrjWi2Iheccb/TIg1is6eEsNUGkQ==} dev: false /@coinbase/wallet-sdk@3.9.3: @@ -3309,8 +3309,8 @@ packages: format-util: 1.0.5 dev: false - /@dydxprotocol/v4-client-js@1.15.0: - resolution: {integrity: sha512-ROQFcv8+dkDMzJzFscNRzE+MGbaDW+KwoBqKl7e/P0lnLZ0tuvVhQPNlz2ArouInyL93+aKjJJNQ6hAMOoijJQ==} + /@dydxprotocol/v4-client-js@1.15.1: + resolution: {integrity: sha512-Dd+uQUcPw+pRAPkcw7rBIOjrANJD35e97DY/uxmNobN1cD3lDZx4ztrSMkaokrKWj/KugnFLUFRGCeSBiSi8ag==} dependencies: '@cosmjs/amino': 0.32.4 '@cosmjs/encoding': 0.32.4 @@ -9546,7 +9546,7 @@ packages: '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.93.2) '@solana/web3.js': 1.93.2 axios: 1.6.7 - chain-registry: 1.69.53 + chain-registry: 1.69.54 cosmjs-types: 0.8.0 keccak256: 1.0.6 kujira.js: 0.9.162 @@ -14199,10 +14199,10 @@ packages: type-detect: 4.1.0 dev: true - /chain-registry@1.69.53: - resolution: {integrity: sha512-5Rz7zgtUFH5ownAkl3fLLobLFT5vGJxm2XATGIIvbAcb/dvArqOVbke1mNc54Ndb3eAHNCBxf36QmDBfIU44kA==} + /chain-registry@1.69.54: + resolution: {integrity: sha512-LqcYWprXXAV0H/4TJWBKV2uqiqXLiyP4TeCZ7+53nI27s2JsY8/LeOoK8TWTuhB9bqIp78pAlnmhK/M/VZSlEg==} dependencies: - '@chain-registry/types': 0.50.28 + '@chain-registry/types': 0.50.29 dev: false /chalk@2.4.2: @@ -19630,7 +19630,7 @@ packages: '@ethersproject/bignumber': 5.7.0 '@keplr-wallet/types': 0.11.64 '@types/google-protobuf': 3.15.12 - chain-registry: 1.69.53 + chain-registry: 1.69.54 cosmjs-types: 0.8.0 long: 4.0.0 text-encoding: 0.7.0 diff --git a/src/abacus-ts/rest/blockTradingRewards.ts b/src/abacus-ts/rest/blockTradingRewards.ts new file mode 100644 index 000000000..d42bccdd0 --- /dev/null +++ b/src/abacus-ts/rest/blockTradingRewards.ts @@ -0,0 +1,44 @@ +import { type RootStore } from '@/state/_store'; +import { setAccountBlockTradingRewardsRaw } from '@/state/raw'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; +import { loadableIdle } from '../loadable'; +import { selectParentSubaccountInfo } from '../socketSelectors'; +import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; + +export function setUpBlockTradingRewardsQuery(store: RootStore) { + const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh([ + 'account', + 'blockTradingRewards', + ]); + + const cleanupEffect = createIndexerQueryStoreEffect(store, { + selector: selectParentSubaccountInfo, + getQueryKey: (data) => ['account', 'blockTradingRewards', data], + getQueryFn: (indexerClient, data) => { + if (!isTruthy(data.wallet) || data.subaccount == null) { + if (store.getState().raw.account.blockTradingRewards.data != null) { + store.dispatch(setAccountBlockTradingRewardsRaw(loadableIdle())); + } + return null; + } + return () => indexerClient.account.getHistoricalBlockTradingRewards(data.wallet!); + }, + onResult: (blockTradingRewards) => { + store.dispatch( + setAccountBlockTradingRewardsRaw({ + status: blockTradingRewards.status, + data: blockTradingRewards.data, + error: blockTradingRewards.error, + }) + ); + }, + }); + + return () => { + cleanupListener(); + cleanupEffect(); + }; +} diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index 473b97342..a7fa3e417 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -1,21 +1,14 @@ import { type RootStore } from '@/state/_store'; -import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; -import { createAppSelector } from '@/state/appTypes'; import { setAccountFillsRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; import { loadableIdle } from '../loadable'; +import { selectParentSubaccountInfo } from '../socketSelectors'; import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; export function setUpFillsQuery(store: RootStore) { - const selectParentSubaccountInfo = createAppSelector( - getUserWalletAddress, - getUserSubaccountNumber, - (wallet, subaccount) => ({ wallet, subaccount }) - ); - const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'fills']); const cleanupEffect = createIndexerQueryStoreEffect(store, { selector: selectParentSubaccountInfo, diff --git a/src/abacus-ts/rest/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/indexerQueryStoreEffect.ts index 52ceec25c..7ac8cf350 100644 --- a/src/abacus-ts/rest/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/indexerQueryStoreEffect.ts @@ -1,6 +1,8 @@ import { IndexerClient } from '@dydxprotocol/v4-client-js'; import { QueryObserver, QueryObserverOptions, QueryObserverResult } from '@tanstack/react-query'; +import { timeUnits } from '@/constants/time'; + import { type RootState, type RootStore } from '@/state/_store'; import { appQueryClient } from '@/state/appQueryClient'; import { createAppSelector } from '@/state/appTypes'; @@ -25,6 +27,10 @@ type QuerySetupConfig = { | 'refetchOnMount' >; +const baseOptions = { + refetchInterval: timeUnits.minute, +}; + export function createIndexerQueryStoreEffect( store: RootStore, config: QuerySetupConfig @@ -59,6 +65,7 @@ export function createIndexerQueryStoreEffect( const observer = new QueryObserver(appQueryClient, { queryKey: ['indexer', ...config.getQueryKey(queryData), indexerClientConfig], queryFn, + ...baseOptions, ...otherOpts, }); diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index 2eb26286b..1c0552123 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -1,23 +1,16 @@ import { keyBy } from 'lodash'; import { type RootStore } from '@/state/_store'; -import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; -import { createAppSelector } from '@/state/appTypes'; import { setAccountOrdersRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; import { loadableIdle } from '../loadable'; +import { selectParentSubaccountInfo } from '../socketSelectors'; import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; export function setUpOrdersQuery(store: RootStore) { - const selectParentSubaccountInfo = createAppSelector( - getUserWalletAddress, - getUserSubaccountNumber, - (wallet, subaccount) => ({ wallet, subaccount }) - ); - const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'orders']); const cleanupEffect = createIndexerQueryStoreEffect(store, { selector: selectParentSubaccountInfo, diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts index e69de29bb..25fc3e875 100644 --- a/src/abacus-ts/rest/transfers.ts +++ b/src/abacus-ts/rest/transfers.ts @@ -0,0 +1,42 @@ +import { type RootStore } from '@/state/_store'; +import { setAccountTransfersRaw } from '@/state/raw'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; +import { loadableIdle } from '../loadable'; +import { selectParentSubaccountInfo } from '../socketSelectors'; +import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; + +export function setUpTransfersQuery(store: RootStore) { + const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'transfers']); + + const cleanupEffect = createIndexerQueryStoreEffect(store, { + selector: selectParentSubaccountInfo, + getQueryKey: (data) => ['account', 'transfers', data], + getQueryFn: (indexerClient, data) => { + if (!isTruthy(data.wallet) || data.subaccount == null) { + if (store.getState().raw.account.transfers.data != null) { + store.dispatch(setAccountTransfersRaw(loadableIdle())); + } + return null; + } + return () => + indexerClient.account.getParentSubaccountNumberTransfers(data.wallet!, data.subaccount!); + }, + onResult: (transfers) => { + store.dispatch( + setAccountTransfersRaw({ + status: transfers.status, + data: transfers.data, + error: transfers.error, + }) + ); + }, + }); + + return () => { + cleanupListener(); + cleanupEffect(); + }; +} diff --git a/src/abacus-ts/socketSelectors.ts b/src/abacus-ts/socketSelectors.ts index cf3f0d976..eec7b7d49 100644 --- a/src/abacus-ts/socketSelectors.ts +++ b/src/abacus-ts/socketSelectors.ts @@ -2,6 +2,7 @@ import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { EndpointsConfig } from '@/hooks/useEndpointsConfig'; +import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; import { getSelectedNetwork } from '@/state/appSelectors'; import { createAppSelector } from '@/state/appTypes'; @@ -15,3 +16,9 @@ export const selectIndexerUrl = createAppSelector(getSelectedNetwork, (network) const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; return `${endpointsConfig.indexers[0]!.api}`; }); + +export const selectParentSubaccountInfo = createAppSelector( + getUserWalletAddress, + getUserSubaccountNumber, + (wallet, subaccount) => ({ wallet, subaccount }) +); diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index 83f57b1c0..78fc5bbe3 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -1,5 +1,7 @@ +import { setUpBlockTradingRewardsQuery } from './rest/blockTradingRewards'; import { setUpFillsQuery } from './rest/fills'; import { setUpOrdersQuery } from './rest/orders'; +import { setUpTransfersQuery } from './rest/transfers'; import { setUpMarkets } from './websocket/markets'; import { setUpParentSubaccount } from './websocket/parentSubaccount'; @@ -8,4 +10,6 @@ export const storeLifecycles = [ setUpParentSubaccount, setUpFillsQuery, setUpOrdersQuery, + setUpTransfersQuery, + setUpBlockTradingRewardsQuery, ] as const; diff --git a/src/abacus-ts/types.ts b/src/abacus-ts/types.ts index 80e269ae3..975ad639d 100644 --- a/src/abacus-ts/types.ts +++ b/src/abacus-ts/types.ts @@ -12,6 +12,11 @@ import { export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; +export type OrderbookData = { + bids: { [price: string]: string }; + asks: { [price: string]: string }; +}; + export interface ParentSubaccountData { address: string; parentSubaccount: number; diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index e69de29bb..85006336c 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -0,0 +1,67 @@ +import { IndexerOrderbookResponseObject } from '@/types/indexer/indexerApiGen'; +import { IndexerWsOrderbookUpdateResponse } from '@/types/indexer/indexerManual'; +import { keyBy, mapValues } from 'lodash'; + +import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { ResourceCacheManager } from '../resourceCacheManager'; +import { OrderbookData } from '../types'; +import { IndexerWebsocket } from './indexerWebsocket'; +import { IndexerWebsocketManager } from './indexerWebsocketManager'; +import { WebsocketDerivedValue } from './websocketDerivedValue'; + +function orderbookWebsocketValue( + websocket: IndexerWebsocket, + marketId: string, + onChange: (val: Loadable) => void +) { + return new WebsocketDerivedValue>( + websocket, + { + channel: 'v4_orderbook', + id: marketId, + handleBaseData: (baseMessage) => { + const message = baseMessage as IndexerOrderbookResponseObject; + return loadableLoaded({ + asks: mapValues( + keyBy(message.asks, (a) => a.price), + (a) => a.size + ), + bids: mapValues( + keyBy(message.bids, (a) => a.price), + (a) => a.size + ), + }); + }, + handleUpdates: (baseUpdates, value) => { + const updates = baseUpdates as IndexerWsOrderbookUpdateResponse[]; + let startingValue = value.data; + if (startingValue == null) { + // eslint-disable-next-line no-console + console.log('MarketsTracker found unexpectedly null base data in update'); + return value; + } + startingValue = { asks: { ...startingValue.asks }, bids: { ...startingValue.bids } }; + updates.forEach((update) => { + if (update.asks) { + update.asks.forEach(([price, size]) => (startingValue.asks[price] = size)); + } + if (update.bids) { + update.bids.forEach(([price, size]) => (startingValue.bids[price] = size)); + } + }); + return loadableLoaded(startingValue); + }, + }, + loadablePending(), + onChange + ); +} + +// todo simplify api to just take market id +// needs to allow adding/removing callbacks too +export const OrderbooksManager = new ResourceCacheManager({ + constructor: ({ wsUrl, marketId }: { wsUrl: string; marketId: string }) => + orderbookWebsocketValue(IndexerWebsocketManager.use(wsUrl), marketId, () => null), + destroyer: (obj) => obj.teardown(), + keySerializer: ({ marketId, wsUrl }) => `${wsUrl}//////\\\\\\${marketId}`, +}); diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index ab636f405..796df4f2c 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -6,7 +6,6 @@ import { import { keyBy } from 'lodash'; import { type RootStore } from '@/state/_store'; -import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; import { createAppSelector } from '@/state/appTypes'; import { setParentSubaccountRaw } from '@/state/raw'; @@ -15,7 +14,7 @@ import { isTruthy } from '@/lib/isTruthy'; import { accountRefreshSignal } from '../accountRefreshSignal'; import { createStoreEffect } from '../createStoreEffect'; import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../loadable'; -import { selectWebsocketUrl } from '../socketSelectors'; +import { selectParentSubaccountInfo, selectWebsocketUrl } from '../socketSelectors'; import { ChildSubaccountData, ParentSubaccountData } from '../types'; import { IndexerWebsocket } from './indexerWebsocket'; import { IndexerWebsocketManager } from './indexerWebsocketManager'; @@ -166,15 +165,14 @@ function accountWebsocketValue( ); } -const selectParentSubaccountInfo = createAppSelector( +const selectParentSubaccount = createAppSelector( selectWebsocketUrl, - getUserWalletAddress, - getUserSubaccountNumber, - (wsUrl, wallet, subaccount) => ({ wsUrl, wallet, subaccount }) + selectParentSubaccountInfo, + (wsUrl, { wallet, subaccount }) => ({ wsUrl, wallet, subaccount }) ); export function setUpParentSubaccount(store: RootStore) { - return createStoreEffect(store, selectParentSubaccountInfo, ({ subaccount, wallet, wsUrl }) => { + return createStoreEffect(store, selectParentSubaccount, ({ subaccount, wallet, wsUrl }) => { if (!isTruthy(wallet) || subaccount == null) { if (store.getState().raw.account.parentSubaccount.data != null) { store.dispatch(setParentSubaccountRaw(loadableIdle())); diff --git a/src/state/raw.ts b/src/state/raw.ts index 8519d0c99..211ee693b 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,5 +1,9 @@ import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; import { MarketsData, ParentSubaccountData } from '@/abacus-ts/types'; +import { + IndexerHistoricalBlockTradingRewardsResponse, + IndexerParentSubaccountTransferResponse, +} from '@/types/indexer/indexerApiGen'; import { IndexerCompositeFillResponse, IndexerCompositeOrderObject, @@ -14,6 +18,8 @@ export interface RawDataState { parentSubaccount: Loadable; fills: Loadable; orders: Loadable<{ [id: string]: IndexerCompositeOrderObject }>; + transfers: Loadable; + blockTradingRewards: Loadable; }; } @@ -23,6 +29,8 @@ const initialState: RawDataState = { parentSubaccount: loadableIdle(), fills: loadableIdle(), orders: loadableIdle(), + transfers: loadableIdle(), + blockTradingRewards: loadableIdle(), }, }; @@ -39,6 +47,18 @@ export const rawSlice = createSlice({ setAccountFillsRaw: (state, action: PayloadAction>) => { state.account.fills = action.payload; }, + setAccountTransfersRaw: ( + state, + action: PayloadAction> + ) => { + state.account.transfers = action.payload; + }, + setAccountBlockTradingRewardsRaw: ( + state, + action: PayloadAction> + ) => { + state.account.blockTradingRewards = action.payload; + }, setAccountOrdersRaw: ( state, action: PayloadAction> @@ -48,5 +68,11 @@ export const rawSlice = createSlice({ }, }); -export const { setAllMarketsRaw, setParentSubaccountRaw, setAccountFillsRaw, setAccountOrdersRaw } = - rawSlice.actions; +export const { + setAllMarketsRaw, + setParentSubaccountRaw, + setAccountFillsRaw, + setAccountOrdersRaw, + setAccountTransfersRaw, + setAccountBlockTradingRewardsRaw, +} = rawSlice.actions; diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 286f13712..633e18e98 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -89,7 +89,7 @@ export interface IndexerWsOrderbookUpdateResponse { bids?: IndexerWsOrderbookUpdateItem[]; } -export type IndexerWsOrderbookUpdateItem = string[]; +export type IndexerWsOrderbookUpdateItem = [string, string]; export interface IndexerWsMarketUpdateResponse { trading?: { [key: string]: IndexerCompositeMarketObject }; From 3cadec2dd7465cc68a60998542159be68c5ec613 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 9 Dec 2024 15:51:52 -0500 Subject: [PATCH 17/65] went wild --- .npmrc | 1 + package.json | 11 +- pnpm-lock.yaml | 1209 +++++++++++++---- scripts/indexer-renames.ts | 12 + scripts/swagger_codegen.sh | 2 - src/abacus-ts/accountRefreshSignal.ts | 20 +- src/abacus-ts/rest/blockTradingRewards.ts | 7 +- src/abacus-ts/rest/fills.ts | 4 +- src/abacus-ts/rest/indexerQueryStoreEffect.ts | 28 +- src/abacus-ts/rest/orders.ts | 6 +- src/abacus-ts/rest/transfers.ts | 7 +- src/abacus-ts/websocket/indexerWebsocket.ts | 92 +- src/abacus-ts/websocket/markets.ts | 10 +- src/abacus-ts/websocket/orderbook.ts | 7 +- src/abacus-ts/websocket/parentSubaccount.ts | 10 +- src/types/indexer/indexerApiGen.ts | 80 +- src/types/indexer/indexerChecks.ts | 32 + src/types/indexer/indexerManual.ts | 16 +- tsconfig.json | 39 +- vite.config.ts | 3 + 20 files changed, 1166 insertions(+), 430 deletions(-) create mode 100644 .npmrc create mode 100644 src/types/indexer/indexerChecks.ts diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..41583e36c --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@jsr:registry=https://npm.jsr.io diff --git a/package.json b/package.json index cbabf5ab6..f237e71a1 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "test": "vitest run", "tsc": "tsc", "postinstall": "tar -xzC public -f tradingview/tradingview.tgz", - "prepare": "husky", + "prepare": "ts-patch install && typia patch && husky", "commitlint": "commitlint --edit", "wdio": "wdio run ./wdio.conf.ts" }, @@ -59,9 +59,9 @@ "@dydxprotocol/v4-client-js": "1.15.1", "@dydxprotocol/v4-localization": "^1.1.254", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", - "@funkit/connect": "^4.0.2", "@emotion/is-prop-valid": "^1.3.0", "@ethersproject/providers": "^5.7.2", + "@funkit/connect": "^4.0.2", "@hugocxl/react-to-image": "^0.0.9", "@js-joda/core": "^5.5.3", "@keplr-wallet/types": "^0.12.121", @@ -145,6 +145,7 @@ "reselect": "^5.1.0", "styled-components": "^6.1.12", "twin.macro": "^3.4.1", + "typia": "^7.1.0", "unionize": "^3.1.0", "use-latest": "^1.2.1", "viem": "^2.16.2", @@ -155,6 +156,7 @@ "@commitlint/cli": "^19.0.3", "@commitlint/config-conventional": "^19.0.3", "@ladle/react": "^4.0.2", + "@ryoppippi/unplugin-typia": "npm:@jsr/ryoppippi__unplugin-typia@^1.1.0", "@testing-library/webdriverio": "^3.2.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/color": "^3.0.3", @@ -209,8 +211,9 @@ "tailwindcss": "^3.4.6", "ts-morph": "^24.0.0", "ts-node": "^10.9.2", + "ts-patch": "^3.3.0", "tsx": "^4.7.1", - "typescript": "^5.6.3", + "typescript": "^5.7.2", "url-polyfill": "^1.1.12", "util": "^0.12.5", "vite": "^4.3.9", @@ -233,4 +236,4 @@ "includeClassNames": true } } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 73b178341..68e584b0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ dependencies: version: 5.7.2 '@funkit/connect': specifier: ^4.0.2 - version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2)(wagmi@2.10.9) + version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2)(wagmi@2.10.9) '@hugocxl/react-to-image': specifier: ^0.0.9 version: 0.0.9(html-to-image@1.11.11)(react@18.2.0) @@ -61,7 +61,7 @@ dependencies: version: 0.12.121 '@privy-io/react-auth': specifier: ^1.73.0 - version: 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.6.3) + version: 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.7.2) '@privy-io/wagmi': specifier: ^0.2.10 version: 0.2.10(@privy-io/react-auth@1.73.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.16.2)(wagmi@2.10.9) @@ -154,7 +154,7 @@ dependencies: version: 1.2.1 '@skip-go/client': specifier: 0.10.3 - version: 0.10.3(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3) + version: 0.10.3(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2) '@solana/web3.js': specifier: ^1.93.0 version: 1.93.2 @@ -256,7 +256,7 @@ dependencies: version: 3.3.0 mipd: specifier: ^0.0.7 - version: 0.0.7(typescript@5.6.3) + version: 0.0.7(typescript@5.7.2) prometheus-query: specifier: ^3.4.0 version: 3.4.0 @@ -299,6 +299,9 @@ dependencies: twin.macro: specifier: ^3.4.1 version: 3.4.1(tailwindcss@3.4.6) + typia: + specifier: ^7.1.0 + version: 7.1.0(@samchon/openapi@2.0.1)(typescript@5.7.2) unionize: specifier: ^3.1.0 version: 3.1.0 @@ -307,10 +310,10 @@ dependencies: version: 1.2.1(@types/react@18.3.3)(react@18.2.0) viem: specifier: ^2.16.2 - version: 2.16.2(typescript@5.6.3) + version: 2.16.2(typescript@5.7.2) wagmi: specifier: ^2.10.7 - version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2) + version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) devDependencies: '@babel/core': @@ -318,13 +321,16 @@ devDependencies: version: 7.23.9 '@commitlint/cli': specifier: ^19.0.3 - version: 19.0.3(@types/node@20.12.13)(typescript@5.6.3) + version: 19.0.3(@types/node@20.12.13)(typescript@5.7.2) '@commitlint/config-conventional': specifier: ^19.0.3 version: 19.0.3 '@ladle/react': specifier: ^4.0.2 - version: 4.0.2(@types/node@20.12.13)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3) + version: 4.0.2(@types/node@20.12.13)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2) + '@ryoppippi/unplugin-typia': + specifier: npm:@jsr/ryoppippi__unplugin-typia@^1.1.0 + version: /@jsr/ryoppippi__unplugin-typia@1.1.0(@samchon/openapi@2.0.1)(@types/node@20.12.13)(rollup@2.79.1)(tsx@4.7.1) '@testing-library/webdriverio': specifier: ^3.2.1 version: 3.2.1(webdriverio@8.36.1) @@ -354,25 +360,25 @@ devDependencies: version: 18.2.6 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.6.3) + version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2) '@typescript-eslint/parser': specifier: ^6.21.0 - version: 6.21.0(eslint@8.57.0)(typescript@5.6.3) + version: 6.21.0(eslint@8.57.0)(typescript@5.7.2) '@vitejs/plugin-react': specifier: ^4.0.1 version: 4.2.1(vite@4.3.9) '@wdio/browserstack-service': specifier: ^8.32.4 - version: 8.33.1(@wdio/cli@8.33.1)(typescript@5.6.3) + version: 8.33.1(@wdio/cli@8.33.1)(typescript@5.7.2) '@wdio/cli': specifier: ^8.32.4 - version: 8.33.1(typescript@5.6.3) + version: 8.33.1(typescript@5.7.2) '@wdio/globals': specifier: ^8.32.4 - version: 8.33.1(typescript@5.6.3) + version: 8.33.1(typescript@5.7.2) '@wdio/local-runner': specifier: ^8.32.4 - version: 8.33.1(typescript@5.6.3) + version: 8.33.1(typescript@5.7.2) '@wdio/mocha-framework': specifier: ^8.32.4 version: 8.33.1 @@ -423,7 +429,7 @@ devDependencies: version: 9.1.0(eslint@8.57.0) eslint-config-standard-with-typescript: specifier: ^43.0.1 - version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.6.3) + version: 43.0.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.7.2) eslint-import-resolver-typescript: specifier: ^3.6.1 version: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) @@ -486,13 +492,16 @@ devDependencies: version: 24.0.0 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.13)(typescript@5.6.3) + version: 10.9.2(@types/node@20.12.13)(typescript@5.7.2) + ts-patch: + specifier: ^3.3.0 + version: 3.3.0 tsx: specifier: ^4.7.1 version: 4.7.1 typescript: - specifier: ^5.6.3 - version: 5.6.3 + specifier: ^5.7.2 + version: 5.7.2 url-polyfill: specifier: ^1.1.12 version: 1.1.12 @@ -510,7 +519,7 @@ devDependencies: version: 0.4.0(vite@4.3.9) vite-plugin-svgr: specifier: ^3.2.0 - version: 3.2.0(rollup@2.79.1)(typescript@5.6.3)(vite@4.3.9) + version: 3.2.0(rollup@2.79.1)(typescript@5.7.2)(vite@4.3.9) vitest: specifier: 1.4.0 version: 1.4.0(@types/node@20.12.13)(jsdom@24.1.0) @@ -1074,7 +1083,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.0.1 + picocolors: 1.1.1 /@babel/compat-data@7.24.7: resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} @@ -1351,7 +1360,7 @@ packages: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.1 + picocolors: 1.1.1 /@babel/parser@7.24.7: resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} @@ -2640,8 +2649,8 @@ packages: - fp-ts dev: false - /@chain-registry/types@0.50.29: - resolution: {integrity: sha512-y/szqUT5oSKSolMQ4pM65Nh6qbiWChBfYUyUP5NqGzhpkBCXcmMoT8pzLudrjWi2Iheccb/TIg1is6eEsNUGkQ==} + /@chain-registry/types@0.50.31: + resolution: {integrity: sha512-WOVNfC0ss4+LsWDqoeBFxHuVHNasxuNvjMWYf8h1x2axUlMDgTLFubkTdW0Hj93uk1fOBTC07bJXCf915NMVnA==} dev: false /@coinbase/wallet-sdk@3.9.3: @@ -2687,14 +2696,14 @@ packages: engines: {node: '>=0.1.90'} dev: true - /@commitlint/cli@19.0.3(@types/node@20.12.13)(typescript@5.6.3): + /@commitlint/cli@19.0.3(@types/node@20.12.13)(typescript@5.7.2): resolution: {integrity: sha512-mGhh/aYPib4Vy4h+AGRloMY+CqkmtdeKPV9poMcZeImF5e3knQ5VYaSeAM0mEzps1dbKsHvABwaDpafLUuM96g==} engines: {node: '>=v18'} hasBin: true dependencies: '@commitlint/format': 19.0.3 '@commitlint/lint': 19.0.3 - '@commitlint/load': 19.0.3(@types/node@20.12.13)(typescript@5.6.3) + '@commitlint/load': 19.0.3(@types/node@20.12.13)(typescript@5.7.2) '@commitlint/read': 19.0.3 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -2763,7 +2772,7 @@ packages: '@commitlint/types': 19.0.3 dev: true - /@commitlint/load@19.0.3(@types/node@20.12.13)(typescript@5.6.3): + /@commitlint/load@19.0.3(@types/node@20.12.13)(typescript@5.7.2): resolution: {integrity: sha512-18Tk/ZcDFRKIoKfEcl7kC+bYkEQ055iyKmGsYDoYWpKf6FUvBrP9bIWapuy/MB+kYiltmP9ITiUx6UXtqC9IRw==} engines: {node: '>=v18'} dependencies: @@ -2772,8 +2781,8 @@ packages: '@commitlint/resolve-extends': 19.0.3 '@commitlint/types': 19.0.3 chalk: 5.3.0 - cosmiconfig: 8.3.6(typescript@5.6.3) - cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.13)(cosmiconfig@8.3.6)(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.13)(cosmiconfig@8.3.6)(typescript@5.7.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -3398,6 +3407,15 @@ packages: dev: true optional: true + /@esbuild/aix-ppc64@0.24.0: + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -3416,6 +3434,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.24.0: + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.17.19: resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} engines: {node: '>=12'} @@ -3434,6 +3461,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.24.0: + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.17.19: resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} engines: {node: '>=12'} @@ -3452,6 +3488,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.24.0: + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.17.19: resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} engines: {node: '>=12'} @@ -3470,6 +3515,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.24.0: + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.17.19: resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} engines: {node: '>=12'} @@ -3488,6 +3542,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.24.0: + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.17.19: resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} engines: {node: '>=12'} @@ -3506,6 +3569,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.24.0: + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.17.19: resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} engines: {node: '>=12'} @@ -3524,6 +3596,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.24.0: + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.17.19: resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} engines: {node: '>=12'} @@ -3542,6 +3623,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.24.0: + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.17.19: resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} engines: {node: '>=12'} @@ -3560,6 +3650,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.24.0: + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.17.19: resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} engines: {node: '>=12'} @@ -3578,6 +3677,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.24.0: + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.17.19: resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} engines: {node: '>=12'} @@ -3596,6 +3704,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.24.0: + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.17.19: resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} engines: {node: '>=12'} @@ -3614,6 +3731,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.24.0: + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.17.19: resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} engines: {node: '>=12'} @@ -3632,6 +3758,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.24.0: + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.17.19: resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} engines: {node: '>=12'} @@ -3650,6 +3785,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.24.0: + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.17.19: resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} engines: {node: '>=12'} @@ -3668,6 +3812,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.24.0: + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.17.19: resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} engines: {node: '>=12'} @@ -3686,6 +3839,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.24.0: + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.17.19: resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} engines: {node: '>=12'} @@ -3704,6 +3866,24 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.24.0: + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.24.0: + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.17.19: resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} engines: {node: '>=12'} @@ -3722,6 +3902,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.24.0: + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.17.19: resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} engines: {node: '>=12'} @@ -3740,6 +3929,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.24.0: + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.17.19: resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} engines: {node: '>=12'} @@ -3758,6 +3956,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.24.0: + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.17.19: resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} engines: {node: '>=12'} @@ -3776,6 +3983,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.24.0: + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.17.19: resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} engines: {node: '>=12'} @@ -3794,6 +4010,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.24.0: + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4266,7 +4491,7 @@ packages: big.js: 6.2.2 dev: false - /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2)(wagmi@2.10.9): + /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2)(wagmi@2.10.9): resolution: {integrity: sha512-aLUZD34S1MIl5k//UdNkhq+lbKoZkJG7Rk8wHpONFCzj3x7pYKDZyv82E1E3GnZsc50+4ONz05c1PL79HXg0vA==} engines: {node: '>=18'} peerDependencies: @@ -4278,9 +4503,9 @@ packages: dependencies: '@datadog/browser-logs': 5.22.0 '@funkit/api-base': 1.4.1 - '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.6.3) + '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.7.2) '@funkit/utils': 1.0.2 - '@funkit/wagmi-tools': 3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3) + '@funkit/wagmi-tools': 3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2) '@meshconnect/web-link-sdk': 2.1.1 '@moonpay/moonpay-react': 1.8.2(react@18.2.0) '@privy-io/js-sdk-core': 0.21.1 @@ -4289,7 +4514,7 @@ packages: '@vanilla-extract/css': 1.15.3(babel-plugin-macros@3.1.0) '@vanilla-extract/dynamic': 2.1.0 '@vanilla-extract/sprinkles': 1.6.1(@vanilla-extract/css@1.15.3) - '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2) + '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) bech32: 2.0.0 clsx: 2.1.1 qrcode: 1.5.3 @@ -4299,8 +4524,8 @@ packages: react-virtuoso: 4.10.1(react-dom@18.2.0)(react@18.2.0) ua-parser-js: 1.0.37 uuid: 9.0.1 - viem: 2.16.2(typescript@5.6.3) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2) + viem: 2.16.2(typescript@5.7.2) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) transitivePeerDependencies: - '@datadog/browser-rum' - '@ethersproject/address' @@ -4319,7 +4544,7 @@ packages: - zod dev: false - /@funkit/core@2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.6.3): + /@funkit/core@2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.7.2): resolution: {integrity: sha512-SvLc9pjjNOmIx0OyfWyfou/AAiaiHC3feIkDiIZZEfg5msffb5lBhVnpPTxXyj0B8YP49ya/SqRjBeQm5tDpDQ==} dependencies: '@aws-sdk/client-secrets-manager': 3.674.0 @@ -4331,12 +4556,12 @@ packages: '@uniswap/sdk': 3.0.3(@ethersproject/address@5.7.0)(@ethersproject/contracts@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/providers@5.7.2)(@ethersproject/solidity@5.7.0) '@uniswap/sdk-core': 4.2.1 '@uniswap/v3-sdk': 3.18.1(hardhat@2.22.13) - abitype: 0.10.3(typescript@5.6.3) + abitype: 0.10.3(typescript@5.7.2) big.js: 6.2.2 dotenv: 16.4.5 ethers: 5.7.2 uuid: 9.0.1 - viem: 2.17.0(typescript@5.6.3) + viem: 2.17.0(typescript@5.7.2) transitivePeerDependencies: - '@ethersproject/address' - '@ethersproject/networks' @@ -4354,18 +4579,18 @@ packages: engines: {node: '>=18'} dev: false - /@funkit/wagmi-tools@3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3): + /@funkit/wagmi-tools@3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2): resolution: {integrity: sha512-3k4df1OLkfSq5rh0J7tSXVFG3W82ux7kF8UT41pv4Lop2ZexLOkDLf6jiFhCYQ921YrMdzZCeu8Dh1DVV6Q4ZQ==} engines: {node: '>=18'} peerDependencies: react: ^18.3.0 react-dom: ^18.3.0 dependencies: - '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.6.3) - '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.17.0) + '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.7.2) + '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - viem: 2.17.0(typescript@5.6.3) + viem: 2.17.0(typescript@5.7.2) transitivePeerDependencies: - '@ethersproject/address' - '@ethersproject/networks' @@ -4808,7 +5033,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri@3.1.2: @@ -4827,18 +5052,22 @@ packages: /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 /@js-joda/core@3.2.0: resolution: {integrity: sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==} @@ -4848,6 +5077,38 @@ packages: resolution: {integrity: sha512-7dqNYwG8gCt4hfg5PKgM7xLEcgSBcx/UgC92OMnhMmvAnq11QzDFPrxUkNR/u5kn17WWLZ8beZ4A3Qrz4pZcmQ==} dev: false + /@jsr/ryoppippi__unplugin-typia@1.1.0(@samchon/openapi@2.0.1)(@types/node@20.12.13)(rollup@2.79.1)(tsx@4.7.1): + resolution: {integrity: sha512-/Azs26dk4J/Lq9nkNCRIC0A0CbOnRnt2RWSKEcGSbhk2Vh3zKut2uyqiwjy7EJccSAnbwZ3fmrYltMiaiyV14A==, tarball: https://npm.jsr.io/~/11/@jsr/ryoppippi__unplugin-typia/1.1.0.tgz} + dependencies: + '@rollup/pluginutils': 5.1.3(rollup@2.79.1) + consola: 3.2.3 + defu: 6.1.4 + diff-match-patch: 1.0.5 + find-cache-dir: 5.0.0 + magic-string: 0.30.14 + pathe: 1.1.2 + pkg-types: 1.2.1 + type-fest: 4.30.0 + typescript: 5.6.3 + typia: 7.1.0(@samchon/openapi@2.0.1)(typescript@5.6.3) + unplugin: 1.16.0 + vite: 6.0.3(@types/node@20.12.13)(tsx@4.7.1) + transitivePeerDependencies: + - '@samchon/openapi' + - '@types/node' + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + dev: true + /@keplr-wallet/common@0.12.121: resolution: {integrity: sha512-CPycrXnBy7+l6qUlOROIt4jXCSdpyTfIJHzDaI5zzBAKxRKFCPx+4LzOb0ZEhZvs8m328f+tfCnWUqngCBPWkA==} dependencies: @@ -4943,7 +5204,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@ladle/react@4.0.2(@types/node@20.12.13)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3): + /@ladle/react@4.0.2(@types/node@20.12.13)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2): resolution: {integrity: sha512-SnYniR/U7kJX1Zh199jhjxqiFa5e5eA8chuX6uYEZYAUtCCY/hQqGr7/7Grr0j6Q4FYu9iQyyV2K1NJKDdUZIw==} engines: {node: '>=18.0.0'} hasBin: true @@ -4976,7 +5237,7 @@ packages: koa: 2.14.2 koa-connect: 2.1.0 lodash.merge: 4.6.2 - msw: 2.1.7(typescript@5.6.3) + msw: 2.1.7(typescript@5.7.2) open: 9.1.0 prism-react-renderer: 2.3.1(react@18.2.0) prop-types: 15.8.1 @@ -4991,7 +5252,7 @@ packages: source-map: 0.7.4 vfile: 6.0.1 vite: 5.0.12(@types/node@20.12.13) - vite-tsconfig-paths: 4.3.1(typescript@5.6.3)(vite@5.0.12) + vite-tsconfig-paths: 4.3.1(typescript@5.7.2)(vite@5.0.12) transitivePeerDependencies: - '@swc/helpers' - '@types/node' @@ -5026,7 +5287,7 @@ packages: dependencies: '@cosmjs/amino': 0.31.3 '@cosmjs/proto-signing': 0.31.3 - typescript: 5.6.3 + typescript: 5.7.2 dev: false /@lifeomic/attempt@3.1.0: @@ -5063,7 +5324,7 @@ packages: /@mdx-js/mdx@3.0.0: resolution: {integrity: sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/estree-jsx': 1.0.0 '@types/hast': 3.0.4 '@types/mdx': 2.0.6 @@ -6011,7 +6272,7 @@ packages: - utf-8-validate dev: false - /@privy-io/react-auth@1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.6.3): + /@privy-io/react-auth@1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.7.2): resolution: {integrity: sha512-sZq1T8R0nsWvd2bL+J5JX77tLM01xBKkVYlrBWU98cFqVm3A2QP1LMeJ53zO6GAjLrBEYT4ToWIiJNoeFk/Bcg==} peerDependencies: react: ^18 @@ -6046,7 +6307,7 @@ packages: libphonenumber-js: 1.10.59 lokijs: 1.5.12 md5: 2.3.0 - mipd: 0.0.7(typescript@5.6.3) + mipd: 0.0.7(typescript@5.7.2) ofetch: 1.3.4 pino-pretty: 10.3.1 qrcode: 1.5.3 @@ -6090,11 +6351,11 @@ packages: viem: ^2 wagmi: ^2 dependencies: - '@privy-io/react-auth': 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.6.3) + '@privy-io/react-auth': 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.7.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - viem: 2.16.2(typescript@5.6.3) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2) + viem: 2.16.2(typescript@5.7.2) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) dev: false /@promptbook/utils@0.50.0-10: @@ -6138,7 +6399,7 @@ packages: /@protobufjs/utf8@1.1.0: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - /@puppeteer/browsers@1.4.6(typescript@5.6.3): + /@puppeteer/browsers@1.4.6(typescript@5.7.2): resolution: {integrity: sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==} engines: {node: '>=16.3.0'} hasBin: true @@ -6154,7 +6415,7 @@ packages: progress: 2.0.3 proxy-agent: 6.3.0 tar-fs: 3.0.4 - typescript: 5.6.3 + typescript: 5.7.2 unbzip2-stream: 1.4.3 yargs: 17.7.1 transitivePeerDependencies: @@ -9211,114 +9472,177 @@ packages: rollup: 2.79.1 dev: true - /@rollup/rollup-android-arm-eabi@4.9.6: - resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} + /@rollup/pluginutils@5.1.3(rollup@2.79.1): + resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + rollup: 2.79.1 + dev: true + + /@rollup/rollup-android-arm-eabi@4.28.1: + resolution: {integrity: sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.9.6: - resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==} + /@rollup/rollup-android-arm64@4.28.1: + resolution: {integrity: sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.9.6: - resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==} + /@rollup/rollup-darwin-arm64@4.28.1: + resolution: {integrity: sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.9.6: - resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==} + /@rollup/rollup-darwin-x64@4.28.1: + resolution: {integrity: sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.9.6: - resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==} + /@rollup/rollup-freebsd-arm64@4.28.1: + resolution: {integrity: sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-x64@4.28.1: + resolution: {integrity: sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.28.1: + resolution: {integrity: sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.28.1: + resolution: {integrity: sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.9.6: - resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==} + /@rollup/rollup-linux-arm64-gnu@4.28.1: + resolution: {integrity: sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.9.6: - resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==} + /@rollup/rollup-linux-arm64-musl@4.28.1: + resolution: {integrity: sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.9.6: - resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==} + /@rollup/rollup-linux-loongarch64-gnu@4.28.1: + resolution: {integrity: sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.28.1: + resolution: {integrity: sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.28.1: + resolution: {integrity: sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.9.6: - resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==} + /@rollup/rollup-linux-s390x-gnu@4.28.1: + resolution: {integrity: sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.28.1: + resolution: {integrity: sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.9.6: - resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==} + /@rollup/rollup-linux-x64-musl@4.28.1: + resolution: {integrity: sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.9.6: - resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==} + /@rollup/rollup-win32-arm64-msvc@4.28.1: + resolution: {integrity: sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.9.6: - resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==} + /@rollup/rollup-win32-ia32-msvc@4.28.1: + resolution: {integrity: sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.9.6: - resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==} + /@rollup/rollup-win32-x64-msvc@4.28.1: + resolution: {integrity: sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /@safe-global/safe-apps-provider@0.18.1(typescript@5.6.3): + /@safe-global/safe-apps-provider@0.18.1(typescript@5.7.2): resolution: {integrity: sha512-V4a05A3EgJcriqtDoJklDz1BOinWhC6P0hjUSxshA4KOZM7rGPCTto/usXs09zr1vvL28evl/NldSTv97j2bmg==} dependencies: - '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.6.3) + '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.7.2) events: 3.3.0 transitivePeerDependencies: - bufferutil @@ -9328,11 +9652,11 @@ packages: - zod dev: false - /@safe-global/safe-apps-sdk@8.1.0(typescript@5.6.3): + /@safe-global/safe-apps-sdk@8.1.0(typescript@5.7.2): resolution: {integrity: sha512-XJbEPuaVc7b9n23MqlF6c+ToYIS3f7P2Sel8f3cSBQ9WORE4xrSuvhMpK9fDSFqJ7by/brc+rmJR/5HViRr0/w==} dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.9.0 - viem: 1.20.0(typescript@5.6.3) + viem: 1.20.0(typescript@5.7.2) transitivePeerDependencies: - bufferutil - encoding @@ -9349,6 +9673,9 @@ packages: - encoding dev: false + /@samchon/openapi@2.0.1: + resolution: {integrity: sha512-Vw/iaxqrWVIXlGuwsLPb7hCZUmhBm/ez0aCP3e/8hPWuA9+0sEWAODrvyyrR8elMzK6uXrRRK9a6KibTQ/jHPw==} + /@scure/base@1.1.5: resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} dev: false @@ -9529,7 +9856,7 @@ packages: '@sinonjs/commons': 3.0.1 dev: false - /@skip-go/client@0.10.3(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.6.3): + /@skip-go/client@0.10.3(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2): resolution: {integrity: sha512-7sA4abXuIB8bHYcM/cdUKqWOsduVq3ORrIehRGgZOJdQsztYEnsrUdqGCtN4PLuPc9VIlXhAXueejiaySAGjig==} dependencies: '@cosmjs/amino': 0.32.4 @@ -9546,11 +9873,11 @@ packages: '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.93.2) '@solana/web3.js': 1.93.2 axios: 1.6.7 - chain-registry: 1.69.54 + chain-registry: 1.69.57 cosmjs-types: 0.8.0 keccak256: 1.0.6 kujira.js: 0.9.162 - viem: 2.16.2(typescript@5.6.3) + viem: 2.16.2(typescript@5.7.2) transitivePeerDependencies: - '@types/react' - bufferutil @@ -10234,14 +10561,14 @@ packages: '@svgr/babel-plugin-transform-svg-component': 7.0.0(@babel/core@7.23.9) dev: true - /@svgr/core@7.0.0(typescript@5.6.3): + /@svgr/core@7.0.0(typescript@5.7.2): resolution: {integrity: sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==} engines: {node: '>=14'} dependencies: '@babel/core': 7.23.9 '@svgr/babel-preset': 7.0.0(@babel/core@7.23.9) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) transitivePeerDependencies: - supports-color - typescript @@ -10501,7 +10828,7 @@ packages: '@babel/runtime': 7.24.7 '@testing-library/dom': 8.20.1 simmerjs: 0.5.6 - webdriverio: 8.36.1(typescript@5.6.3) + webdriverio: 8.36.1(typescript@5.7.2) dev: true /@tootallnate/quickjs-emscripten@0.23.0: @@ -10552,7 +10879,7 @@ packages: /@types/acorn@4.0.6: resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /@types/aria-query@5.0.4: @@ -10689,20 +11016,20 @@ packages: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} dependencies: '@types/eslint': 8.56.10 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /@types/eslint@8.56.10: resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/json-schema': 7.0.15 dev: true /@types/estree-jsx@1.0.0: resolution: {integrity: sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /@types/estree@0.0.39: @@ -10713,6 +11040,10 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + /@types/ethereumjs-util@5.2.0: resolution: {integrity: sha512-qwQgQqXXTRv2h2AlJef+tMEszLFkCB9dWnrJYIdAwqjubERXEc/geB+S3apRw0yQyTVnsBf8r6BhlrE8vx+3WQ==} dependencies: @@ -10959,7 +11290,7 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.6.3): + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2): resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -10971,10 +11302,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@5.5.0) eslint: 8.57.0 @@ -10982,13 +11313,13 @@ packages: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.6.3): + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -11000,11 +11331,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@5.5.0) eslint: 8.57.0 - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true @@ -11017,7 +11348,7 @@ packages: '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.6.3): + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.7.2): resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -11027,12 +11358,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.7.2) debug: 4.3.4(supports-color@5.5.0) eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true @@ -11042,7 +11373,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3): + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.2): resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -11058,13 +11389,13 @@ packages: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.6.3) - typescript: 5.6.3 + ts-api-utils: 1.3.0(typescript@5.7.2) + typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.6.3): + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.7.2): resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -11075,7 +11406,7 @@ packages: '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) eslint: 8.57.0 semver: 7.6.2 transitivePeerDependencies: @@ -11652,7 +11983,7 @@ packages: dependencies: '@vitest/utils': 1.4.0 p-limit: 5.0.0 - pathe: 1.1.1 + pathe: 1.1.2 dev: true /@vitest/snapshot@1.4.0: @@ -11678,7 +12009,7 @@ packages: pretty-format: 29.7.0 dev: true - /@wagmi/connectors@5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2): + /@wagmi/connectors@5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2): resolution: {integrity: sha512-lbjXEv6HhOa9nXZ5r6NGFJdaadCt2Yj9hSWHjKuiTobrE6dEGQqG16mCQS17yXcvXpI62Q/sW6SL347JrBju/Q==} peerDependencies: '@wagmi/core': 2.11.6 @@ -11690,14 +12021,14 @@ packages: dependencies: '@coinbase/wallet-sdk': 4.0.4 '@metamask/sdk': 0.26.4(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1) - '@safe-global/safe-apps-provider': 0.18.1(typescript@5.6.3) - '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.6.3) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2) + '@safe-global/safe-apps-provider': 0.18.1(typescript@5.7.2) + '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.7.2) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) '@walletconnect/ethereum-provider': 2.13.0(@types/react@18.3.3)(react@18.2.0) '@walletconnect/modal': 2.6.2(@types/react@18.3.3)(react@18.2.0) cbw-sdk: /@coinbase/wallet-sdk@3.9.3 - typescript: 5.6.3 - viem: 2.16.2(typescript@5.6.3) + typescript: 5.7.2 + viem: 2.16.2(typescript@5.7.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11723,7 +12054,7 @@ packages: - zod dev: false - /@wagmi/core@2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2): + /@wagmi/core@2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2): resolution: {integrity: sha512-Ohk7Bh+Q8kjzxEHImIq98CnPduz8n1a5bdwJi6F7zU3h62crhlVq7fZBYoBhoDgmX0ROVOMr8WW3XU3XhRwUOw==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -11736,9 +12067,9 @@ packages: optional: true dependencies: eventemitter3: 5.0.1 - mipd: 0.0.5(typescript@5.6.3) - typescript: 5.6.3 - viem: 2.16.2(typescript@5.6.3) + mipd: 0.0.5(typescript@5.7.2) + typescript: 5.7.2 + viem: 2.16.2(typescript@5.7.2) zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' @@ -11749,7 +12080,7 @@ packages: - zod dev: false - /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2): + /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2): resolution: {integrity: sha512-bX84cpLq3WWQgGthJlSgcWPAOdLzrP/W0jnbz5XowkCUn6j/T77WyxN5pBb+HmLoJf3ei9tkX9zWhMpczTc3cA==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -11762,9 +12093,9 @@ packages: optional: true dependencies: eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.6.3) - typescript: 5.6.3 - viem: 2.16.2(typescript@5.6.3) + mipd: 0.0.7(typescript@5.7.2) + typescript: 5.7.2 + viem: 2.16.2(typescript@5.7.2) zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' @@ -11772,7 +12103,7 @@ packages: - react dev: false - /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.17.0): + /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-bX84cpLq3WWQgGthJlSgcWPAOdLzrP/W0jnbz5XowkCUn6j/T77WyxN5pBb+HmLoJf3ei9tkX9zWhMpczTc3cA==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -11785,9 +12116,9 @@ packages: optional: true dependencies: eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.6.3) - typescript: 5.6.3 - viem: 2.17.0(typescript@5.6.3) + mipd: 0.0.7(typescript@5.7.2) + typescript: 5.7.2 + viem: 2.17.0(typescript@5.7.2) zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' @@ -12366,7 +12697,7 @@ packages: tslib: 1.14.1 dev: false - /@wdio/browserstack-service@8.33.1(@wdio/cli@8.33.1)(typescript@5.6.3): + /@wdio/browserstack-service@8.33.1(@wdio/cli@8.33.1)(typescript@5.7.2): resolution: {integrity: sha512-CcGZSp0xJXo0eHWM/LQBtTmV0Y9NsvJuVsj4tmAf5d/92GNHcF6fW22Udsp7or9g2tJyj6LmJI0lcaCOprliiw==} engines: {node: ^16.13 || >=18} peerDependencies: @@ -12375,7 +12706,7 @@ packages: '@percy/appium-app': 2.0.4 '@percy/selenium-webdriver': 2.0.5 '@types/gitconfiglocal': 2.0.3 - '@wdio/cli': 8.33.1(typescript@5.6.3) + '@wdio/cli': 8.33.1(typescript@5.7.2) '@wdio/logger': 8.28.0 '@wdio/reporter': 8.32.4 '@wdio/types': 8.32.4 @@ -12387,7 +12718,7 @@ packages: gitconfiglocal: 2.1.0 got: 12.6.1 uuid: 9.0.1 - webdriverio: 8.33.1(typescript@5.6.3) + webdriverio: 8.33.1(typescript@5.7.2) winston-transport: 4.7.0 yauzl: 3.1.2 transitivePeerDependencies: @@ -12399,7 +12730,7 @@ packages: - utf-8-validate dev: true - /@wdio/cli@8.33.1(typescript@5.6.3): + /@wdio/cli@8.33.1(typescript@5.7.2): resolution: {integrity: sha512-Ngt5R6YAmErkSKnWLWt1JilLIKDPIB0P93bzQhb9bQhmg1arFBcl75uiwe6kf6T355vzcNslMaEJyeuqGChmCg==} engines: {node: ^16.13 || >=18} hasBin: true @@ -12407,7 +12738,7 @@ packages: '@types/node': 20.12.13 '@vitest/snapshot': 1.4.0 '@wdio/config': 8.33.1 - '@wdio/globals': 8.33.1(typescript@5.6.3) + '@wdio/globals': 8.33.1(typescript@5.7.2) '@wdio/logger': 8.28.0 '@wdio/protocols': 8.32.0 '@wdio/types': 8.32.4 @@ -12426,7 +12757,7 @@ packages: lodash.union: 4.6.0 read-pkg-up: 10.0.0 recursive-readdir: 2.2.3 - webdriverio: 8.33.1(typescript@5.6.3) + webdriverio: 8.33.1(typescript@5.7.2) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -12468,12 +12799,12 @@ packages: - supports-color dev: true - /@wdio/globals@8.33.1(typescript@5.6.3): + /@wdio/globals@8.33.1(typescript@5.7.2): resolution: {integrity: sha512-1ud9oq7n9MMNywS/FoMRRWqW6uhcoxgnpXoGeLE2Tr+4f937ABOl+sfZgjycXujyvR7yTL8AROOYajp1Yuv1Xg==} engines: {node: ^16.13 || >=18} optionalDependencies: - expect-webdriverio: 4.13.0(typescript@5.6.3) - webdriverio: 8.33.1(typescript@5.6.3) + expect-webdriverio: 4.13.0(typescript@5.7.2) + webdriverio: 8.33.1(typescript@5.7.2) transitivePeerDependencies: - bufferutil - devtools @@ -12483,14 +12814,14 @@ packages: - utf-8-validate dev: true - /@wdio/local-runner@8.33.1(typescript@5.6.3): + /@wdio/local-runner@8.33.1(typescript@5.7.2): resolution: {integrity: sha512-eQp12wHIkyh5zl9fun1qjv5Qvf4mCHPgLs5sKbfo3OK4LadzmD4/QNvDG8DYq/9cyuhVvnHgbLQ3XAnkoPde3w==} engines: {node: ^16.13 || >=18} dependencies: '@types/node': 20.12.13 '@wdio/logger': 8.28.0 '@wdio/repl': 8.24.12 - '@wdio/runner': 8.33.1(typescript@5.6.3) + '@wdio/runner': 8.33.1(typescript@5.7.2) '@wdio/types': 8.32.4 async-exit-hook: 2.0.1 split2: 4.2.0 @@ -12550,21 +12881,21 @@ packages: object-inspect: 1.13.1 dev: true - /@wdio/runner@8.33.1(typescript@5.6.3): + /@wdio/runner@8.33.1(typescript@5.7.2): resolution: {integrity: sha512-i0eRwMCePKkQocWsdkPQpBb1jELyNR5JCwnmOgM3g9fQI6KAf5D4oEUkNDFL/vD4UtgbSRmux7b7j5G01VvuqQ==} engines: {node: ^16.13 || >=18} dependencies: '@types/node': 20.12.13 '@wdio/config': 8.33.1 - '@wdio/globals': 8.33.1(typescript@5.6.3) + '@wdio/globals': 8.33.1(typescript@5.7.2) '@wdio/logger': 8.28.0 '@wdio/types': 8.32.4 '@wdio/utils': 8.33.1 deepmerge-ts: 5.1.0 - expect-webdriverio: 4.13.0(typescript@5.6.3) + expect-webdriverio: 4.13.0(typescript@5.7.2) gaze: 1.1.3 webdriver: 8.33.1 - webdriverio: 8.33.1(typescript@5.6.3) + webdriverio: 8.33.1(typescript@5.7.2) transitivePeerDependencies: - bufferutil - devtools @@ -12896,7 +13227,7 @@ packages: jsonparse: 1.3.1 through: 2.3.8 - /abitype@0.10.3(typescript@5.6.3): + /abitype@0.10.3(typescript@5.7.2): resolution: {integrity: sha512-tRN+7XIa7J9xugdbRzFv/95ka5ivR/sRe01eiWvM0HWWjHuigSZEACgKa0sj4wGuekTDtghCx+5Izk/cOi78pQ==} peerDependencies: typescript: '>=5.0.4' @@ -12907,10 +13238,10 @@ packages: zod: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: false - /abitype@0.9.8(typescript@5.6.3): + /abitype@0.9.8(typescript@5.7.2): resolution: {integrity: sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==} peerDependencies: typescript: '>=5.0.4' @@ -12921,10 +13252,10 @@ packages: zod: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: false - /abitype@1.0.4(typescript@5.6.3): + /abitype@1.0.4(typescript@5.7.2): resolution: {integrity: sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw==} peerDependencies: typescript: '>=5.0.4' @@ -12935,10 +13266,10 @@ packages: zod: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: false - /abitype@1.0.5(typescript@5.6.3): + /abitype@1.0.5(typescript@5.7.2): resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} peerDependencies: typescript: '>=5.0.4' @@ -12949,7 +13280,7 @@ packages: zod: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: false /abort-controller@3.0.0: @@ -12969,13 +13300,13 @@ packages: mime-types: 2.1.35 negotiator: 0.6.3 - /acorn-import-assertions@1.9.0(acorn@8.11.3): + /acorn-import-assertions@1.9.0(acorn@8.14.0): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} deprecated: package has been renamed to acorn-import-attributes peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.3 + acorn: 8.14.0 dev: true /acorn-jsx@5.3.2(acorn@8.11.3): @@ -12986,6 +13317,14 @@ packages: acorn: 8.11.3 dev: true + /acorn-jsx@5.3.2(acorn@8.14.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + dev: true + /acorn-walk@8.3.3: resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} engines: {node: '>=0.4.0'} @@ -12997,6 +13336,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + /adm-zip@0.4.16: resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} engines: {node: '>=0.3.0'} @@ -13262,6 +13606,9 @@ packages: is-string: 1.0.7 dev: true + /array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -14199,10 +14546,10 @@ packages: type-detect: 4.1.0 dev: true - /chain-registry@1.69.54: - resolution: {integrity: sha512-LqcYWprXXAV0H/4TJWBKV2uqiqXLiyP4TeCZ7+53nI27s2JsY8/LeOoK8TWTuhB9bqIp78pAlnmhK/M/VZSlEg==} + /chain-registry@1.69.57: + resolution: {integrity: sha512-i9QC8yRJjoYCxB4VsPXxa5TcVH2dctKxejIfOohPr78j3F+qZw5yob8XaKVG0/iK5s4tVZnhur5ssHuebZHuMw==} dependencies: - '@chain-registry/types': 0.50.29 + '@chain-registry/types': 0.50.31 dev: false /chalk@2.4.2: @@ -14243,7 +14590,6 @@ packages: /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: true /charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} @@ -14360,7 +14706,6 @@ packages: /cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} - dev: true /cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -14516,6 +14861,10 @@ packages: resolution: {integrity: sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w==} dev: false + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + /commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -14537,6 +14886,20 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} + /comment-json@4.2.5: + resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} + engines: {node: '>= 6'} + dependencies: + array-timsort: 1.0.3 + core-util-is: 1.0.3 + esprima: 4.0.1 + has-own-prop: 2.0.0 + repeat-string: 1.6.1 + + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -14584,6 +14947,9 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + /confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} dev: true @@ -14603,7 +14969,6 @@ packages: /consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} - dev: false /console-browserify@1.2.0: resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} @@ -14698,7 +15063,7 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} requiresBuild: true - /cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.13)(cosmiconfig@8.3.6)(typescript@5.6.3): + /cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.13)(cosmiconfig@8.3.6)(typescript@5.7.2): resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} peerDependencies: @@ -14707,9 +15072,9 @@ packages: typescript: '>=4' dependencies: '@types/node': 20.12.13 - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) jiti: 1.21.0 - typescript: 5.6.3 + typescript: 5.7.2 dev: true /cosmiconfig@5.2.1: @@ -14732,7 +15097,7 @@ packages: path-type: 4.0.0 yaml: 1.10.2 - /cosmiconfig@8.3.6(typescript@5.6.3): + /cosmiconfig@8.3.6(typescript@5.7.2): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} peerDependencies: @@ -14745,7 +15110,7 @@ packages: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - typescript: 5.6.3 + typescript: 5.7.2 dev: true /cosmjs-types@0.7.2: @@ -15306,9 +15671,8 @@ packages: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - /defu@6.1.3: - resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==} - dev: false + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} /degenerator@5.0.1: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} @@ -15414,6 +15778,10 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + /diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + dev: true + /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -15521,6 +15889,10 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + /drange@1.1.1: + resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} + engines: {node: '>=4'} + /duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} dependencies: @@ -15951,6 +16323,38 @@ packages: '@esbuild/win32-x64': 0.19.12 dev: true + /esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + dev: true + /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -16022,8 +16426,8 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -16058,7 +16462,7 @@ packages: eslint: 8.57.0 dev: true - /eslint-config-standard-with-typescript@43.0.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.6.3): + /eslint-config-standard-with-typescript@43.0.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.7.2): resolution: {integrity: sha512-WfZ986+qzIzX6dcr4yGUyVb/l9N3Z8wPXCc5z/70fljs3UbWhhV+WxrfgsqMToRzuuyX9MqZ974pq2UPhDTOcA==} deprecated: Please use eslint-config-love, instead. peerDependencies: @@ -16069,14 +16473,14 @@ packages: eslint-plugin-promise: ^6.0.0 typescript: '*' dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.6.3) - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-config-standard: 17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.2.0)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-n: 16.6.2(eslint@8.57.0) eslint-plugin-promise: 6.2.0(eslint@8.57.0) - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color dev: true @@ -16150,7 +16554,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -16181,7 +16585,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.6.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.7.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -16438,7 +16842,7 @@ packages: /estree-util-attach-comments@3.0.0: resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /estree-util-build-jsx@3.0.1: @@ -16480,7 +16884,7 @@ packages: /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /esutils@2.0.3: @@ -16786,7 +17190,7 @@ packages: strip-final-newline: 3.0.0 dev: true - /expect-webdriverio@4.13.0(typescript@5.6.3): + /expect-webdriverio@4.13.0(typescript@5.7.2): resolution: {integrity: sha512-y2LF6vECifTOiOk0i0FMPWJGyntiW+eqzQWFZimu9Cae8XMUH5q4F5SzpfGCxsvmOdf3uFjlr+u9IXrQBN5o0Q==} engines: {node: '>=16 || >=18 || >=20'} dependencies: @@ -16795,9 +17199,9 @@ packages: jest-matcher-utils: 29.7.0 lodash.isequal: 4.5.0 optionalDependencies: - '@wdio/globals': 8.33.1(typescript@5.6.3) + '@wdio/globals': 8.33.1(typescript@5.7.2) '@wdio/logger': 8.28.0 - webdriverio: 8.36.1(typescript@5.6.3) + webdriverio: 8.36.1(typescript@5.7.2) transitivePeerDependencies: - bufferutil - devtools @@ -16856,7 +17260,6 @@ packages: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - dev: true /extract-zip@2.0.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} @@ -16988,7 +17391,6 @@ packages: engines: {node: '>=8'} dependencies: escape-string-regexp: 1.0.5 - dev: true /figures@5.0.0: resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} @@ -17072,6 +17474,14 @@ packages: pkg-dir: 4.2.0 dev: true + /find-cache-dir@5.0.0: + resolution: {integrity: sha512-OuWNfjfP05JcpAP3JPgAKUhWefjMRfI5iAoSsvE24ANYWJaepAtlSgWECSVEuRgSXpyNEc9DJwG/TZpgcOqyig==} + engines: {node: '>=16'} + dependencies: + common-path-prefix: 3.0.0 + pkg-dir: 7.0.0 + dev: true + /find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} @@ -17496,6 +17906,15 @@ packages: ini: 4.1.1 dev: true + /global-prefix@4.0.0: + resolution: {integrity: sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==} + engines: {node: '>=16'} + dependencies: + ini: 4.1.3 + kind-of: 6.0.3 + which: 4.0.0 + dev: true + /global@4.4.0: resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} dependencies: @@ -17674,11 +18093,11 @@ packages: resolution: {integrity: sha512-+F3ZqrNV/CFXXfZ2lXBINHi+rM4Xw3CDC5z2CDK3NMPocjonKipGLLDSkrqY9DOrioZNPTIdDMWfQKm//3X2DA==} dependencies: cookie-es: 1.0.0 - defu: 6.1.3 + defu: 6.1.4 destr: 2.0.3 iron-webcrypto: 1.0.0 radix3: 1.1.0 - ufo: 1.5.3 + ufo: 1.5.4 uncrypto: 0.1.3 unenv: 1.8.0 dev: false @@ -17702,10 +18121,10 @@ packages: hardhat: ^2.0.0 dependencies: chokidar: 3.5.3 - hardhat: 2.22.13(ts-node@10.9.2)(typescript@5.6.3) + hardhat: 2.22.13(ts-node@10.9.2)(typescript@5.7.2) dev: false - /hardhat@2.22.13(ts-node@10.9.2)(typescript@5.6.3): + /hardhat@2.22.13(ts-node@10.9.2)(typescript@5.7.2): resolution: {integrity: sha512-psVJX4FSXDpSXwsU8OcKTJN04pQEj9cFBMX5OPko+OFwbIoiOpvRmafa954/UaA1934npTj8sV3gaTSdx9bPbA==} hasBin: true peerDependencies: @@ -17757,9 +18176,9 @@ packages: solc: 0.8.26(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.2(@types/node@20.12.13)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@20.12.13)(typescript@5.7.2) tsort: 0.0.1 - typescript: 5.6.3 + typescript: 5.7.2 undici: 5.28.4 uuid: 8.3.2 ws: 7.5.9 @@ -17782,6 +18201,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + /has-own-prop@2.0.0: + resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==} + engines: {node: '>=8'} + /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: @@ -17903,7 +18326,7 @@ packages: /hast-util-to-estree@3.1.0: resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/estree-jsx': 1.0.0 '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -17926,7 +18349,7 @@ packages: /hast-util-to-jsx-runtime@2.3.0: resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/hast': 3.0.4 '@types/unist': 3.0.2 comma-separated-tokens: 2.0.3 @@ -18286,6 +18709,11 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true + /ini@4.1.3: + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /inline-style-parser@0.1.1: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} dev: true @@ -18313,7 +18741,6 @@ packages: strip-ansi: 6.0.1 through: 2.3.8 wrap-ansi: 6.2.0 - dev: true /inquirer@9.2.12: resolution: {integrity: sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==} @@ -18860,7 +19287,7 @@ packages: /is-reference@3.0.1: resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 dev: true /is-regex@1.1.4: @@ -19494,9 +19921,6 @@ packages: engines: {node: '>=6'} hasBin: true - /jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -19630,7 +20054,7 @@ packages: '@ethersproject/bignumber': 5.7.0 '@keplr-wallet/types': 0.11.64 '@types/google-protobuf': 3.15.12 - chain-registry: 1.69.54 + chain-registry: 1.69.57 cosmjs-types: 0.8.0 long: 4.0.0 text-encoding: 0.7.0 @@ -19759,16 +20183,16 @@ packages: citty: 0.1.5 clipboardy: 3.0.0 consola: 3.2.3 - defu: 6.1.3 + defu: 6.1.4 get-port-please: 3.1.1 h3: 1.9.0 http-shutdown: 1.2.2 jiti: 1.21.0 - mlly: 1.4.2 + mlly: 1.7.3 node-forge: 1.3.1 - pathe: 1.1.1 + pathe: 1.1.2 std-env: 3.6.0 - ufo: 1.5.3 + ufo: 1.5.4 untun: 0.1.3 uqr: 0.1.2 dev: false @@ -19813,7 +20237,7 @@ packages: engines: {node: '>=14'} dependencies: mlly: 1.4.2 - pkg-types: 1.0.3 + pkg-types: 1.2.1 dev: true /locate-app@2.4.15: @@ -20076,6 +20500,12 @@ packages: hasBin: true dev: true + /magic-string@0.30.14: + resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true + /magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} @@ -20715,7 +21145,7 @@ packages: /micromark-extension-mdx-expression@3.0.0: resolution: {integrity: sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.1 micromark-factory-space: 2.0.0 @@ -20729,7 +21159,7 @@ packages: resolution: {integrity: sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.1 @@ -20749,7 +21179,7 @@ packages: /micromark-extension-mdxjs-esm@3.0.0: resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-core-commonmark: 2.0.0 micromark-util-character: 2.1.0 @@ -20763,8 +21193,8 @@ packages: /micromark-extension-mdxjs@3.0.0: resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.0 micromark-extension-mdx-md: 2.0.0 @@ -20793,7 +21223,7 @@ packages: /micromark-factory-mdx-expression@2.0.1: resolution: {integrity: sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-util-character: 2.1.0 micromark-util-events-to-acorn: 2.0.2 @@ -20879,7 +21309,7 @@ packages: resolution: {integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/unist': 3.0.2 devlop: 1.1.0 estree-util-visit: 2.0.0 @@ -21089,7 +21519,7 @@ packages: resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} engines: {node: '>=16 || 14 >=14.17'} - /mipd@0.0.5(typescript@5.6.3): + /mipd@0.0.5(typescript@5.7.2): resolution: {integrity: sha512-gbKA784D2WKb5H/GtqEv+Ofd1S9Zj+Z/PGDIl1u1QAbswkxD28BQ5bSXQxkeBzPBABg1iDSbiwGG1XqlOxRspA==} peerDependencies: typescript: '>=5.0.4' @@ -21097,15 +21527,15 @@ packages: typescript: optional: true dependencies: - typescript: 5.6.3 - viem: 1.20.0(typescript@5.6.3) + typescript: 5.7.2 + viem: 1.20.0(typescript@5.7.2) transitivePeerDependencies: - bufferutil - utf-8-validate - zod dev: false - /mipd@0.0.7(typescript@5.6.3): + /mipd@0.0.7(typescript@5.7.2): resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} peerDependencies: typescript: '>=5.0.4' @@ -21113,7 +21543,7 @@ packages: typescript: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: false /mitt@2.1.0: @@ -21145,10 +21575,19 @@ packages: /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} dependencies: - acorn: 8.11.3 - pathe: 1.1.1 - pkg-types: 1.0.3 - ufo: 1.5.3 + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + dev: true + + /mlly@1.7.3: + resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 /mnemonist@0.38.5: resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} @@ -21228,7 +21667,7 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /msw@2.1.7(typescript@5.6.3): + /msw@2.1.7(typescript@5.7.2): resolution: {integrity: sha512-yTIYqEMqDSrdbVMrfmqP6rTKQsnIbglTvVmAHDWwNegyXPXRcV+RjsaFEqubRS266gwWCDLm9YdOkWSKLdDvJQ==} engines: {node: '>=18'} hasBin: true @@ -21255,8 +21694,8 @@ packages: outvariant: 1.4.2 path-to-regexp: 6.2.1 strict-event-emitter: 0.5.1 - type-fest: 4.10.2 - typescript: 5.6.3 + type-fest: 4.30.0 + typescript: 5.7.2 yargs: 17.7.2 dev: true @@ -21295,7 +21734,6 @@ packages: /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - dev: true /mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} @@ -21684,7 +22122,7 @@ packages: dependencies: destr: 2.0.3 node-fetch-native: 1.6.4 - ufo: 1.5.3 + ufo: 1.5.4 dev: false /on-exit-leak-free@0.2.0: @@ -21949,6 +22387,9 @@ packages: netmask: 2.0.2 dev: true + /package-manager-detector@0.2.7: + resolution: {integrity: sha512-g4+387DXDKlZzHkP+9FLt8yKj8+/3tOkPv7DVTJGGRm00RkEWgqbFstX1mXJ4M0VDYhUqsTOiISqNOJnhAu3PQ==} + /pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} dev: true @@ -22094,6 +22535,10 @@ packages: /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -22133,7 +22578,7 @@ packages: /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-walker: 3.0.3 is-reference: 3.0.1 dev: true @@ -22141,6 +22586,9 @@ packages: /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -22249,12 +22697,19 @@ packages: find-up: 5.0.0 dev: true - /pkg-types@1.0.3: - resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + /pkg-dir@7.0.0: + resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} + engines: {node: '>=14.16'} dependencies: - jsonc-parser: 3.2.0 - mlly: 1.4.2 - pathe: 1.1.1 + find-up: 6.3.0 + dev: true + + /pkg-types@1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.3 + pathe: 1.1.2 /pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} @@ -22310,7 +22765,7 @@ packages: dependencies: lilconfig: 3.1.2 postcss: 8.4.39 - ts-node: 10.9.2(@types/node@20.12.13)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@20.12.13)(typescript@5.7.2) yaml: 2.4.5 /postcss-nested@6.2.0(postcss@8.4.39): @@ -22337,8 +22792,8 @@ packages: engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + picocolors: 1.1.1 + source-map-js: 1.2.1 /postcss@8.4.39: resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} @@ -22348,6 +22803,15 @@ packages: picocolors: 1.0.1 source-map-js: 1.2.0 + /postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true + /preact@10.17.0: resolution: {integrity: sha512-SNsI8cbaCcUS5tbv9nlXuCfIXnJ9ysBMWk0WnB6UWwcVA3qZ2O6FxqDFECMAMttvLQcW/HaNZUe2BLidyvrVYw==} dev: false @@ -22641,7 +23105,7 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - /puppeteer-core@20.9.0(typescript@5.6.3): + /puppeteer-core@20.9.0(typescript@5.7.2): resolution: {integrity: sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==} engines: {node: '>=16.3.0'} requiresBuild: true @@ -22651,12 +23115,12 @@ packages: typescript: optional: true dependencies: - '@puppeteer/browsers': 1.4.6(typescript@5.6.3) + '@puppeteer/browsers': 1.4.6(typescript@5.7.2) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0(encoding@0.1.13) debug: 4.3.4(supports-color@5.5.0) devtools-protocol: 0.0.1147663 - typescript: 5.6.3 + typescript: 5.7.2 ws: 8.13.0 transitivePeerDependencies: - bufferutil @@ -22790,6 +23254,13 @@ packages: resolution: {integrity: sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A==} dev: false + /randexp@0.5.3: + resolution: {integrity: sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==} + engines: {node: '>=4'} + dependencies: + drange: 1.1.1 + ret: 0.2.2 + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -23252,7 +23723,7 @@ packages: '@types/normalize-package-data': 2.4.1 normalize-package-data: 6.0.0 parse-json: 7.1.1 - type-fest: 4.10.2 + type-fest: 4.30.0 dev: true /readable-stream@1.0.34: @@ -23568,6 +24039,10 @@ packages: unified: 11.0.4 dev: true + /repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -23659,6 +24134,10 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 + /ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + /retimer@2.0.0: resolution: {integrity: sha512-KLXY85WkEq2V2bKex/LOO1ViXVn2KGYe4PYysAdYdjmraYIUsVkXu8O4am+8+5UbaaGl1qho4aqAAPHNQ4GSbg==} dev: true @@ -23769,26 +24248,32 @@ packages: fsevents: 2.3.3 dev: true - /rollup@4.9.6: - resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} + /rollup@4.28.1: + resolution: {integrity: sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.9.6 - '@rollup/rollup-android-arm64': 4.9.6 - '@rollup/rollup-darwin-arm64': 4.9.6 - '@rollup/rollup-darwin-x64': 4.9.6 - '@rollup/rollup-linux-arm-gnueabihf': 4.9.6 - '@rollup/rollup-linux-arm64-gnu': 4.9.6 - '@rollup/rollup-linux-arm64-musl': 4.9.6 - '@rollup/rollup-linux-riscv64-gnu': 4.9.6 - '@rollup/rollup-linux-x64-gnu': 4.9.6 - '@rollup/rollup-linux-x64-musl': 4.9.6 - '@rollup/rollup-win32-arm64-msvc': 4.9.6 - '@rollup/rollup-win32-ia32-msvc': 4.9.6 - '@rollup/rollup-win32-x64-msvc': 4.9.6 + '@rollup/rollup-android-arm-eabi': 4.28.1 + '@rollup/rollup-android-arm64': 4.28.1 + '@rollup/rollup-darwin-arm64': 4.28.1 + '@rollup/rollup-darwin-x64': 4.28.1 + '@rollup/rollup-freebsd-arm64': 4.28.1 + '@rollup/rollup-freebsd-x64': 4.28.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.28.1 + '@rollup/rollup-linux-arm-musleabihf': 4.28.1 + '@rollup/rollup-linux-arm64-gnu': 4.28.1 + '@rollup/rollup-linux-arm64-musl': 4.28.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.28.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.28.1 + '@rollup/rollup-linux-riscv64-gnu': 4.28.1 + '@rollup/rollup-linux-s390x-gnu': 4.28.1 + '@rollup/rollup-linux-x64-gnu': 4.28.1 + '@rollup/rollup-linux-x64-musl': 4.28.1 + '@rollup/rollup-win32-arm64-msvc': 4.28.1 + '@rollup/rollup-win32-ia32-msvc': 4.28.1 + '@rollup/rollup-win32-x64-msvc': 4.28.1 fsevents: 2.3.3 dev: true @@ -23823,7 +24308,6 @@ packages: /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} - dev: true /run-async@3.0.0: resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} @@ -23966,6 +24450,12 @@ packages: engines: {node: '>=10'} hasBin: true + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true + /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -24280,6 +24770,10 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + /source-map-resolve@0.6.0: resolution: {integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated @@ -24868,7 +25362,7 @@ packages: hasBin: true dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.11.3 + acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -25070,13 +25564,13 @@ packages: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} dev: true - /ts-api-utils@1.3.0(typescript@5.6.3): + /ts-api-utils@1.3.0(typescript@5.7.2): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: true /ts-interface-checker@0.1.13: @@ -25096,7 +25590,7 @@ packages: code-block-writer: 13.0.3 dev: true - /ts-node@10.9.2(@types/node@20.12.13)(typescript@5.6.3): + /ts-node@10.9.2(@types/node@20.12.13)(typescript@5.7.2): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -25122,11 +25616,23 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.3 + typescript: 5.7.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - /tsconfck@3.0.1(typescript@5.6.3): + /ts-patch@3.3.0: + resolution: {integrity: sha512-zAOzDnd5qsfEnjd9IGy1IRuvA7ygyyxxdxesbhMdutt8AHFjD8Vw8hU2rMF89HX1BKRWFYqKHrO8Q6lw0NeUZg==} + hasBin: true + dependencies: + chalk: 4.1.2 + global-prefix: 4.0.0 + minimist: 1.2.8 + resolve: 1.22.8 + semver: 7.6.3 + strip-ansi: 6.0.1 + dev: true + + /tsconfck@3.0.1(typescript@5.7.2): resolution: {integrity: sha512-7ppiBlF3UEddCLeI1JRx5m2Ryq+xk4JrZuq4EuYXykipebaq1dV0Fhgr1hb7CkmHt32QSgOZlcqVLEtHBG4/mg==} engines: {node: ^18 || >=20} hasBin: true @@ -25136,7 +25642,7 @@ packages: typescript: optional: true dependencies: - typescript: 5.6.3 + typescript: 5.7.2 dev: true /tsconfig-paths@3.15.0: @@ -25265,8 +25771,8 @@ packages: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} - /type-fest@4.10.2: - resolution: {integrity: sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==} + /type-fest@4.30.0: + resolution: {integrity: sha512-G6zXWS1dLj6eagy6sVhOMQiLtJdxQBHIA9Z6HFUNLOlr6MFOgzV8wvmidtPONfPtEUv0uZsy77XJNzTAfwPDaA==} engines: {node: '>=16'} dev: true @@ -25340,13 +25846,51 @@ packages: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true + dev: true + + /typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + /typia@7.1.0(@samchon/openapi@2.0.1)(typescript@5.6.3): + resolution: {integrity: sha512-pG3H1KNIo3/Cd0VssdE+badLYnLnAQ7QtdYldqzqzXIDWG+Ve5fl0H4vQ/j+d1+rOAuurxfZ5bsCcw83SiYDVw==} + hasBin: true + peerDependencies: + '@samchon/openapi': '>=2.0.1 <3.0.0' + typescript: '>=4.8.0 <5.8.0' + dependencies: + '@samchon/openapi': 2.0.1 + commander: 10.0.1 + comment-json: 4.2.5 + inquirer: 8.2.6 + package-manager-detector: 0.2.7 + randexp: 0.5.3 + typescript: 5.6.3 + dev: true + + /typia@7.1.0(@samchon/openapi@2.0.1)(typescript@5.7.2): + resolution: {integrity: sha512-pG3H1KNIo3/Cd0VssdE+badLYnLnAQ7QtdYldqzqzXIDWG+Ve5fl0H4vQ/j+d1+rOAuurxfZ5bsCcw83SiYDVw==} + hasBin: true + peerDependencies: + '@samchon/openapi': '>=2.0.1 <3.0.0' + typescript: '>=4.8.0 <5.8.0' + dependencies: + '@samchon/openapi': 2.0.1 + commander: 10.0.1 + comment-json: 4.2.5 + inquirer: 8.2.6 + package-manager-detector: 0.2.7 + randexp: 0.5.3 + typescript: 5.7.2 + dev: false /ua-parser-js@1.0.37: resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} dev: false - /ufo@1.5.3: - resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + /ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} /uint8arrays@3.1.0: resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} @@ -25397,10 +25941,10 @@ packages: resolution: {integrity: sha512-uIGbdCWZfhRRmyKj1UioCepQ0jpq638j/Cf0xFTn4zD1nGJ2lSdzYHLzfdXN791oo/0juUiSWW1fBklXMTsuqg==} dependencies: consola: 3.2.3 - defu: 6.1.3 + defu: 6.1.4 mime: 3.0.0 node-fetch-native: 1.6.4 - pathe: 1.1.1 + pathe: 1.1.2 dev: false /unfetch@4.2.0: @@ -25535,6 +26079,14 @@ packages: engines: {node: '>= 0.8'} dev: false + /unplugin@1.16.0: + resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==} + engines: {node: '>=14.0.0'} + dependencies: + acorn: 8.14.0 + webpack-virtual-modules: 0.6.2 + dev: true + /unstorage@1.10.1(idb-keyval@6.2.1): resolution: {integrity: sha512-rWQvLRfZNBpF+x8D3/gda5nUCQL2PgXy2jNG4U7/Rc9BGEv9+CAJd0YyGCROUBKs9v49Hg8huw3aih5Bf5TAVw==} peerDependencies: @@ -25587,7 +26139,7 @@ packages: mri: 1.2.0 node-fetch-native: 1.6.4 ofetch: 1.3.4 - ufo: 1.5.3 + ufo: 1.5.4 transitivePeerDependencies: - supports-color dev: false @@ -25602,7 +26154,7 @@ packages: dependencies: citty: 0.1.5 consola: 3.2.3 - pathe: 1.1.1 + pathe: 1.1.2 dev: false /unzipper@0.11.6: @@ -25623,7 +26175,7 @@ packages: dependencies: browserslist: 4.23.0 escalade: 3.1.2 - picocolors: 1.0.1 + picocolors: 1.1.1 /uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} @@ -25857,7 +26409,7 @@ packages: vfile-message: 4.0.2 dev: true - /viem@1.20.0(typescript@5.6.3): + /viem@1.20.0(typescript@5.7.2): resolution: {integrity: sha512-yPjV9pJr10xi28C/9LEvs5zdZNEMiru3Kz7nufghVYABJAfeSkoZQXb6b23n7MscS7c55JO5nmUI3xKkd9g6Yg==} peerDependencies: typescript: '>=5.0.4' @@ -25870,9 +26422,9 @@ packages: '@noble/hashes': 1.3.2 '@scure/bip32': 1.3.2 '@scure/bip39': 1.2.1 - abitype: 0.9.8(typescript@5.6.3) + abitype: 0.9.8(typescript@5.7.2) isows: 1.0.3(ws@8.13.0) - typescript: 5.6.3 + typescript: 5.7.2 ws: 8.13.0 transitivePeerDependencies: - bufferutil @@ -25880,7 +26432,7 @@ packages: - zod dev: false - /viem@2.16.2(typescript@5.6.3): + /viem@2.16.2(typescript@5.7.2): resolution: {integrity: sha512-qor3v1cJFR3jcPtcJxPbKfKURAH2agNf2IWZIaSReV6teNLERiu4Sr7kbqpkIeTAEpiDCVQwg336M+mub1m+pg==} peerDependencies: typescript: '>=5.0.4' @@ -25893,9 +26445,9 @@ packages: '@noble/hashes': 1.3.2 '@scure/bip32': 1.3.2 '@scure/bip39': 1.2.1 - abitype: 1.0.4(typescript@5.6.3) + abitype: 1.0.4(typescript@5.7.2) isows: 1.0.4(ws@8.17.1) - typescript: 5.6.3 + typescript: 5.7.2 ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -25903,7 +26455,7 @@ packages: - zod dev: false - /viem@2.17.0(typescript@5.6.3): + /viem@2.17.0(typescript@5.7.2): resolution: {integrity: sha512-+gaVlsfDsHL1oYdjpatdRxW1WK/slLYVvpOws3fEdLfQFUToezKI6YLC9l1g2uKm4Hg3OdGX1KQy/G7/58tTKQ==} peerDependencies: typescript: '>=5.0.4' @@ -25916,9 +26468,9 @@ packages: '@noble/hashes': 1.4.0 '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 - abitype: 1.0.5(typescript@5.6.3) + abitype: 1.0.5(typescript@5.7.2) isows: 1.0.4(ws@8.17.1) - typescript: 5.6.3 + typescript: 5.7.2 ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -25933,7 +26485,7 @@ packages: dependencies: cac: 6.7.14 debug: 4.3.4(supports-color@5.5.0) - pathe: 1.1.1 + pathe: 1.1.2 picocolors: 1.0.1 vite: 5.0.12(@types/node@20.12.13) transitivePeerDependencies: @@ -25969,13 +26521,13 @@ packages: vite: 4.3.9(@types/node@20.12.13) dev: true - /vite-plugin-svgr@3.2.0(rollup@2.79.1)(typescript@5.6.3)(vite@4.3.9): + /vite-plugin-svgr@3.2.0(rollup@2.79.1)(typescript@5.7.2)(vite@4.3.9): resolution: {integrity: sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==} peerDependencies: vite: ^2.6.0 || 3 || 4 dependencies: '@rollup/pluginutils': 5.0.3(rollup@2.79.1) - '@svgr/core': 7.0.0(typescript@5.6.3) + '@svgr/core': 7.0.0(typescript@5.7.2) '@svgr/plugin-jsx': 7.0.0 vite: 4.3.9(@types/node@20.12.13) transitivePeerDependencies: @@ -25984,7 +26536,7 @@ packages: - typescript dev: true - /vite-tsconfig-paths@4.3.1(typescript@5.6.3)(vite@5.0.12): + /vite-tsconfig-paths@4.3.1(typescript@5.7.2)(vite@5.0.12): resolution: {integrity: sha512-cfgJwcGOsIxXOLU/nELPny2/LUD/lcf1IbfyeKTv2bsupVbTH/xpFtdQlBmIP1GEK2CjjLxYhFfB+QODFAx5aw==} peerDependencies: vite: '*' @@ -25994,7 +26546,7 @@ packages: dependencies: debug: 4.3.4(supports-color@5.5.0) globrex: 0.1.2 - tsconfck: 3.0.1(typescript@5.6.3) + tsconfck: 3.0.1(typescript@5.7.2) vite: 5.0.12(@types/node@20.12.13) transitivePeerDependencies: - supports-color @@ -26064,8 +26616,57 @@ packages: dependencies: '@types/node': 20.12.13 esbuild: 0.19.12 - postcss: 8.4.39 - rollup: 4.9.6 + postcss: 8.4.49 + rollup: 4.28.1 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@6.0.3(@types/node@20.12.13)(tsx@4.7.1): + resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + '@types/node': 20.12.13 + esbuild: 0.24.0 + postcss: 8.4.49 + rollup: 4.28.1 + tsx: 4.7.1 optionalDependencies: fsevents: 2.3.3 dev: true @@ -26155,7 +26756,7 @@ packages: - supports-color dev: true - /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2): + /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2): resolution: {integrity: sha512-pYGTLmVIAC4q/a90i+vlrkJL86n5Kf/gwhhi65XtQklpsUQWrKDmn4dsY1/yFeAmZ/1yx1mpxYpX3LI97eTuWA==} peerDependencies: '@tanstack/react-query': '>=5.0.0' @@ -26167,12 +26768,12 @@ packages: optional: true dependencies: '@tanstack/react-query': 5.37.1(react@18.2.0) - '@wagmi/connectors': 5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.6.3)(viem@2.16.2) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.6.3)(viem@2.16.2) + '@wagmi/connectors': 5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) react: 18.2.0 - typescript: 5.6.3 + typescript: 5.7.2 use-sync-external-store: 1.2.0(react@18.2.0) - viem: 2.16.2(typescript@5.6.3) + viem: 2.16.2(typescript@5.7.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -26496,7 +27097,7 @@ packages: - utf-8-validate dev: true - /webdriverio@8.33.1(typescript@5.6.3): + /webdriverio@8.33.1(typescript@5.7.2): resolution: {integrity: sha512-1DsF8sx1a46AoVYCUpEwJYU74iBAW/U2H5r6p+60ct7dIiFmxmc4uCbOqtf7NLOTgrIzAOaRnT0EsrRICpg5Qw==} engines: {node: ^16.13 || >=18} peerDependencies: @@ -26523,7 +27124,7 @@ packages: lodash.clonedeep: 4.5.0 lodash.zip: 4.2.0 minimatch: 9.0.4 - puppeteer-core: 20.9.0(typescript@5.6.3) + puppeteer-core: 20.9.0(typescript@5.7.2) query-selector-shadow-dom: 1.0.1 resq: 1.11.0 rgb2hex: 0.2.5 @@ -26537,7 +27138,7 @@ packages: - utf-8-validate dev: true - /webdriverio@8.36.1(typescript@5.6.3): + /webdriverio@8.36.1(typescript@5.7.2): resolution: {integrity: sha512-vzE09oFQeMbOYJ/75jZ13sDIljzC3HH7uoUJKAMAEtyrn/bu1F9Sg/4IDEsvQaRD3pz3ae6SkRld33lcQk6HJA==} engines: {node: ^16.13 || >=18} peerDependencies: @@ -26564,7 +27165,7 @@ packages: lodash.clonedeep: 4.5.0 lodash.zip: 4.2.0 minimatch: 9.0.4 - puppeteer-core: 20.9.0(typescript@5.6.3) + puppeteer-core: 20.9.0(typescript@5.7.2) query-selector-shadow-dom: 1.0.1 resq: 1.11.0 rgb2hex: 0.2.5 @@ -26595,6 +27196,10 @@ packages: engines: {node: '>=10.13.0'} dev: true + /webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + dev: true + /webpack@5.91.0: resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==} engines: {node: '>=10.13.0'} @@ -26606,12 +27211,12 @@ packages: optional: true dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) + acorn: 8.14.0 + acorn-import-assertions: 1.9.0(acorn@8.14.0) browserslist: 4.23.0 chrome-trace-event: 1.0.4 enhanced-resolve: 5.16.1 diff --git a/scripts/indexer-renames.ts b/scripts/indexer-renames.ts index 08714f31b..63079f5e3 100644 --- a/scripts/indexer-renames.ts +++ b/scripts/indexer-renames.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-extraneous-dependencies import { EnumDeclaration, InterfaceDeclaration, @@ -50,5 +51,16 @@ types.forEach((typeDecl: TypeAliasDeclaration) => { typeDecl.rename(newName); }); +interfaces.forEach((interfaceDeclaration) => { + interfaceDeclaration.getProperties().forEach((property) => { + if (property.hasQuestionToken()) { + const typeNode = property.getTypeNode(); + if (typeNode && !typeNode.getText().includes('null')) { + property.setType(`${typeNode.getText()} | null`); + } + } + }); +}); + // Save the changes sourceFile.saveSync(); diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh index 32c2536af..a4110c9f7 100755 --- a/scripts/swagger_codegen.sh +++ b/scripts/swagger_codegen.sh @@ -41,5 +41,3 @@ cd $CURRENT_DIR npx tsx scripts/indexer-renames.ts pnpm prettier ./src/types/indexer/indexerApiGen.ts --write sed -i '' 's/export interface IndexerAPIOrderStatus {}/export type IndexerAPIOrderStatus = IndexerOrderStatus | IndexerBestEffortOpenedStatus;/' ./src/types/indexer/indexerApiGen.ts - - diff --git a/src/abacus-ts/accountRefreshSignal.ts b/src/abacus-ts/accountRefreshSignal.ts index c57851938..fc503f600 100644 --- a/src/abacus-ts/accountRefreshSignal.ts +++ b/src/abacus-ts/accountRefreshSignal.ts @@ -1,3 +1,7 @@ +import { min } from 'lodash'; + +import { timeUnits } from '@/constants/time'; + import { appQueryClient } from '@/state/appQueryClient'; import { Signal } from './signal'; @@ -6,8 +10,18 @@ import { Signal } from './signal'; // mostly network reconnects, refreshes, page visibility changes, etc export const accountRefreshSignal = new Signal(); +const BUFFER_REFRESH_TIME = timeUnits.second * 5; export function refreshIndexerQueryOnAccountSocketRefresh(key: any[]) { - return accountRefreshSignal.onTrigger(() => - appQueryClient.invalidateQueries({ queryKey: ['indexer', ...key], exact: false }) - ); + return accountRefreshSignal.onTrigger(() => { + // we don't refresh if all data was updated within the last few seconds + const minTime = min( + appQueryClient + .getQueryCache() + .findAll({ queryKey: ['indexer', ...key], exact: false }) + .map((q) => q.state.dataUpdatedAt) + ); + if ((minTime ?? 0) < new Date().valueOf() - BUFFER_REFRESH_TIME) { + appQueryClient.invalidateQueries({ queryKey: ['indexer', ...key], exact: false }); + } + }); } diff --git a/src/abacus-ts/rest/blockTradingRewards.ts b/src/abacus-ts/rest/blockTradingRewards.ts index d42bccdd0..d9fba5241 100644 --- a/src/abacus-ts/rest/blockTradingRewards.ts +++ b/src/abacus-ts/rest/blockTradingRewards.ts @@ -1,3 +1,5 @@ +import { isParentSubaccountBlockRewardResponse } from '@/types/indexer/indexerChecks'; + import { type RootStore } from '@/state/_store'; import { setAccountBlockTradingRewardsRaw } from '@/state/raw'; @@ -30,7 +32,10 @@ export function setUpBlockTradingRewardsQuery(store: RootStore) { store.dispatch( setAccountBlockTradingRewardsRaw({ status: blockTradingRewards.status, - data: blockTradingRewards.data, + data: + blockTradingRewards.data != null + ? isParentSubaccountBlockRewardResponse(blockTradingRewards.data) + : blockTradingRewards.data, error: blockTradingRewards.error, }) ); diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index a7fa3e417..bfbf4dcab 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -1,3 +1,5 @@ +import { isParentSubaccountFillResponse } from '@/types/indexer/indexerChecks'; + import { type RootStore } from '@/state/_store'; import { setAccountFillsRaw } from '@/state/raw'; @@ -27,7 +29,7 @@ export function setUpFillsQuery(store: RootStore) { store.dispatch( setAccountFillsRaw({ status: fills.status, - data: fills.data, + data: fills.data != null ? isParentSubaccountFillResponse(fills.data) : fills.data, error: fills.error, }) ); diff --git a/src/abacus-ts/rest/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/indexerQueryStoreEffect.ts index 7ac8cf350..640ef2bc1 100644 --- a/src/abacus-ts/rest/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/indexerQueryStoreEffect.ts @@ -11,12 +11,7 @@ import { createStoreEffect } from '../createStoreEffect'; import { selectIndexerUrl, selectWebsocketUrl } from '../socketSelectors'; import { IndexerClientManager } from './indexerClientManager'; -type QuerySetupConfig = { - selector: (state: RootState) => T; - getQueryKey: (selectorResult: NoInfer) => any[]; - getQueryFn: (client: IndexerClient, selectorResult: NoInfer) => (() => Promise) | null; - onResult: (result: NoInfer>) => void; -} & Pick< +type PassedQueryOptions = Pick< QueryObserverOptions, | 'staleTime' | 'gcTime' @@ -27,8 +22,16 @@ type QuerySetupConfig = { | 'refetchOnMount' >; -const baseOptions = { +type QuerySetupConfig = { + selector: (state: RootState) => T; + getQueryKey: (selectorResult: NoInfer) => any[]; + getQueryFn: (client: IndexerClient, selectorResult: NoInfer) => (() => Promise) | null; + onResult: (result: NoInfer>) => void; +} & PassedQueryOptions; + +const baseOptions: PassedQueryOptions = { refetchInterval: timeUnits.minute, + staleTime: timeUnits.second * 30, }; export function createIndexerQueryStoreEffect( @@ -70,7 +73,16 @@ export function createIndexerQueryStoreEffect( }); const unsubscribe = observer.subscribe((result) => { - config.onResult(result); + try { + config.onResult(result); + } catch (e) { + // eslint-disable-next-line no-console + console.error( + 'IndexerQueryStoreEffect: Error handling result from react query store effect', + e, + result + ); + } }); return () => { diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index 1c0552123..39cee1877 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -1,3 +1,4 @@ +import { isParentSubaccountOrders } from '@/types/indexer/indexerChecks'; import { keyBy } from 'lodash'; import { type RootStore } from '@/state/_store'; @@ -40,7 +41,10 @@ export function setUpOrdersQuery(store: RootStore) { store.dispatch( setAccountOrdersRaw({ status: orders.status, - data: orders.data != null ? keyBy(orders.data, (o) => o.id ?? '') : orders.data, + data: + orders.data != null + ? keyBy(isParentSubaccountOrders(orders.data), (o) => o.id ?? '') + : orders.data, error: orders.error, }) ); diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts index 25fc3e875..c77511712 100644 --- a/src/abacus-ts/rest/transfers.ts +++ b/src/abacus-ts/rest/transfers.ts @@ -1,3 +1,5 @@ +import { isParentSubaccountTransferResponse } from '@/types/indexer/indexerChecks'; + import { type RootStore } from '@/state/_store'; import { setAccountTransfersRaw } from '@/state/raw'; @@ -28,7 +30,10 @@ export function setUpTransfersQuery(store: RootStore) { store.dispatch( setAccountTransfersRaw({ status: transfers.status, - data: transfers.data, + data: + transfers.data != null + ? isParentSubaccountTransferResponse(transfers.data) + : transfers.data, error: transfers.error, }) ); diff --git a/src/abacus-ts/websocket/indexerWebsocket.ts b/src/abacus-ts/websocket/indexerWebsocket.ts index 5879df9a8..955e80f54 100644 --- a/src/abacus-ts/websocket/indexerWebsocket.ts +++ b/src/abacus-ts/websocket/indexerWebsocket.ts @@ -1,3 +1,5 @@ +import typia from 'typia'; + import { assertNever } from '@/lib/assertNever'; import { isTruthy } from '@/lib/isTruthy'; @@ -92,51 +94,57 @@ export class IndexerWebsocket { }; } - private _handleMessage = (message: IndexerWebsocketMessageType) => { - if (message.type === 'error') { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered server side error:', message.message); - } else if (message.type === 'connected') { - // do nothing - } else if ( - message.type === 'subscribed' || - message.type === 'channel_batch_data' || - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - message.type === 'channel_data' - ) { - const channel = message.channel; - const id = message.id; - if (this.subscriptions[channel] == null) { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered message with unknown target', channel, id); - return; - } - if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { + private _handleMessage = (messagePre: any) => { + try { + const message = isWsMessage(messagePre); + if (message.type === 'error') { // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered message with unknown target', channel, id); - return; - } - if (message.type === 'subscribed') { - this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleBaseData( - message.contents, - message - ); - } else if (message.type === 'channel_data') { - this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( - [message.contents], - message - ); + console.error('IndexerWebsocket encountered server side error:', message.message); + } else if (message.type === 'connected') { + // do nothing + } else if ( + message.type === 'subscribed' || + message.type === 'channel_batch_data' || // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - } else if (message.type === 'channel_batch_data') { - this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( - message.contents, - message - ); + message.type === 'channel_data' + ) { + const channel = message.channel; + const id = message.id; + if (this.subscriptions[channel] == null) { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket encountered message with unknown target', channel, id); + return; + } + if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket encountered message with unknown target', channel, id); + return; + } + if (message.type === 'subscribed') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleBaseData( + message.contents, + message + ); + } else if (message.type === 'channel_data') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( + [message.contents], + message + ); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if (message.type === 'channel_batch_data') { + this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID]!.handleUpdates( + message.contents, + message + ); + } else { + assertNever(message); + } } else { assertNever(message); } - } else { - assertNever(message); + } catch (e) { + // eslint-disable-next-line no-console + console.error('IndexerWebsocket: Error handling websocket message', message, e); } }; @@ -173,6 +181,7 @@ type IndexerWebsocketMessageType = channel: string; id: string | undefined; version: string; + subaccountNumber?: number; contents: any[]; } | { @@ -180,6 +189,9 @@ type IndexerWebsocketMessageType = channel: string; id: string | undefined; version: string; + subaccountNumber?: number; contents: any; } | { type: 'subscribed'; channel: string; id: string | undefined; contents: any }; + +export const isWsMessage = typia.createAssert(); diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index 1c6ad9d46..cf238b05e 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -1,5 +1,7 @@ -import { IndexerPerpetualMarketResponse } from '@/types/indexer/indexerApiGen'; -import { IndexerWsMarketUpdateResponse } from '@/types/indexer/indexerManual'; +import { + isWsMarketUpdateResponses, + isWsPerpetualMarketResponse, +} from '@/types/indexer/indexerChecks'; import { throttle } from 'lodash'; import { timeUnits } from '@/constants/time'; @@ -25,11 +27,11 @@ function marketsWebsocketValue( channel: 'v4_markets', id: undefined, handleBaseData: (baseMessage) => { - const message = baseMessage as IndexerPerpetualMarketResponse; + const message = isWsPerpetualMarketResponse(baseMessage); return loadableLoaded(message.markets); }, handleUpdates: (baseUpdates, value) => { - const updates = baseUpdates as IndexerWsMarketUpdateResponse[]; + const updates = isWsMarketUpdateResponses(baseUpdates); let startingValue = value.data; if (startingValue == null) { // eslint-disable-next-line no-console diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index 85006336c..a709209c7 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -1,5 +1,4 @@ -import { IndexerOrderbookResponseObject } from '@/types/indexer/indexerApiGen'; -import { IndexerWsOrderbookUpdateResponse } from '@/types/indexer/indexerManual'; +import { isWsOrderbookResponse, isWsOrderbookUpdateResponses } from '@/types/indexer/indexerChecks'; import { keyBy, mapValues } from 'lodash'; import { Loadable, loadableLoaded, loadablePending } from '../loadable'; @@ -20,7 +19,7 @@ function orderbookWebsocketValue( channel: 'v4_orderbook', id: marketId, handleBaseData: (baseMessage) => { - const message = baseMessage as IndexerOrderbookResponseObject; + const message = isWsOrderbookResponse(baseMessage); return loadableLoaded({ asks: mapValues( keyBy(message.asks, (a) => a.price), @@ -33,7 +32,7 @@ function orderbookWebsocketValue( }); }, handleUpdates: (baseUpdates, value) => { - const updates = baseUpdates as IndexerWsOrderbookUpdateResponse[]; + const updates = isWsOrderbookUpdateResponses(baseUpdates); let startingValue = value.data; if (startingValue == null) { // eslint-disable-next-line no-console diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 796df4f2c..645afb972 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -1,8 +1,8 @@ import { IndexerSubaccountResponseObject } from '@/types/indexer/indexerApiGen'; import { - IndexerWsParentSubaccountSubscribedResponse, - IndexerWsParentSubaccountUpdateObject, -} from '@/types/indexer/indexerManual'; + isWsParentSubaccountSubscribed, + isWsParentSubaccountUpdates, +} from '@/types/indexer/indexerChecks'; import { keyBy } from 'lodash'; import { type RootStore } from '@/state/_store'; @@ -68,7 +68,7 @@ function accountWebsocketValue( channel: 'v4_parent_subaccounts', id: `${address}/${subaccount}`, handleBaseData: (baseMessage) => { - const message = baseMessage as IndexerWsParentSubaccountSubscribedResponse; + const message = isWsParentSubaccountSubscribed(baseMessage); accountRefreshSignal.notify(); return loadableLoaded({ @@ -86,7 +86,7 @@ function accountWebsocketValue( }); }, handleUpdates: (baseUpdates, value, fullMessage) => { - const updates = baseUpdates as IndexerWsParentSubaccountUpdateObject[]; + const updates = isWsParentSubaccountUpdates(baseUpdates); const subaccountNumber = fullMessage?.subaccountNumber as number | undefined; if (value.data == null || updates.length === 0 || subaccountNumber == null) { return value; diff --git a/src/types/indexer/indexerApiGen.ts b/src/types/indexer/indexerApiGen.ts index 01db031a0..4a4af9ee4 100644 --- a/src/types/indexer/indexerApiGen.ts +++ b/src/types/indexer/indexerApiGen.ts @@ -363,13 +363,13 @@ export interface IndexerCandleResponseObject { * @type {string} * @memberof CandleResponseObject */ - orderbookMidPriceOpen?: string; + orderbookMidPriceOpen?: string | null; /** * * @type {string} * @memberof CandleResponseObject */ - orderbookMidPriceClose?: string; + orderbookMidPriceClose?: string | null; /** * * @type {string} @@ -407,7 +407,7 @@ export interface IndexerComplianceResponse { * @type {string} * @memberof ComplianceResponse */ - reason?: string; + reason?: string | null; } /** * @@ -438,13 +438,13 @@ export interface IndexerComplianceV2Response { * @type {IndexerComplianceReason} * @memberof ComplianceV2Response */ - reason?: IndexerComplianceReason; + reason?: IndexerComplianceReason | null; /** * * @type {string} * @memberof ComplianceV2Response */ - updatedAt?: string; + updatedAt?: string | null; } /** * @@ -457,19 +457,19 @@ export interface IndexerFillResponse { * @type {number} * @memberof FillResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof FillResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof FillResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -560,13 +560,13 @@ export interface IndexerFillResponseObject { * @type {string} * @memberof FillResponseObject */ - orderId?: string; + orderId?: string | null; /** * * @type {string} * @memberof FillResponseObject */ - clientMetadata?: string; + clientMetadata?: string | null; /** * * @type {number} @@ -704,19 +704,19 @@ export interface IndexerHistoricalPnlResponse { * @type {number} * @memberof HistoricalPnlResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof HistoricalPnlResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof HistoricalPnlResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -753,13 +753,13 @@ export interface IndexerHistoricalTradingRewardAggregation { * @type {IndexerIsoString} * @memberof HistoricalTradingRewardAggregation */ - endedAt?: IndexerIsoString; + endedAt?: IndexerIsoString | null; /** * * @type {string} * @memberof HistoricalTradingRewardAggregation */ - endedAtHeight?: string; + endedAtHeight?: string | null; /** * * @type {IndexerTradingRewardAggregationPeriod} @@ -906,19 +906,19 @@ export interface IndexerOrderResponseObject { * @type {string} * @memberof OrderResponseObject */ - goodTilBlock?: string; + goodTilBlock?: string | null; /** * * @type {string} * @memberof OrderResponseObject */ - goodTilBlockTime?: string; + goodTilBlockTime?: string | null; /** * * @type {string} * @memberof OrderResponseObject */ - createdAtHeight?: string; + createdAtHeight?: string | null; /** * * @type {string} @@ -930,7 +930,7 @@ export interface IndexerOrderResponseObject { * @type {string} * @memberof OrderResponseObject */ - triggerPrice?: string; + triggerPrice?: string | null; /** * * @type {IndexerAPITimeInForce} @@ -960,13 +960,13 @@ export interface IndexerOrderResponseObject { * @type {IndexerIsoString} * @memberof OrderResponseObject */ - updatedAt?: IndexerIsoString; + updatedAt?: IndexerIsoString | null; /** * * @type {string} * @memberof OrderResponseObject */ - updatedAtHeight?: string; + updatedAtHeight?: string | null; /** * * @type {number} @@ -1095,19 +1095,19 @@ export interface IndexerParentSubaccountTransferResponse { * @type {number} * @memberof ParentSubaccountTransferResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof ParentSubaccountTransferResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof ParentSubaccountTransferResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -1247,13 +1247,13 @@ export interface IndexerPerpetualMarketResponseObject { * @type {string} * @memberof PerpetualMarketResponseObject */ - openInterestLowerCap?: string; + openInterestLowerCap?: string | null; /** * * @type {string} * @memberof PerpetualMarketResponseObject */ - openInterestUpperCap?: string; + openInterestUpperCap?: string | null; /** * * @type {string} @@ -1385,13 +1385,13 @@ export interface IndexerPerpetualPositionResponseObject { * @type {IndexerIsoString} * @memberof PerpetualPositionResponseObject */ - closedAt?: IndexerIsoString; + closedAt?: IndexerIsoString | null; /** * * @type {string} * @memberof PerpetualPositionResponseObject */ - exitPrice?: string; + exitPrice?: string | null; /** * * @type {number} @@ -1582,19 +1582,19 @@ export interface IndexerTradeResponse { * @type {number} * @memberof TradeResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof TradeResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof TradeResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -1672,7 +1672,7 @@ export interface IndexerTraderSearchResponse { * @type {IndexerTraderSearchResponseObject} * @memberof TraderSearchResponse */ - result?: IndexerTraderSearchResponseObject; + result?: IndexerTraderSearchResponseObject | null; } /** * @@ -1726,19 +1726,19 @@ export interface IndexerTransferBetweenResponse { * @type {number} * @memberof TransferBetweenResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof TransferBetweenResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof TransferBetweenResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -1763,19 +1763,19 @@ export interface IndexerTransferResponse { * @type {number} * @memberof TransferResponse */ - pageSize?: number; + pageSize?: number | null; /** * * @type {number} * @memberof TransferResponse */ - totalResults?: number; + totalResults?: number | null; /** * * @type {number} * @memberof TransferResponse */ - offset?: number; + offset?: number | null; /** * * @type {Array} @@ -1855,7 +1855,7 @@ export interface IndexerTransferResponseObjectSender { * @type {number} * @memberof TransferResponseObjectSender */ - subaccountNumber?: number; + subaccountNumber?: number | null; /** * * @type {string} @@ -1916,7 +1916,7 @@ export interface IndexerVaultPosition { * @type {IndexerPerpetualPositionResponseObject} * @memberof VaultPosition */ - perpetualPosition?: IndexerPerpetualPositionResponseObject; + perpetualPosition?: IndexerPerpetualPositionResponseObject | null; /** * * @type {string} diff --git a/src/types/indexer/indexerChecks.ts b/src/types/indexer/indexerChecks.ts new file mode 100644 index 000000000..e3c3805ee --- /dev/null +++ b/src/types/indexer/indexerChecks.ts @@ -0,0 +1,32 @@ +import typia from 'typia'; + +import { + IndexerHistoricalBlockTradingRewardsResponse, + IndexerOrderbookResponseObject, + IndexerParentSubaccountTransferResponse, + IndexerPerpetualMarketResponse, +} from './indexerApiGen'; +import { + IndexerCompositeFillResponse, + IndexerCompositeOrderObject, + IndexerWsMarketUpdateResponse, + IndexerWsOrderbookUpdateResponse, + IndexerWsParentSubaccountSubscribedResponse, + IndexerWsParentSubaccountUpdateObject, +} from './indexerManual'; + +export const isWsParentSubaccountSubscribed = + typia.createAssert(); +export const isWsParentSubaccountUpdates = + typia.createAssert(); +export const isWsPerpetualMarketResponse = typia.createAssert(); +export const isWsMarketUpdateResponses = typia.createAssert(); +export const isWsOrderbookResponse = typia.createAssert(); +export const isWsOrderbookUpdateResponses = + typia.createAssert(); +export const isParentSubaccountFillResponse = typia.createAssert(); +export const isParentSubaccountOrders = typia.createAssert(); +export const isParentSubaccountTransferResponse = + typia.createAssert(); +export const isParentSubaccountBlockRewardResponse = + typia.createAssert(); diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 633e18e98..5592f2f50 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -36,17 +36,17 @@ export interface IndexerCompositeOrderObject { type?: IndexerOrderType; reduceOnly?: boolean; orderFlags?: string; - goodTilBlock?: string; - goodTilBlockTime?: string; - createdAtHeight?: string; + goodTilBlock?: string | null; + goodTilBlockTime?: string | null; + createdAtHeight?: string | null; clientMetadata?: string; - triggerPrice?: string; + triggerPrice?: string | null; timeInForce?: IndexerAPITimeInForce; status?: IndexerAPIOrderStatus; postOnly?: boolean; ticker?: string; - updatedAt?: IndexerIsoString; - updatedAtHeight?: string; + updatedAt?: IndexerIsoString | null; + updatedAtHeight?: string | null; subaccountNumber?: number; removalReason?: string; totalOptimisticFilled?: string; @@ -116,8 +116,8 @@ export interface IndexerCompositeFillObject { affiliateRevShare?: string; createdAt?: IndexerIsoString; createdAtHeight?: string; - orderId?: string; - clientMetadata?: string; + orderId?: string | null; + clientMetadata?: string | null; subaccountNumber?: number; ticker?: string; } diff --git a/tsconfig.json b/tsconfig.json index 6efb2030c..0d8d4404e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,11 @@ "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], + "lib": [ + "DOM", + "DOM.Iterable", + "ESNext" + ], "allowJs": false, "skipLibCheck": true, "esModuleInterop": false, @@ -20,10 +24,33 @@ "useUnknownInCatchVariables": false, "noUncheckedIndexedAccess": true, "paths": { - "@/*": ["src/*"] + "@/*": [ + "src/*" + ] }, - "types": ["node", "@wdio/globals", "mocha"] + "types": [ + "node", + "@wdio/globals", + "mocha" + ], + "plugins": [ + { + "transform": "typia/lib/transform" + } + ], + "strictNullChecks": true }, - "include": ["src", "scripts", "styled.d.ts", "__tests__", "wdio.conf.ts", "types"], - "references": [{ "path": "./tsconfig.node.json" }] -} + "include": [ + "src", + "scripts", + "styled.d.ts", + "__tests__", + "wdio.conf.ts", + "types" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 6d29f9b77..057ab9a23 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,3 +1,4 @@ +import UnpluginTypia from '@ryoppippi/unplugin-typia/vite'; import react from '@vitejs/plugin-react'; import fs from 'fs'; import path from 'path'; @@ -52,6 +53,8 @@ export default defineConfig(({ mode }) => ({ }, plugins: [ nodePolyfills(), + UnpluginTypia({}), + react({ babel: { plugins: [ From 1c516a3c8215b37b680cac7926ad3f60bdd90f72 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 9 Dec 2024 15:59:45 -0500 Subject: [PATCH 18/65] fixes --- src/abacus-ts/websocket/indexerWebsocket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abacus-ts/websocket/indexerWebsocket.ts b/src/abacus-ts/websocket/indexerWebsocket.ts index 955e80f54..e575444a3 100644 --- a/src/abacus-ts/websocket/indexerWebsocket.ts +++ b/src/abacus-ts/websocket/indexerWebsocket.ts @@ -144,7 +144,7 @@ export class IndexerWebsocket { } } catch (e) { // eslint-disable-next-line no-console - console.error('IndexerWebsocket: Error handling websocket message', message, e); + console.error('IndexerWebsocket: Error handling websocket message', messagePre, e); } }; From f0cfc7adb22b1374519a19b3538439e8e6b26d81 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 9 Dec 2024 16:23:55 -0500 Subject: [PATCH 19/65] fix --- src/abacus-ts/rest/blockTradingRewards.ts | 4 +- src/abacus-ts/rest/fills.ts | 4 +- src/abacus-ts/rest/orders.ts | 4 +- src/abacus-ts/rest/transfers.ts | 4 +- src/abacus-ts/storeLifecycles.ts | 2 + src/abacus-ts/websocket/orderbook.ts | 52 ++++++++++++++++----- src/abacus-ts/websocket/parentSubaccount.ts | 4 +- src/state/raw.ts | 12 ++++- 8 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/abacus-ts/rest/blockTradingRewards.ts b/src/abacus-ts/rest/blockTradingRewards.ts index d9fba5241..b90d90f86 100644 --- a/src/abacus-ts/rest/blockTradingRewards.ts +++ b/src/abacus-ts/rest/blockTradingRewards.ts @@ -21,9 +21,6 @@ export function setUpBlockTradingRewardsQuery(store: RootStore) { getQueryKey: (data) => ['account', 'blockTradingRewards', data], getQueryFn: (indexerClient, data) => { if (!isTruthy(data.wallet) || data.subaccount == null) { - if (store.getState().raw.account.blockTradingRewards.data != null) { - store.dispatch(setAccountBlockTradingRewardsRaw(loadableIdle())); - } return null; } return () => indexerClient.account.getHistoricalBlockTradingRewards(data.wallet!); @@ -45,5 +42,6 @@ export function setUpBlockTradingRewardsQuery(store: RootStore) { return () => { cleanupListener(); cleanupEffect(); + store.dispatch(setAccountBlockTradingRewardsRaw(loadableIdle())); }; } diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index bfbf4dcab..542fd2e06 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -17,9 +17,6 @@ export function setUpFillsQuery(store: RootStore) { getQueryKey: (data) => ['account', 'fills', data.wallet, data.subaccount], getQueryFn: (indexerClient, data) => { if (!isTruthy(data.wallet) || data.subaccount == null) { - if (store.getState().raw.account.fills.data != null) { - store.dispatch(setAccountFillsRaw(loadableIdle())); - } return null; } return () => @@ -38,5 +35,6 @@ export function setUpFillsQuery(store: RootStore) { return () => { cleanupListener(); cleanupEffect(); + store.dispatch(setAccountFillsRaw(loadableIdle())); }; } diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index 39cee1877..de1e72d51 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -18,9 +18,6 @@ export function setUpOrdersQuery(store: RootStore) { getQueryKey: (data) => ['account', 'orders', data.wallet, data.subaccount], getQueryFn: (indexerClient, data) => { if (!isTruthy(data.wallet) || data.subaccount == null) { - if (store.getState().raw.account.orders.data != null) { - store.dispatch(setAccountOrdersRaw(loadableIdle())); - } return null; } return () => @@ -53,5 +50,6 @@ export function setUpOrdersQuery(store: RootStore) { return () => { cleanupListener(); cleanupEffect(); + store.dispatch(setAccountOrdersRaw(loadableIdle())); }; } diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts index c77511712..5f4f5d272 100644 --- a/src/abacus-ts/rest/transfers.ts +++ b/src/abacus-ts/rest/transfers.ts @@ -18,9 +18,6 @@ export function setUpTransfersQuery(store: RootStore) { getQueryKey: (data) => ['account', 'transfers', data], getQueryFn: (indexerClient, data) => { if (!isTruthy(data.wallet) || data.subaccount == null) { - if (store.getState().raw.account.transfers.data != null) { - store.dispatch(setAccountTransfersRaw(loadableIdle())); - } return null; } return () => @@ -43,5 +40,6 @@ export function setUpTransfersQuery(store: RootStore) { return () => { cleanupListener(); cleanupEffect(); + store.dispatch(setAccountTransfersRaw(loadableIdle())); }; } diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index 78fc5bbe3..92e86673b 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -3,6 +3,7 @@ import { setUpFillsQuery } from './rest/fills'; import { setUpOrdersQuery } from './rest/orders'; import { setUpTransfersQuery } from './rest/transfers'; import { setUpMarkets } from './websocket/markets'; +import { setUpOrderbook } from './websocket/orderbook'; import { setUpParentSubaccount } from './websocket/parentSubaccount'; export const storeLifecycles = [ @@ -12,4 +13,5 @@ export const storeLifecycles = [ setUpOrdersQuery, setUpTransfersQuery, setUpBlockTradingRewardsQuery, + setUpOrderbook, ] as const; diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index a709209c7..c3712774c 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -1,8 +1,17 @@ import { isWsOrderbookResponse, isWsOrderbookUpdateResponses } from '@/types/indexer/indexerChecks'; -import { keyBy, mapValues } from 'lodash'; +import { keyBy, mapValues, throttle } from 'lodash'; -import { Loadable, loadableLoaded, loadablePending } from '../loadable'; -import { ResourceCacheManager } from '../resourceCacheManager'; +import { timeUnits } from '@/constants/time'; + +import { type RootStore } from '@/state/_store'; +import { createAppSelector } from '@/state/appTypes'; +import { setOrderbookRaw } from '@/state/raw'; + +import { isTruthy } from '@/lib/isTruthy'; + +import { createStoreEffect } from '../createStoreEffect'; +import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../loadable'; +import { selectWebsocketUrl } from '../socketSelectors'; import { OrderbookData } from '../types'; import { IndexerWebsocket } from './indexerWebsocket'; import { IndexerWebsocketManager } from './indexerWebsocketManager'; @@ -56,11 +65,32 @@ function orderbookWebsocketValue( ); } -// todo simplify api to just take market id -// needs to allow adding/removing callbacks too -export const OrderbooksManager = new ResourceCacheManager({ - constructor: ({ wsUrl, marketId }: { wsUrl: string; marketId: string }) => - orderbookWebsocketValue(IndexerWebsocketManager.use(wsUrl), marketId, () => null), - destroyer: (obj) => obj.teardown(), - keySerializer: ({ marketId, wsUrl }) => `${wsUrl}//////\\\\\\${marketId}`, -}); +const selectMarketAndWsInfo = createAppSelector( + selectWebsocketUrl, + (state) => state.perpetuals.currentMarketId, + (wsUrl, currentMarketId) => ({ wsUrl, currentMarketId }) +); + +export function setUpOrderbook(store: RootStore) { + return createStoreEffect(store, selectMarketAndWsInfo, ({ currentMarketId, wsUrl }) => { + if (!isTruthy(currentMarketId)) { + return undefined; + } + const throttledSetOrderbook = throttle((data: Loadable) => { + store.dispatch(setOrderbookRaw({ marketId: currentMarketId, data })); + }, timeUnits.second / 2); + + const thisTracker = orderbookWebsocketValue( + IndexerWebsocketManager.use(wsUrl), + currentMarketId, + (data) => throttledSetOrderbook(data) + ); + + return () => { + thisTracker.teardown(); + IndexerWebsocketManager.markDone(wsUrl); + throttledSetOrderbook.cancel(); + store.dispatch(setOrderbookRaw({ marketId: currentMarketId, data: loadableIdle() })); + }; + }); +} diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 645afb972..174502e17 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -174,9 +174,6 @@ const selectParentSubaccount = createAppSelector( export function setUpParentSubaccount(store: RootStore) { return createStoreEffect(store, selectParentSubaccount, ({ subaccount, wallet, wsUrl }) => { if (!isTruthy(wallet) || subaccount == null) { - if (store.getState().raw.account.parentSubaccount.data != null) { - store.dispatch(setParentSubaccountRaw(loadableIdle())); - } return undefined; } const thisTracker = accountWebsocketValue( @@ -189,6 +186,7 @@ export function setUpParentSubaccount(store: RootStore) { return () => { thisTracker.teardown(); IndexerWebsocketManager.markDone(wsUrl); + store.dispatch(setParentSubaccountRaw(loadableIdle())); }; }); } diff --git a/src/state/raw.ts b/src/state/raw.ts index 211ee693b..0b3a3d16e 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,5 +1,5 @@ import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; -import { MarketsData, ParentSubaccountData } from '@/abacus-ts/types'; +import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/types'; import { IndexerHistoricalBlockTradingRewardsResponse, IndexerParentSubaccountTransferResponse, @@ -13,6 +13,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; export interface RawDataState { markets: { allMarkets: Loadable; + orderbooks: { [marketId: string]: Loadable }; }; account: { parentSubaccount: Loadable; @@ -24,7 +25,7 @@ export interface RawDataState { } const initialState: RawDataState = { - markets: { allMarkets: loadableIdle() }, + markets: { allMarkets: loadableIdle(), orderbooks: {} }, account: { parentSubaccount: loadableIdle(), fills: loadableIdle(), @@ -41,6 +42,12 @@ export const rawSlice = createSlice({ setAllMarketsRaw: (state, action: PayloadAction>) => { state.markets.allMarkets = action.payload; }, + setOrderbookRaw: ( + state, + action: PayloadAction<{ marketId: string; data: Loadable }> + ) => { + state.markets.orderbooks[action.payload.marketId] = action.payload.data; + }, setParentSubaccountRaw: (state, action: PayloadAction>) => { state.account.parentSubaccount = action.payload; }, @@ -69,6 +76,7 @@ export const rawSlice = createSlice({ }); export const { + setOrderbookRaw, setAllMarketsRaw, setParentSubaccountRaw, setAccountFillsRaw, From 0198c5902d92476f25575ef272e60085356ab3fe Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:31:32 -0500 Subject: [PATCH 20/65] move files around, fix logging --- src/abacus-ts/accountRefreshSignal.ts | 3 +- src/abacus-ts/{ => lib}/createStoreEffect.ts | 0 src/abacus-ts/{ => lib}/loadable.ts | 0 .../{ => lib}/resourceCacheManager.ts | 0 src/abacus-ts/{ => lib}/signal.ts | 0 src/abacus-ts/logs.ts | 5 ++++ src/abacus-ts/rest/blockTradingRewards.ts | 4 +-- src/abacus-ts/rest/fills.ts | 4 +-- .../rest/{ => lib}/indexerClientManager.ts | 2 +- .../rest/{ => lib}/indexerQueryStoreEffect.ts | 11 +++---- src/abacus-ts/rest/orders.ts | 4 +-- src/abacus-ts/rest/transfers.ts | 4 +-- .../websocket/{ => lib}/indexerWebsocket.ts | 30 ++++++++++++------- .../{ => lib}/indexerWebsocketManager.ts | 2 +- .../{ => lib}/reconnectingWebsocket.ts | 17 ++++++----- .../{ => lib}/websocketDerivedValue.ts | 0 src/abacus-ts/websocket/markets.ts | 10 +++---- src/abacus-ts/websocket/orderbook.ts | 10 +++---- src/abacus-ts/websocket/parentSubaccount.ts | 10 +++---- src/constants/analytics.ts | 2 +- src/lib/telemetry.ts | 2 +- src/state/raw.ts | 2 +- 22 files changed, 70 insertions(+), 52 deletions(-) rename src/abacus-ts/{ => lib}/createStoreEffect.ts (100%) rename src/abacus-ts/{ => lib}/loadable.ts (100%) rename src/abacus-ts/{ => lib}/resourceCacheManager.ts (100%) rename src/abacus-ts/{ => lib}/signal.ts (100%) create mode 100644 src/abacus-ts/logs.ts rename src/abacus-ts/rest/{ => lib}/indexerClientManager.ts (83%) rename src/abacus-ts/rest/{ => lib}/indexerQueryStoreEffect.ts (88%) rename src/abacus-ts/websocket/{ => lib}/indexerWebsocket.ts (87%) rename src/abacus-ts/websocket/{ => lib}/indexerWebsocketManager.ts (78%) rename src/abacus-ts/websocket/{ => lib}/reconnectingWebsocket.ts (88%) rename src/abacus-ts/websocket/{ => lib}/websocketDerivedValue.ts (100%) diff --git a/src/abacus-ts/accountRefreshSignal.ts b/src/abacus-ts/accountRefreshSignal.ts index fc503f600..f7497f1e1 100644 --- a/src/abacus-ts/accountRefreshSignal.ts +++ b/src/abacus-ts/accountRefreshSignal.ts @@ -4,13 +4,14 @@ import { timeUnits } from '@/constants/time'; import { appQueryClient } from '@/state/appQueryClient'; -import { Signal } from './signal'; +import { Signal } from './lib/signal'; // triggers when we got fresh parent subaccount data from the websocket for any reason // mostly network reconnects, refreshes, page visibility changes, etc export const accountRefreshSignal = new Signal(); const BUFFER_REFRESH_TIME = timeUnits.second * 5; + export function refreshIndexerQueryOnAccountSocketRefresh(key: any[]) { return accountRefreshSignal.onTrigger(() => { // we don't refresh if all data was updated within the last few seconds diff --git a/src/abacus-ts/createStoreEffect.ts b/src/abacus-ts/lib/createStoreEffect.ts similarity index 100% rename from src/abacus-ts/createStoreEffect.ts rename to src/abacus-ts/lib/createStoreEffect.ts diff --git a/src/abacus-ts/loadable.ts b/src/abacus-ts/lib/loadable.ts similarity index 100% rename from src/abacus-ts/loadable.ts rename to src/abacus-ts/lib/loadable.ts diff --git a/src/abacus-ts/resourceCacheManager.ts b/src/abacus-ts/lib/resourceCacheManager.ts similarity index 100% rename from src/abacus-ts/resourceCacheManager.ts rename to src/abacus-ts/lib/resourceCacheManager.ts diff --git a/src/abacus-ts/signal.ts b/src/abacus-ts/lib/signal.ts similarity index 100% rename from src/abacus-ts/signal.ts rename to src/abacus-ts/lib/signal.ts diff --git a/src/abacus-ts/logs.ts b/src/abacus-ts/logs.ts new file mode 100644 index 000000000..7fe963e67 --- /dev/null +++ b/src/abacus-ts/logs.ts @@ -0,0 +1,5 @@ +import { log } from '@/lib/telemetry'; + +export function logAbacusTsError(source: string, message: string, ...args: any[]) { + log(`${source}: ${message}`, undefined, { context: args }); +} diff --git a/src/abacus-ts/rest/blockTradingRewards.ts b/src/abacus-ts/rest/blockTradingRewards.ts index b90d90f86..0f80a3147 100644 --- a/src/abacus-ts/rest/blockTradingRewards.ts +++ b/src/abacus-ts/rest/blockTradingRewards.ts @@ -6,9 +6,9 @@ import { setAccountBlockTradingRewardsRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; -import { loadableIdle } from '../loadable'; +import { loadableIdle } from '../lib/loadable'; import { selectParentSubaccountInfo } from '../socketSelectors'; -import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; +import { createIndexerQueryStoreEffect } from './lib/indexerQueryStoreEffect'; export function setUpBlockTradingRewardsQuery(store: RootStore) { const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh([ diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index 542fd2e06..d4e401188 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -6,9 +6,9 @@ import { setAccountFillsRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; -import { loadableIdle } from '../loadable'; +import { loadableIdle } from '../lib/loadable'; import { selectParentSubaccountInfo } from '../socketSelectors'; -import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; +import { createIndexerQueryStoreEffect } from './lib/indexerQueryStoreEffect'; export function setUpFillsQuery(store: RootStore) { const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'fills']); diff --git a/src/abacus-ts/rest/indexerClientManager.ts b/src/abacus-ts/rest/lib/indexerClientManager.ts similarity index 83% rename from src/abacus-ts/rest/indexerClientManager.ts rename to src/abacus-ts/rest/lib/indexerClientManager.ts index c868a1a04..a0bd54fde 100644 --- a/src/abacus-ts/rest/indexerClientManager.ts +++ b/src/abacus-ts/rest/lib/indexerClientManager.ts @@ -1,6 +1,6 @@ import { IndexerClient, IndexerConfig } from '@dydxprotocol/v4-client-js'; -import { ResourceCacheManager } from '../resourceCacheManager'; +import { ResourceCacheManager } from '../../lib/resourceCacheManager'; export const IndexerClientManager = new ResourceCacheManager({ constructor: ({ wsUrl, url }: { url: string; wsUrl: string }) => diff --git a/src/abacus-ts/rest/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts similarity index 88% rename from src/abacus-ts/rest/indexerQueryStoreEffect.ts rename to src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts index 640ef2bc1..ed6e708d7 100644 --- a/src/abacus-ts/rest/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts @@ -1,3 +1,4 @@ +import { logAbacusTsError } from '@/abacus-ts/logs'; import { IndexerClient } from '@dydxprotocol/v4-client-js'; import { QueryObserver, QueryObserverOptions, QueryObserverResult } from '@tanstack/react-query'; @@ -7,8 +8,8 @@ import { type RootState, type RootStore } from '@/state/_store'; import { appQueryClient } from '@/state/appQueryClient'; import { createAppSelector } from '@/state/appTypes'; -import { createStoreEffect } from '../createStoreEffect'; -import { selectIndexerUrl, selectWebsocketUrl } from '../socketSelectors'; +import { createStoreEffect } from '../../lib/createStoreEffect'; +import { selectIndexerUrl, selectWebsocketUrl } from '../../socketSelectors'; import { IndexerClientManager } from './indexerClientManager'; type PassedQueryOptions = Pick< @@ -76,9 +77,9 @@ export function createIndexerQueryStoreEffect( try { config.onResult(result); } catch (e) { - // eslint-disable-next-line no-console - console.error( - 'IndexerQueryStoreEffect: Error handling result from react query store effect', + logAbacusTsError( + 'IndexerQueryStoreEffect', + 'Error handling result from react query store effect', e, result ); diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index de1e72d51..4f5699c8e 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -7,9 +7,9 @@ import { setAccountOrdersRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; -import { loadableIdle } from '../loadable'; +import { loadableIdle } from '../lib/loadable'; import { selectParentSubaccountInfo } from '../socketSelectors'; -import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; +import { createIndexerQueryStoreEffect } from './lib/indexerQueryStoreEffect'; export function setUpOrdersQuery(store: RootStore) { const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'orders']); diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts index 5f4f5d272..fa68dc553 100644 --- a/src/abacus-ts/rest/transfers.ts +++ b/src/abacus-ts/rest/transfers.ts @@ -6,9 +6,9 @@ import { setAccountTransfersRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { refreshIndexerQueryOnAccountSocketRefresh } from '../accountRefreshSignal'; -import { loadableIdle } from '../loadable'; +import { loadableIdle } from '../lib/loadable'; import { selectParentSubaccountInfo } from '../socketSelectors'; -import { createIndexerQueryStoreEffect } from './indexerQueryStoreEffect'; +import { createIndexerQueryStoreEffect } from './lib/indexerQueryStoreEffect'; export function setUpTransfersQuery(store: RootStore) { const cleanupListener = refreshIndexerQueryOnAccountSocketRefresh(['account', 'transfers']); diff --git a/src/abacus-ts/websocket/indexerWebsocket.ts b/src/abacus-ts/websocket/lib/indexerWebsocket.ts similarity index 87% rename from src/abacus-ts/websocket/indexerWebsocket.ts rename to src/abacus-ts/websocket/lib/indexerWebsocket.ts index e575444a3..dbce6afb2 100644 --- a/src/abacus-ts/websocket/indexerWebsocket.ts +++ b/src/abacus-ts/websocket/lib/indexerWebsocket.ts @@ -1,3 +1,4 @@ +import { logAbacusTsError } from '@/abacus-ts/logs'; import typia from 'typia'; import { assertNever } from '@/lib/assertNever'; @@ -52,6 +53,7 @@ export class IndexerWebsocket { }): () => void { this.subscriptions[channel] ??= {}; if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] != null) { + logAbacusTsError('IndexerWebsocket', 'this subscription already exists', `${channel}/${id}`); throw new Error(`IndexerWebsocket error: this subscription already exists. ${channel}/${id}`); } this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] = { @@ -98,8 +100,7 @@ export class IndexerWebsocket { try { const message = isWsMessage(messagePre); if (message.type === 'error') { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered server side error:', message.message); + logAbacusTsError('IndexerWebsocket', 'encountered server side error:', message.message); } else if (message.type === 'connected') { // do nothing } else if ( @@ -111,13 +112,21 @@ export class IndexerWebsocket { const channel = message.channel; const id = message.id; if (this.subscriptions[channel] == null) { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered message with unknown target', channel, id); + logAbacusTsError( + 'IndexerWebsocket', + 'encountered message with unknown target', + channel, + id + ); return; } if (this.subscriptions[channel][id ?? NO_ID_SPECIAL_STRING_ID] == null) { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket encountered message with unknown target', channel, id); + logAbacusTsError( + 'IndexerWebsocket', + 'encountered message with unknown target', + channel, + id + ); return; } if (message.type === 'subscribed') { @@ -143,8 +152,7 @@ export class IndexerWebsocket { assertNever(message); } } catch (e) { - // eslint-disable-next-line no-console - console.error('IndexerWebsocket: Error handling websocket message', messagePre, e); + logAbacusTsError('IndexerWebsocket', 'Error handling websocket message', messagePre, e); } }; @@ -165,9 +173,9 @@ export class IndexerWebsocket { }); }); } else { - // eslint-disable-next-line no-console - console.error( - "IndexerWebsocket error: handle fresh connect called when websocket isn't ready." + logAbacusTsError( + 'IndexerWebsocket', + "handle fresh connect called when websocket isn't ready." ); } }; diff --git a/src/abacus-ts/websocket/indexerWebsocketManager.ts b/src/abacus-ts/websocket/lib/indexerWebsocketManager.ts similarity index 78% rename from src/abacus-ts/websocket/indexerWebsocketManager.ts rename to src/abacus-ts/websocket/lib/indexerWebsocketManager.ts index 1087e6c56..dccf4d7ec 100644 --- a/src/abacus-ts/websocket/indexerWebsocketManager.ts +++ b/src/abacus-ts/websocket/lib/indexerWebsocketManager.ts @@ -1,4 +1,4 @@ -import { ResourceCacheManager } from '../resourceCacheManager'; +import { ResourceCacheManager } from '../../lib/resourceCacheManager'; import { IndexerWebsocket } from './indexerWebsocket'; export const IndexerWebsocketManager = new ResourceCacheManager({ diff --git a/src/abacus-ts/websocket/reconnectingWebsocket.ts b/src/abacus-ts/websocket/lib/reconnectingWebsocket.ts similarity index 88% rename from src/abacus-ts/websocket/reconnectingWebsocket.ts rename to src/abacus-ts/websocket/lib/reconnectingWebsocket.ts index 6056f2b86..fc3ece62e 100644 --- a/src/abacus-ts/websocket/reconnectingWebsocket.ts +++ b/src/abacus-ts/websocket/lib/reconnectingWebsocket.ts @@ -1,3 +1,5 @@ +import { logAbacusTsError } from '@/abacus-ts/logs'; + interface WebSocketConfig { url: string; handleMessage: (data: any) => void; @@ -50,8 +52,7 @@ export class ReconnectingWebSocket { const data = JSON.parse(event.data); this.handleMessage(data); } catch (e) { - // eslint-disable-next-line no-console - console.error('ReconnectingWebSocket: error in handler', e); + logAbacusTsError('ReconnectingWebSocket', 'error in handler', e); } }; @@ -61,8 +62,7 @@ export class ReconnectingWebSocket { }; this.ws.onerror = (error) => { - // eslint-disable-next-line no-console - console.error('ReconnectingWebSocket error:', error); + logAbacusTsError('ReconnectingWebSocket', 'socket error encountered', error); this.ws?.close(); }; @@ -70,12 +70,10 @@ export class ReconnectingWebSocket { this.currentReconnectInterval = this.initialReconnectInterval; // eslint-disable-next-line no-console console.log('ReconnectingWebsocket: Connected to ', this.url); - this.handleFreshConnect(); }; } catch (error) { - // eslint-disable-next-line no-console - console.error('ReconnectingWebSocket connection error:', error); + logAbacusTsError('ReconnectingWebSocket', 'connection error', error); this.ws?.close(); this.ws = null; this.handleReconnect(); @@ -112,6 +110,11 @@ export class ReconnectingWebSocket { public send(data: any): void { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + logAbacusTsError( + 'ReconnectingWebsocket', + 'Someone attempted to send data on socket in invalid state', + this.url + ); throw new Error('ReconnectingWebSocket: WebSocket is not connected'); } diff --git a/src/abacus-ts/websocket/websocketDerivedValue.ts b/src/abacus-ts/websocket/lib/websocketDerivedValue.ts similarity index 100% rename from src/abacus-ts/websocket/websocketDerivedValue.ts rename to src/abacus-ts/websocket/lib/websocketDerivedValue.ts diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index cf238b05e..5656a0698 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -9,13 +9,13 @@ import { timeUnits } from '@/constants/time'; import { type RootStore } from '@/state/_store'; import { setAllMarketsRaw } from '@/state/raw'; -import { createStoreEffect } from '../createStoreEffect'; -import { Loadable, loadableLoaded, loadablePending } from '../loadable'; +import { createStoreEffect } from '../lib/createStoreEffect'; +import { Loadable, loadableLoaded, loadablePending } from '../lib/loadable'; import { selectWebsocketUrl } from '../socketSelectors'; import { MarketsData } from '../types'; -import { IndexerWebsocket } from './indexerWebsocket'; -import { IndexerWebsocketManager } from './indexerWebsocketManager'; -import { WebsocketDerivedValue } from './websocketDerivedValue'; +import { IndexerWebsocket } from './lib/indexerWebsocket'; +import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; +import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; function marketsWebsocketValue( websocket: IndexerWebsocket, diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index c3712774c..9d4c31e32 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -9,13 +9,13 @@ import { setOrderbookRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; -import { createStoreEffect } from '../createStoreEffect'; -import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../loadable'; +import { createStoreEffect } from '../lib/createStoreEffect'; +import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../lib/loadable'; import { selectWebsocketUrl } from '../socketSelectors'; import { OrderbookData } from '../types'; -import { IndexerWebsocket } from './indexerWebsocket'; -import { IndexerWebsocketManager } from './indexerWebsocketManager'; -import { WebsocketDerivedValue } from './websocketDerivedValue'; +import { IndexerWebsocket } from './lib/indexerWebsocket'; +import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; +import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; function orderbookWebsocketValue( websocket: IndexerWebsocket, diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 174502e17..8ca42d78e 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -12,13 +12,13 @@ import { setParentSubaccountRaw } from '@/state/raw'; import { isTruthy } from '@/lib/isTruthy'; import { accountRefreshSignal } from '../accountRefreshSignal'; -import { createStoreEffect } from '../createStoreEffect'; -import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../loadable'; +import { createStoreEffect } from '../lib/createStoreEffect'; +import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../lib/loadable'; import { selectParentSubaccountInfo, selectWebsocketUrl } from '../socketSelectors'; import { ChildSubaccountData, ParentSubaccountData } from '../types'; -import { IndexerWebsocket } from './indexerWebsocket'; -import { IndexerWebsocketManager } from './indexerWebsocketManager'; -import { WebsocketDerivedValue } from './websocketDerivedValue'; +import { IndexerWebsocket } from './lib/indexerWebsocket'; +import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; +import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; function isValidSubaccount(childSubaccount: IndexerSubaccountResponseObject) { return ( diff --git a/src/constants/analytics.ts b/src/constants/analytics.ts index d3c4c6cd9..52c31560f 100644 --- a/src/constants/analytics.ts +++ b/src/constants/analytics.ts @@ -324,7 +324,7 @@ export const AnalyticsEvents = unionize( Error: ofType<{ location: string; - error: Error; + error?: Error; metadata?: any; }>(), RouteError: ofType<{ diff --git a/src/lib/telemetry.ts b/src/lib/telemetry.ts index 18b084676..075c4672c 100644 --- a/src/lib/telemetry.ts +++ b/src/lib/telemetry.ts @@ -4,7 +4,7 @@ import { isDev } from '@/constants/networks'; import { track } from './analytics/analytics'; import { dd } from './analytics/datadog'; -export const log = (location: string, error: Error, metadata?: object) => { +export const log = (location: string, error?: Error, metadata?: object) => { if (isDev) { // eslint-disable-next-line no-console console.warn('telemetry/log:', { location, error, metadata }); diff --git a/src/state/raw.ts b/src/state/raw.ts index 0b3a3d16e..bfc54e21c 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,4 +1,4 @@ -import { Loadable, loadableIdle } from '@/abacus-ts/loadable'; +import { Loadable, loadableIdle } from '@/abacus-ts/lib/loadable'; import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/types'; import { IndexerHistoricalBlockTradingRewardsResponse, From 6189fa1280336da1a043c77c5d8d0b14707ebae2 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:32:11 -0500 Subject: [PATCH 21/65] fix --- scripts/swagger_codegen.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh index a4110c9f7..be3fa661b 100755 --- a/scripts/swagger_codegen.sh +++ b/scripts/swagger_codegen.sh @@ -16,9 +16,6 @@ trap cleanup EXIT curl -o $TMP_DIR/swagger.json https://raw.githubusercontent.com/dydxprotocol/v4-chain/main/indexer/services/comlink/public/swagger.json -# Remove required attribute -# ${CURRENT_DIR}/json_remove_attr.sh -f $TMP_DIR/swagger.json -a required - cd "$TMP_DIR" swagger-codegen generate -i swagger.json -o generated -l typescript-fetch From dcc53a8b464e580a06af5268d102c16ee6cc5046 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:33:26 -0500 Subject: [PATCH 22/65] fix --- scripts/swagger_codegen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/swagger_codegen.sh b/scripts/swagger_codegen.sh index be3fa661b..0f8d1ee50 100755 --- a/scripts/swagger_codegen.sh +++ b/scripts/swagger_codegen.sh @@ -20,6 +20,7 @@ cd "$TMP_DIR" swagger-codegen generate -i swagger.json -o generated -l typescript-fetch +# a bunch of one off fixes to massage this thing into a reasonable state, probably very fragile sed -i '' '1,79d; /export const DefaultApiFetchParamCreator/,$d' generated/api.ts sed -i '' -e ':a' -e '$d;N;2,4ba' -e 'P;D' generated/api.ts line_num=$(grep -n "export interface SparklineResponseObject" generated/api.ts | cut -d: -f1) && sed -i '' "$((line_num-5)),$((line_num+3))d" generated/api.ts From 75ff184422f2b09c19a18945a3f0efb3d2a26f6d Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:37:34 -0500 Subject: [PATCH 23/65] fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f237e71a1..2b2552dba 100644 --- a/package.json +++ b/package.json @@ -236,4 +236,4 @@ "includeClassNames": true } } -} \ No newline at end of file +} From 6856775334eeb9069a88fb6cf888f9cf206e2863 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:49:33 -0500 Subject: [PATCH 24/65] fix --- src/types/indexer/chain.ts | 227 ----------------------------------- src/types/indexer/configs.ts | 33 ----- 2 files changed, 260 deletions(-) delete mode 100644 src/types/indexer/chain.ts delete mode 100644 src/types/indexer/configs.ts diff --git a/src/types/indexer/chain.ts b/src/types/indexer/chain.ts deleted file mode 100644 index 746b69115..000000000 --- a/src/types/indexer/chain.ts +++ /dev/null @@ -1,227 +0,0 @@ -// Staking Rewards -export interface OnChainStakingRewardsResponse { - rewards?: OnChainStakingReward[]; - total?: OnChainStakingRewardAmount[]; -} - -export interface OnChainStakingReward { - validatorAddress?: string; - reward?: OnChainStakingRewardAmount[]; -} - -export interface OnChainStakingRewardAmount { - denom?: string; - amount?: string; -} - -// Rewards Parameters -export interface OnChainRewardsParamsResponse { - params?: OnChainRewardsParams; -} - -export interface OnChainRewardsParams { - treasuryAccount?: string; - denom?: string; - denomExponent?: number; - marketId?: number; - feeMultiplierPpm?: number; -} - -// Equity Tiers -export interface OnChainEquityTiersResponse { - equityTierLimitConfig?: OnChainEquityTiers; -} - -export interface OnChainEquityTiers { - shortTermOrderEquityTiers?: OnChainEquityTier[]; - statefulOrderEquityTiers?: OnChainEquityTier[]; -} - -export interface OnChainEquityTier { - usdTncRequired?: string; - limit?: number; -} - -// Transactions -export interface ChainError { - message: string; - line?: number; - column?: number; - stack?: string; -} - -export interface OnChainTransactionErrorResponse { - error: ChainError; -} - -export interface ChainEvent { - type: string; - attributes: ChainEventAttribute[]; -} - -export interface ChainEventAttribute { - key: string; - value: string; -} - -export interface OnChainTransactionSuccessResponse { - height?: number; - hash?: string; - code?: number; - tx: string; - txIndex?: number; - gasUsed?: string; - gasWanted?: string; - events?: ChainEvent[]; -} - -// Vault Deposit Withdraw Slippage -export interface OnChainVaultDepositWithdrawSlippageResponse { - sharesToWithdraw: OnChainNumShares; - expectedQuoteQuantums: number; -} - -// User Fee Tier -export interface OnChainUserFeeTierResponse { - index?: number; - tier?: OnChainUserFeeTier; -} - -export interface OnChainUserFeeTier { - name?: string; - absoluteVolumeRequirement?: string; - totalVolumeShareRequirementPpm?: number; - makerVolumeShareRequirementPpm?: number; - makerFeePpm?: number; - takerFeePpm?: number; -} - -// Delegation -export interface OnChainDelegationResponse { - delegationResponses?: OnChainDelegationObject[]; - pagination?: OnChainAccountPagination; -} - -export interface OnChainDelegationObject { - delegation?: OnChainDelegationInfo; - balance?: OnChainAccountBalanceObject; -} - -export interface OnChainDelegationInfo { - delegatorAddress?: string; - validatorAddress?: string; - shares?: string; -} - -export interface OnChainAccountPagination { - nextKey?: string; - total?: string; -} - -// Fee Tiers -export interface OnChainFeeTiersResponse { - params?: OnChainFeeTierParams; -} - -export interface OnChainFeeTierParams { - tiers?: OnChainFeeTier[]; -} - -export interface OnChainFeeTier { - name?: string; - absoluteVolumeRequirement?: string; - totalVolumeShareRequirementPpm?: number; - makerVolumeShareRequirementPpm?: number; - makerFeePpm?: number; - takerFeePpm?: number; -} - -// Token Price -export interface OnChainTokenPriceResponse { - marketPrice?: OnChainTokenPrice; -} - -export interface OnChainTokenPrice { - price?: string; - id?: number; - exponent?: number; -} - -// Account Balance -export interface OnChainAccountBalanceObject { - denom?: string; - amount?: string; -} - -// Withdrawal Capacity -export interface OnChainWithdrawalCapacityResponse { - limiterCapacityList?: OnChainLimiterCapacity[]; -} - -export interface OnChainLimiterCapacity { - limiter?: OnChainLimiter; - capacity?: string; -} - -export interface OnChainLimiter { - period?: OnChainLimiterPeriod; - baselineMinimum?: string; - baselineTvlPpm?: number; -} - -export interface OnChainLimiterPeriod { - seconds?: string; - nanos?: number; -} - -// Unbonding -export interface OnChainUnbondingResponse { - unbondingResponses?: OnChainUnbondingObject[]; - pagination?: OnChainAccountPagination; -} - -export interface OnChainUnbondingObject { - delegatorAddress?: string; - validatorAddress?: string; - entries?: OnChainUnbondingEntry[]; -} - -export interface OnChainUnbondingEntry { - creationHeight?: string; - completionTime?: string; - initialBalance?: string; - balance?: string; - unbondingId?: string; - unbondingOnHoldRefCount?: string; -} - -// Account Vault -export interface OnChainShareUnlock { - shares?: OnChainNumShares; - unlockBlockHeight?: number; -} - -export interface OnChainNumShares { - numShares?: number; -} - -export interface OnChainAccountVaultResponse { - address?: string; - shares?: OnChainNumShares; - shareUnlocks?: OnChainShareUnlock[]; - equity?: number; - withdrawableEquity?: number; -} - -// Withdrawal And Transfer Gating Status -export interface OnChainWithdrawalAndTransferGatingStatusResponse { - negativeTncSubaccountSeenAtBlock?: number; - chainOutageSeenAtBlock?: number; - withdrawalsAndTransfersUnblockedAtBlock?: number; -} - -// User Stats -export interface OnChainUserStatsResponse { - takerNotional?: string; - makerNotional?: string; -} diff --git a/src/types/indexer/configs.ts b/src/types/indexer/configs.ts deleted file mode 100644 index 73150f7c4..000000000 --- a/src/types/indexer/configs.ts +++ /dev/null @@ -1,33 +0,0 @@ -export interface ConfigsLaunchIncentiveResponse { - data?: ConfigsLaunchIncentiveData; -} - -export interface ConfigsLaunchIncentiveData { - tradingSeasons?: ConfigsLaunchIncentiveSeason[]; -} - -export interface ConfigsLaunchIncentiveSeason { - label?: string; - startTimestamp?: number; -} - -export interface ConfigsLaunchIncentivePoints { - incentivePoints?: number; - marketMakingIncentivePoints?: number; - dydxRewards?: number; -} - -export interface ConfigsMarketAsset { - name: string; - websiteLink?: string; - whitepaperLink?: string; - coinMarketCapsLink?: string; - tags?: string[]; -} - -export interface ConfigsAssetMetadata { - name: string; - logo: string; - urls: Record; - sector_tags?: string[]; -} From 88cb956ada030401393949951fae2bc9a0b415b6 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 16:59:11 -0500 Subject: [PATCH 25/65] fix --- src/state/_store.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/state/_store.ts b/src/state/_store.ts index 1a016a50d..d1b93d1b9 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -4,6 +4,8 @@ import { persistReducer, persistStore } from 'redux-persist'; import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; import storage from 'redux-persist/lib/storage'; +import { isDev } from '@/constants/networks'; + import abacusStateManager from '@/lib/abacus'; import { accountSlice } from './account'; @@ -94,7 +96,7 @@ export const persistor = persistStore(store); // Set store so (Abacus & v4-Client) classes can getState and dispatch abacusStateManager.setStore(store); -const useAbacusTs: boolean = true; +const useAbacusTs: boolean = isDev; if (useAbacusTs) { // we ignore the cleanups for now since we want these running forever storeLifecycles.forEach((fn) => fn(store)); From 4f4e06179e8d84db9928037ae3dcbb00fb561c61 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:02:35 -0500 Subject: [PATCH 26/65] fix --- src/abacus-ts/websocket/trades.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/abacus-ts/websocket/trades.ts diff --git a/src/abacus-ts/websocket/trades.ts b/src/abacus-ts/websocket/trades.ts deleted file mode 100644 index e69de29bb..000000000 From e965fb5ef9ba2155eff8c83a1b9b1c3ab79d864b Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:28:07 -0500 Subject: [PATCH 27/65] fix --- src/lib/testFlags.ts | 6 ++++++ src/state/_store.ts | 8 +++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lib/testFlags.ts b/src/lib/testFlags.ts index d7972c798..704e83b8c 100644 --- a/src/lib/testFlags.ts +++ b/src/lib/testFlags.ts @@ -1,3 +1,5 @@ +import { isDev } from '@/constants/networks'; + class TestFlags { public queryParams: { [key: string]: string }; @@ -59,6 +61,10 @@ class TestFlags { get showInstantDepositToggle() { return !!this.queryParams.funkit_toggle; } + + get useAbacusTs() { + return isDev; + } } export const testFlags = new TestFlags(); diff --git a/src/state/_store.ts b/src/state/_store.ts index d1b93d1b9..0a50638c0 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -1,12 +1,10 @@ -import { storeLifecycles } from '@/abacus-ts/storeLifecycles'; import { Middleware, combineReducers, configureStore } from '@reduxjs/toolkit'; import { persistReducer, persistStore } from 'redux-persist'; import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; import storage from 'redux-persist/lib/storage'; -import { isDev } from '@/constants/networks'; - import abacusStateManager from '@/lib/abacus'; +import { testFlags } from '@/lib/testFlags'; import { accountSlice } from './account'; import { affiliatesSlice } from './affiliates'; @@ -96,8 +94,8 @@ export const persistor = persistStore(store); // Set store so (Abacus & v4-Client) classes can getState and dispatch abacusStateManager.setStore(store); -const useAbacusTs: boolean = isDev; -if (useAbacusTs) { +if (testFlags.useAbacusTs) { + const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); // we ignore the cleanups for now since we want these running forever storeLifecycles.forEach((fn) => fn(store)); } From 74f78efadeb73225930cbc5c1b9f2d4ee093e1c9 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:34:44 -0500 Subject: [PATCH 28/65] start --- src/abacus-ts/selectors/base.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/abacus-ts/selectors/base.ts diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts new file mode 100644 index 000000000..f925855b1 --- /dev/null +++ b/src/abacus-ts/selectors/base.ts @@ -0,0 +1,15 @@ +import { type RootState } from '@/state/_store'; + +export const selectRawState = (state: RootState) => state.raw; + +export const selectRawAccountState = (state: RootState) => state.raw.account; + +export const selectRawMarketsState = (state: RootState) => state.raw.markets.allMarkets; + +export const selectParentSubaccountData = (state: RootState) => + state.raw.account.parentSubaccount.data; +export const selectFillsData = (state: RootState) => state.raw.account.fills.data; +export const selectOrdersData = (state: RootState) => state.raw.account.orders.data; +export const selectTransfersData = (state: RootState) => state.raw.account.transfers.data; +export const selectBlockTradingRewardsData = (state: RootState) => + state.raw.account.blockTradingRewards.data; From 5172c36a83e978e9f31dcd0732fd3f48479ea0ee Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:35:49 -0500 Subject: [PATCH 29/65] fix --- src/state/_store.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/state/_store.ts b/src/state/_store.ts index 0a50638c0..59f0af63d 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -4,6 +4,7 @@ import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; import storage from 'redux-persist/lib/storage'; import abacusStateManager from '@/lib/abacus'; +import { runFn } from '@/lib/do'; import { testFlags } from '@/lib/testFlags'; import { accountSlice } from './account'; @@ -95,9 +96,11 @@ export const persistor = persistStore(store); abacusStateManager.setStore(store); if (testFlags.useAbacusTs) { - const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); - // we ignore the cleanups for now since we want these running forever - storeLifecycles.forEach((fn) => fn(store)); + runFn(async () => { + const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); + // we ignore the cleanups for now since we want these running forever + storeLifecycles.forEach((fn) => fn(store)); + }); } export type RootStore = typeof store; From 5486c65a2270d9e39bd52f975fe9aee18df2efaa Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:48:09 -0500 Subject: [PATCH 30/65] fix --- src/abacus-ts/types.ts | 44 --------------------- src/abacus-ts/websocket/markets.ts | 2 +- src/abacus-ts/websocket/orderbook.ts | 2 +- src/abacus-ts/websocket/parentSubaccount.ts | 2 +- src/state/raw.ts | 2 +- 5 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 src/abacus-ts/types.ts diff --git a/src/abacus-ts/types.ts b/src/abacus-ts/types.ts deleted file mode 100644 index 975ad639d..000000000 --- a/src/abacus-ts/types.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - IndexerAssetPositionResponseObject, - IndexerHistoricalBlockTradingReward, - IndexerPerpetualMarketResponseObject, - IndexerPerpetualPositionResponseObject, - IndexerTransferResponseObject, -} from '@/types/indexer/indexerApiGen'; -import { - IndexerCompositeFillObject, - IndexerCompositeOrderObject, -} from '@/types/indexer/indexerManual'; - -export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; - -export type OrderbookData = { - bids: { [price: string]: string }; - asks: { [price: string]: string }; -}; - -export interface ParentSubaccountData { - address: string; - parentSubaccount: number; - - childSubaccounts: { [subaccountNumber: string]: ChildSubaccountData | undefined }; - - // this data is lost on websocket reconnect, should never be trusted as the ONLY source for this information - // it should be used to trigger a rest call refresh (debounced) and merged with the rest call result until the refresh completes - ephemeral: { - tradingRewards?: IndexerHistoricalBlockTradingReward[]; - fills?: IndexerCompositeFillObject[]; - orders?: { [orderId: string]: IndexerCompositeOrderObject }; - transfers?: IndexerTransferResponseObject[]; - }; -} - -export interface ChildSubaccountData { - address: string; - - subaccountNumber: number; - - openPerpetualPositions: { [market: string]: IndexerPerpetualPositionResponseObject }; - - assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; -} diff --git a/src/abacus-ts/websocket/markets.ts b/src/abacus-ts/websocket/markets.ts index 5656a0698..370d9f093 100644 --- a/src/abacus-ts/websocket/markets.ts +++ b/src/abacus-ts/websocket/markets.ts @@ -11,8 +11,8 @@ import { setAllMarketsRaw } from '@/state/raw'; import { createStoreEffect } from '../lib/createStoreEffect'; import { Loadable, loadableLoaded, loadablePending } from '../lib/loadable'; +import { MarketsData } from '../rawTypes'; import { selectWebsocketUrl } from '../socketSelectors'; -import { MarketsData } from '../types'; import { IndexerWebsocket } from './lib/indexerWebsocket'; import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index 9d4c31e32..0ceb9171b 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -11,8 +11,8 @@ import { isTruthy } from '@/lib/isTruthy'; import { createStoreEffect } from '../lib/createStoreEffect'; import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../lib/loadable'; +import { OrderbookData } from '../rawTypes'; import { selectWebsocketUrl } from '../socketSelectors'; -import { OrderbookData } from '../types'; import { IndexerWebsocket } from './lib/indexerWebsocket'; import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 8ca42d78e..95cc87dfb 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -14,8 +14,8 @@ import { isTruthy } from '@/lib/isTruthy'; import { accountRefreshSignal } from '../accountRefreshSignal'; import { createStoreEffect } from '../lib/createStoreEffect'; import { Loadable, loadableIdle, loadableLoaded, loadablePending } from '../lib/loadable'; +import { ChildSubaccountData, ParentSubaccountData } from '../rawTypes'; import { selectParentSubaccountInfo, selectWebsocketUrl } from '../socketSelectors'; -import { ChildSubaccountData, ParentSubaccountData } from '../types'; import { IndexerWebsocket } from './lib/indexerWebsocket'; import { IndexerWebsocketManager } from './lib/indexerWebsocketManager'; import { WebsocketDerivedValue } from './lib/websocketDerivedValue'; diff --git a/src/state/raw.ts b/src/state/raw.ts index bfc54e21c..a514699f7 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,5 +1,5 @@ import { Loadable, loadableIdle } from '@/abacus-ts/lib/loadable'; -import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/types'; +import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/rawTypes'; import { IndexerHistoricalBlockTradingRewardsResponse, IndexerParentSubaccountTransferResponse, From a6fe44f1456205e44f59ca38faa3a40d46cb1d9d Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 10 Dec 2024 17:48:33 -0500 Subject: [PATCH 31/65] fix --- src/abacus-ts/rawTypes.ts | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/abacus-ts/rawTypes.ts diff --git a/src/abacus-ts/rawTypes.ts b/src/abacus-ts/rawTypes.ts new file mode 100644 index 000000000..975ad639d --- /dev/null +++ b/src/abacus-ts/rawTypes.ts @@ -0,0 +1,44 @@ +import { + IndexerAssetPositionResponseObject, + IndexerHistoricalBlockTradingReward, + IndexerPerpetualMarketResponseObject, + IndexerPerpetualPositionResponseObject, + IndexerTransferResponseObject, +} from '@/types/indexer/indexerApiGen'; +import { + IndexerCompositeFillObject, + IndexerCompositeOrderObject, +} from '@/types/indexer/indexerManual'; + +export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; + +export type OrderbookData = { + bids: { [price: string]: string }; + asks: { [price: string]: string }; +}; + +export interface ParentSubaccountData { + address: string; + parentSubaccount: number; + + childSubaccounts: { [subaccountNumber: string]: ChildSubaccountData | undefined }; + + // this data is lost on websocket reconnect, should never be trusted as the ONLY source for this information + // it should be used to trigger a rest call refresh (debounced) and merged with the rest call result until the refresh completes + ephemeral: { + tradingRewards?: IndexerHistoricalBlockTradingReward[]; + fills?: IndexerCompositeFillObject[]; + orders?: { [orderId: string]: IndexerCompositeOrderObject }; + transfers?: IndexerTransferResponseObject[]; + }; +} + +export interface ChildSubaccountData { + address: string; + + subaccountNumber: number; + + openPerpetualPositions: { [market: string]: IndexerPerpetualPositionResponseObject }; + + assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; +} From 13e0acb431c1e0dc2d163ab70bbee83d71774c14 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 11 Dec 2024 13:20:06 -0500 Subject: [PATCH 32/65] more types --- src/abacus-ts/selectors/account.ts | 0 src/abacus-ts/summaryTypes.ts | 15 +++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/abacus-ts/selectors/account.ts create mode 100644 src/abacus-ts/summaryTypes.ts diff --git a/src/abacus-ts/selectors/account.ts b/src/abacus-ts/selectors/account.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts new file mode 100644 index 000000000..db03e627d --- /dev/null +++ b/src/abacus-ts/summaryTypes.ts @@ -0,0 +1,15 @@ +interface SubaccountSummaryBase { + quoteBalance: number; + notionalTotal: number; + + freeCollateral: number; + equity: number; + + initialRiskTotal: number; + leverage: number; + marginUsage: number; +} + +interface SubaccountSummary {} + +interface GroupedSubaccountSummary {} From 59a27a01628bf1e400c085262631784ed012b591 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 15:31:43 -0500 Subject: [PATCH 33/65] updates --- src/abacus-ts/calculators/account.ts | 113 ++++++++++++++++++++ src/abacus-ts/summaryTypes.ts | 87 +++++++++++++-- src/abacus-ts/websocket/parentSubaccount.ts | 4 +- src/lib/do.ts | 1 + src/lib/numbers.ts | 3 + 5 files changed, 195 insertions(+), 13 deletions(-) create mode 100644 src/abacus-ts/calculators/account.ts diff --git a/src/abacus-ts/calculators/account.ts b/src/abacus-ts/calculators/account.ts new file mode 100644 index 000000000..c0eb02cf9 --- /dev/null +++ b/src/abacus-ts/calculators/account.ts @@ -0,0 +1,113 @@ +import { + IndexerPerpetualMarketResponseObject, + IndexerPerpetualPositionResponseObject, + IndexerPositionSide, +} from '@/types/indexer/indexerApiGen'; +import BigNumber from 'bignumber.js'; + +import { calc } from '@/lib/do'; +import { MaybeBigNumber, MustBigNumber } from '@/lib/numbers'; + +import { ChildSubaccountData, MarketsData } from '../rawTypes'; +import { SubaccountPositionDerivedCore, SubaccountSummaryCore } from '../summaryTypes'; + +export function calculateSubaccountSummaryCore( + subaccountData: ChildSubaccountData, + markets: MarketsData +): SubaccountSummaryCore { + const quoteBalance = calc(() => { + const usdcPosition = subaccountData.assetPositions.USDC; + if (!usdcPosition?.size) return MustBigNumber(0); + + const size = MustBigNumber(usdcPosition.size); + return usdcPosition.side === IndexerPositionSide.LONG ? size : size.negated(); + }); + + // Calculate totals from perpetual positions + const { valueTotal, initialRiskTotal } = Object.values( + subaccountData.openPerpetualPositions + ).reduce( + (acc, position) => { + const market = markets[position.market]; + if (market == null) { + return acc; + } + const { notionalTotal: positionValue, initialRiskTotal: positionRisk } = + getDerivedPositionInfo(position, market); + return { + valueTotal: acc.valueTotal.plus(positionValue), + initialRiskTotal: acc.initialRiskTotal.plus(positionRisk), + }; + }, + { + valueTotal: MustBigNumber(0), + initialRiskTotal: MustBigNumber(0), + } + ); + + return { + quoteBalance, + valueTotal, + initialRiskTotal, + }; +} + +const NUM_PARENT_SUBACCOUNTS = 128; + +function getDerivedPositionInfo( + position: IndexerPerpetualPositionResponseObject, + market: IndexerPerpetualMarketResponseObject +): SubaccountPositionDerivedCore { + const marginMode = position.subaccountNumber < NUM_PARENT_SUBACCOUNTS ? 'CROSS' : 'ISOLATED'; + const effectiveImf = getMarketEffectiveInitialMargin(market) ?? MustBigNumber(0); + + const size = MustBigNumber(position.size); + const oracle = MustBigNumber(market.oraclePrice); + const signedSize = position.side === IndexerPositionSide.SHORT ? size.negated() : size; + const notional = size.times(oracle); + const value = signedSize.times(oracle); + + return { + marginMode, + valueTotal: value, + notionalTotal: notional, + initialRiskTotal: notional.times(effectiveImf), + adjustedImf: effectiveImf, + adjustedMmf: MaybeBigNumber(market.maintenanceMarginFraction) ?? MustBigNumber(0), + }; +} + +function getMarketEffectiveInitialMargin(config: IndexerPerpetualMarketResponseObject) { + const initialMarginFraction = MaybeBigNumber(config.initialMarginFraction); + const openInterest = MaybeBigNumber(config.openInterest); + const openInterestLowerCap = MaybeBigNumber(config.openInterestLowerCap); + const openInterestUpperCap = MaybeBigNumber(config.openInterestUpperCap); + const oraclePrice = MaybeBigNumber(config.oraclePrice); + + if (initialMarginFraction == null) return null; + if ( + oraclePrice == null || + openInterest == null || + openInterestLowerCap == null || + openInterestUpperCap == null + ) { + return initialMarginFraction; + } + + // if these are equal we can throw an error from dividing by zero + if (openInterestUpperCap === openInterestLowerCap) { + return initialMarginFraction; + } + + const openNotional = openInterest.times(oraclePrice); + const scalingFactor = openNotional + .minus(openInterestLowerCap) + .div(openInterestUpperCap.minus(openInterestLowerCap)); + const imfIncrease = scalingFactor.times(MustBigNumber(1).minus(initialMarginFraction)); + + const effectiveIMF = BigNumber.minimum( + initialMarginFraction.plus(BigNumber.maximum(imfIncrease, 0.0)), + 1.0 + ); + return effectiveIMF; +} diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index db03e627d..060f95c33 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -1,15 +1,80 @@ -interface SubaccountSummaryBase { - quoteBalance: number; - notionalTotal: number; +import { IndexerPerpetualPositionResponseObject } from '@/types/indexer/indexerApiGen'; +import { type BigNumber } from 'bignumber.js'; - freeCollateral: number; - equity: number; +type ReplaceBigNumberInUnion = T extends string ? BigNumber : T; - initialRiskTotal: number; - leverage: number; - marginUsage: number; -} +// Helper type to select properties that can be strings (including in unions) +type SelectStringProperties = { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + [P in keyof T]: NonNullable extends string | infer U ? P : never; +}[keyof T]; -interface SubaccountSummary {} +// Main type that converts specified properties from string to BigNumber +type ConvertStringToBigNumber> = { + [P in keyof T]: P extends K ? ReplaceBigNumberInUnion : T[P]; +}; -interface GroupedSubaccountSummary {} +export type SubaccountSummaryCore = { + quoteBalance: BigNumber; + valueTotal: BigNumber; + initialRiskTotal: BigNumber; +}; + +export type SubaccountSummaryDerived = { + notionalTotal: BigNumber; + + freeCollateral: BigNumber; + equity: BigNumber; + + leverage: BigNumber; + marginUsage: BigNumber; +}; + +export type SubaccountSummary = SubaccountSummaryCore & SubaccountSummaryDerived; + +// type SubaccountPositionCore = ConvertStringToBigNumber< +// IndexerPerpetualPositionResponseObject, +// | 'size' +// | 'maxSize' +// | 'entryPrice' +// | 'realizedPnl' +// | 'createdAtHeight' +// | 'sumOpen' +// | 'sumClose' +// | 'netFunding' +// | 'unrealizedPnl' +// | 'exitPrice' +// >; + +export type SubaccountPositionBase = IndexerPerpetualPositionResponseObject; + +export type SubaccountPositionDerivedArgs = { + marketConfigs: { + effectiveInitialMarginFraction: BigNumber; + maintenanceMarginFraction: BigNumber; + }; + marketOraclePrice: BigNumber; + containingSubaccountInfo: SubaccountSummaryCore; +}; + +export type SubaccountPositionDerivedCore = { + marginMode: 'ISOLATED' | 'CROSS'; + notionalTotal: BigNumber; // always positive + valueTotal: BigNumber; // can be negative + adjustedImf: BigNumber; + adjustedMmf: BigNumber; + + initialRiskTotal: BigNumber; +}; + +export type SubaccountPositionDerivedExtra = { + maxLeverage: BigNumber; + + marginValue: BigNumber; + leverage: BigNumber; + + updatedUnrealizedPnl: BigNumber; + updatedUnrealizedPnlPercent: BigNumber; + + liquidationPrice: BigNumber; +}; diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 95cc87dfb..3919a5a83 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -59,14 +59,14 @@ function freshChildSubaccount({ function accountWebsocketValue( websocket: IndexerWebsocket, address: string, - subaccount: string, + parentSubaccount: string, onChange: (val: Loadable) => void ) { return new WebsocketDerivedValue>( websocket, { channel: 'v4_parent_subaccounts', - id: `${address}/${subaccount}`, + id: `${address}/${parentSubaccount}`, handleBaseData: (baseMessage) => { const message = isWsParentSubaccountSubscribed(baseMessage); accountRefreshSignal.notify(); diff --git a/src/lib/do.ts b/src/lib/do.ts index 16375f8c6..10a5470ce 100644 --- a/src/lib/do.ts +++ b/src/lib/do.ts @@ -1,6 +1,7 @@ export function runFn(fn: () => T): T { return fn(); } +export const calc = runFn; type NonNullableArray = { [K in keyof T]: NonNullable; diff --git a/src/lib/numbers.ts b/src/lib/numbers.ts index 9b2b6b6bd..e51f78060 100644 --- a/src/lib/numbers.ts +++ b/src/lib/numbers.ts @@ -14,6 +14,9 @@ export const MustBigNumber = (amount?: BigNumberish | null): BigNumber => // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing new BigNumber(amount || 0); +export const MaybeBigNumber = (amount?: BigNumberish | null): BigNumber | undefined => + amount ? MustBigNumber(amount) : undefined; + /** * @description Rounds the input to the nearest multiple of `factor`, which must be non-zero. */ From bfc405eea218ca30e61a45825db17b61aa6471db Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 15:32:41 -0500 Subject: [PATCH 34/65] fix --- src/abacus-ts/websocket/parentSubaccount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 95cc87dfb..b753e3575 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -59,14 +59,14 @@ function freshChildSubaccount({ function accountWebsocketValue( websocket: IndexerWebsocket, address: string, - subaccount: string, + parentSubaccountNumber: string, onChange: (val: Loadable) => void ) { return new WebsocketDerivedValue>( websocket, { channel: 'v4_parent_subaccounts', - id: `${address}/${subaccount}`, + id: `${address}/${parentSubaccountNumber}`, handleBaseData: (baseMessage) => { const message = isWsParentSubaccountSubscribed(baseMessage); accountRefreshSignal.notify(); From 917832c83e09f42894be3204c7d88e8b4bc049bb Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 15:48:43 -0500 Subject: [PATCH 35/65] fixes --- src/abacus-ts/lib/createStoreEffect.ts | 6 +++++- src/abacus-ts/rest/blockTradingRewards.ts | 1 + src/abacus-ts/rest/fills.ts | 1 + src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts | 2 ++ src/abacus-ts/rest/orders.ts | 1 + src/abacus-ts/rest/transfers.ts | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/abacus-ts/lib/createStoreEffect.ts b/src/abacus-ts/lib/createStoreEffect.ts index 8d4f66226..0857b36e3 100644 --- a/src/abacus-ts/lib/createStoreEffect.ts +++ b/src/abacus-ts/lib/createStoreEffect.ts @@ -10,7 +10,7 @@ export function createStoreEffect( let lastValue = selector(store.getState()); let lastCleanup = handleChange(lastValue); - return store.subscribe(() => { + const removeStoreListener = store.subscribe(() => { const thisValue = selector(store.getState()); if (thisValue !== lastValue) { lastCleanup?.(); @@ -18,4 +18,8 @@ export function createStoreEffect( lastCleanup = handleChange(thisValue); } }); + return () => { + lastCleanup?.(); + removeStoreListener(); + }; } diff --git a/src/abacus-ts/rest/blockTradingRewards.ts b/src/abacus-ts/rest/blockTradingRewards.ts index 0f80a3147..86b039759 100644 --- a/src/abacus-ts/rest/blockTradingRewards.ts +++ b/src/abacus-ts/rest/blockTradingRewards.ts @@ -37,6 +37,7 @@ export function setUpBlockTradingRewardsQuery(store: RootStore) { }) ); }, + onNoQuery: () => store.dispatch(setAccountBlockTradingRewardsRaw(loadableIdle())), }); return () => { diff --git a/src/abacus-ts/rest/fills.ts b/src/abacus-ts/rest/fills.ts index d4e401188..93214b8cb 100644 --- a/src/abacus-ts/rest/fills.ts +++ b/src/abacus-ts/rest/fills.ts @@ -31,6 +31,7 @@ export function setUpFillsQuery(store: RootStore) { }) ); }, + onNoQuery: () => store.dispatch(setAccountFillsRaw(loadableIdle())), }); return () => { cleanupListener(); diff --git a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts index ed6e708d7..3d68fd562 100644 --- a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts @@ -28,6 +28,7 @@ type QuerySetupConfig = { getQueryKey: (selectorResult: NoInfer) => any[]; getQueryFn: (client: IndexerClient, selectorResult: NoInfer) => (() => Promise) | null; onResult: (result: NoInfer>) => void; + onNoQuery: () => void; } & PassedQueryOptions; const baseOptions: PassedQueryOptions = { @@ -61,6 +62,7 @@ export function createIndexerQueryStoreEffect( const queryFn = config.getQueryFn(indexerClient, queryData); if (!queryFn) { IndexerClientManager.markDone(indexerClientConfig); + config.onNoQuery(); return undefined; } diff --git a/src/abacus-ts/rest/orders.ts b/src/abacus-ts/rest/orders.ts index 4f5699c8e..1d0082aa0 100644 --- a/src/abacus-ts/rest/orders.ts +++ b/src/abacus-ts/rest/orders.ts @@ -46,6 +46,7 @@ export function setUpOrdersQuery(store: RootStore) { }) ); }, + onNoQuery: () => store.dispatch(setAccountOrdersRaw(loadableIdle())), }); return () => { cleanupListener(); diff --git a/src/abacus-ts/rest/transfers.ts b/src/abacus-ts/rest/transfers.ts index fa68dc553..ae5847c9a 100644 --- a/src/abacus-ts/rest/transfers.ts +++ b/src/abacus-ts/rest/transfers.ts @@ -35,6 +35,7 @@ export function setUpTransfersQuery(store: RootStore) { }) ); }, + onNoQuery: () => store.dispatch(setAccountTransfersRaw(loadableIdle())), }); return () => { From 41bb0af5d9fedc632944a38f097867b4458e5339 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 15:51:42 -0500 Subject: [PATCH 36/65] fix --- pnpm-lock.yaml | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0dc1ee64d..c540f961e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2649,13 +2649,8 @@ packages: - fp-ts dev: false -<<<<<<< HEAD - /@chain-registry/types@0.50.31: - resolution: {integrity: sha512-WOVNfC0ss4+LsWDqoeBFxHuVHNasxuNvjMWYf8h1x2axUlMDgTLFubkTdW0Hj93uk1fOBTC07bJXCf915NMVnA==} -======= - /@chain-registry/types@0.50.33: - resolution: {integrity: sha512-1zArCjYizFdfbP3L1WCUm3iL7Kf7VBS8N87SEqaTg6rC+fePYsq90LGpFuq2wzNPfQWPT7tsMT22ISeDIYflLA==} ->>>>>>> origin/main + /@chain-registry/types@0.50.34: + resolution: {integrity: sha512-CMhHOOiICw/mHHJNqiqbwlwrAnexGsmVdtTv0IdV0NphxfkqzvUomiUpQsHnU0hjjLoFPxoe8atMNIMJs9v4vg==} dev: false /@coinbase/wallet-sdk@3.9.3: @@ -8464,7 +8459,7 @@ packages: hermes-profile-transformer: 0.0.6 node-stream-zip: 1.15.0 ora: 5.4.1 - semver: 7.6.2 + semver: 7.6.3 strip-ansi: 5.2.0 wcwidth: 1.0.1 yaml: 2.4.5 @@ -8547,7 +8542,7 @@ packages: node-fetch: 2.7.0(encoding@0.1.13) open: 6.4.0 ora: 5.4.1 - semver: 7.6.2 + semver: 7.6.3 shell-quote: 1.8.1 sudo-prompt: 9.2.1 transitivePeerDependencies: @@ -8581,7 +8576,7 @@ packages: fs-extra: 8.1.0 graceful-fs: 4.2.11 prompts: 2.4.2 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - bufferutil - encoding @@ -9878,7 +9873,7 @@ packages: '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.93.2) '@solana/web3.js': 1.93.2 axios: 1.6.7 - chain-registry: 1.69.59 + chain-registry: 1.69.60 cosmjs-types: 0.8.0 keccak256: 1.0.6 kujira.js: 0.9.162 @@ -14551,10 +14546,10 @@ packages: type-detect: 4.1.0 dev: true - /chain-registry@1.69.59: - resolution: {integrity: sha512-8NUDiFtgXJAOpFTGwAnBzps3Kfn/tlvLNVZ8W6J/5JbGf7R8ZSSeuMM+g8xm1toI7nbjgzN1HDGh/VjazVbbQw==} + /chain-registry@1.69.60: + resolution: {integrity: sha512-uh8b/RsxP9QfwxPKldcZronEnU/BRYNRxDcCCW4chyr3vxBbGoXkCk2PtK6JgPV53W4CukhcxNgawzhKO2YnEw==} dependencies: - '@chain-registry/types': 0.50.33 + '@chain-registry/types': 0.50.34 dev: false /chalk@2.4.2: @@ -20059,7 +20054,7 @@ packages: '@ethersproject/bignumber': 5.7.0 '@keplr-wallet/types': 0.11.64 '@types/google-protobuf': 3.15.12 - chain-registry: 1.69.59 + chain-registry: 1.69.60 cosmjs-types: 0.8.0 long: 4.0.0 text-encoding: 0.7.0 @@ -24459,7 +24454,6 @@ packages: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - dev: true /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} From 73d52e8236b85c2c3349c43f6ad81e6b27eef14d Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 16:26:42 -0500 Subject: [PATCH 37/65] fix --- src/abacus-ts/calculators/account.ts | 28 ++++++++++++++++++++-------- src/abacus-ts/summaryTypes.ts | 17 ++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/abacus-ts/calculators/account.ts b/src/abacus-ts/calculators/account.ts index c0eb02cf9..a603bb18b 100644 --- a/src/abacus-ts/calculators/account.ts +++ b/src/abacus-ts/calculators/account.ts @@ -32,8 +32,10 @@ export function calculateSubaccountSummaryCore( if (market == null) { return acc; } - const { notionalTotal: positionValue, initialRiskTotal: positionRisk } = - getDerivedPositionInfo(position, market); + const { value: positionValue, initialRiskTotal: positionRisk } = getDerivedPositionInfo( + position, + market + ); return { valueTotal: acc.valueTotal.plus(positionValue), initialRiskTotal: acc.initialRiskTotal.plus(positionRisk), @@ -59,25 +61,35 @@ function getDerivedPositionInfo( market: IndexerPerpetualMarketResponseObject ): SubaccountPositionDerivedCore { const marginMode = position.subaccountNumber < NUM_PARENT_SUBACCOUNTS ? 'CROSS' : 'ISOLATED'; - const effectiveImf = getMarketEffectiveInitialMargin(market) ?? MustBigNumber(0); + const effectiveImf = getMarketEffectiveInitialMarginForMarket(market) ?? MustBigNumber(0); - const size = MustBigNumber(position.size); + // indexer position size is already signed I think but we will be extra sure + const size = MustBigNumber(position.size).abs(); const oracle = MustBigNumber(market.oraclePrice); const signedSize = position.side === IndexerPositionSide.SHORT ? size.negated() : size; + const notional = size.times(oracle); const value = signedSize.times(oracle); return { marginMode, - valueTotal: value, - notionalTotal: notional, + size, + signedSize, + value, + notional, initialRiskTotal: notional.times(effectiveImf), adjustedImf: effectiveImf, adjustedMmf: MaybeBigNumber(market.maintenanceMarginFraction) ?? MustBigNumber(0), + maxLeverage: calc(() => { + if (effectiveImf.isZero()) { + return null; + } + return MustBigNumber(1).div(effectiveImf); + }), }; } -function getMarketEffectiveInitialMargin(config: IndexerPerpetualMarketResponseObject) { +function getMarketEffectiveInitialMarginForMarket(config: IndexerPerpetualMarketResponseObject) { const initialMarginFraction = MaybeBigNumber(config.initialMarginFraction); const openInterest = MaybeBigNumber(config.openInterest); const openInterestLowerCap = MaybeBigNumber(config.openInterestLowerCap); @@ -95,7 +107,7 @@ function getMarketEffectiveInitialMargin(config: IndexerPerpetualMarketResponseO } // if these are equal we can throw an error from dividing by zero - if (openInterestUpperCap === openInterestLowerCap) { + if (openInterestUpperCap.eq(openInterestLowerCap)) { return initialMarginFraction; } diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index 060f95c33..8a882e4bf 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -59,22 +59,25 @@ export type SubaccountPositionDerivedArgs = { export type SubaccountPositionDerivedCore = { marginMode: 'ISOLATED' | 'CROSS'; - notionalTotal: BigNumber; // always positive - valueTotal: BigNumber; // can be negative + + signedSize: BigNumber; + size: BigNumber; + notional: BigNumber; // always positive + value: BigNumber; // can be negative + adjustedImf: BigNumber; adjustedMmf: BigNumber; initialRiskTotal: BigNumber; + maxLeverage: BigNumber | null; }; export type SubaccountPositionDerivedExtra = { - maxLeverage: BigNumber; - - marginValue: BigNumber; + // all these depend on the subaccount being calculated leverage: BigNumber; + marginValue: BigNumber; + liquidationPrice: BigNumber; updatedUnrealizedPnl: BigNumber; updatedUnrealizedPnlPercent: BigNumber; - - liquidationPrice: BigNumber; }; From 2487d1dcc2b101b61617e785253d3b2c62f66443 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 16:42:53 -0500 Subject: [PATCH 38/65] fix horrible stupid mistake --- src/abacus-ts/lib/createStoreEffect.ts | 1 + src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts | 4 +--- src/abacus-ts/socketSelectors.ts | 7 +++---- src/abacus-ts/websocket/orderbook.ts | 3 +-- src/abacus-ts/websocket/parentSubaccount.ts | 3 +-- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/abacus-ts/lib/createStoreEffect.ts b/src/abacus-ts/lib/createStoreEffect.ts index 0857b36e3..11e2bd318 100644 --- a/src/abacus-ts/lib/createStoreEffect.ts +++ b/src/abacus-ts/lib/createStoreEffect.ts @@ -18,6 +18,7 @@ export function createStoreEffect( lastCleanup = handleChange(thisValue); } }); + return () => { lastCleanup?.(); removeStoreListener(); diff --git a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts index 3d68fd562..22783a72b 100644 --- a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts @@ -41,9 +41,7 @@ export function createIndexerQueryStoreEffect( config: QuerySetupConfig ) { const fullSelector = createAppSelector( - selectWebsocketUrl, - selectIndexerUrl, - config.selector, + [selectWebsocketUrl, selectIndexerUrl, config.selector], (wsUrl, indexerUrl, selectorResult) => ({ infrastructure: { wsUrl, indexerUrl }, queryData: selectorResult, diff --git a/src/abacus-ts/socketSelectors.ts b/src/abacus-ts/socketSelectors.ts index eec7b7d49..2cc5da442 100644 --- a/src/abacus-ts/socketSelectors.ts +++ b/src/abacus-ts/socketSelectors.ts @@ -7,18 +7,17 @@ import { getSelectedNetwork } from '@/state/appSelectors'; import { createAppSelector } from '@/state/appTypes'; const suffix = '/v4/ws'; -export const selectWebsocketUrl = createAppSelector(getSelectedNetwork, (network) => { +export const selectWebsocketUrl = createAppSelector([getSelectedNetwork], (network) => { const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; return `${endpointsConfig.indexers[0]!.socket}${suffix}`; }); -export const selectIndexerUrl = createAppSelector(getSelectedNetwork, (network) => { +export const selectIndexerUrl = createAppSelector([getSelectedNetwork], (network) => { const endpointsConfig: EndpointsConfig = ENVIRONMENT_CONFIG_MAP[network].endpoints; return `${endpointsConfig.indexers[0]!.api}`; }); export const selectParentSubaccountInfo = createAppSelector( - getUserWalletAddress, - getUserSubaccountNumber, + [getUserWalletAddress, getUserSubaccountNumber], (wallet, subaccount) => ({ wallet, subaccount }) ); diff --git a/src/abacus-ts/websocket/orderbook.ts b/src/abacus-ts/websocket/orderbook.ts index 0ceb9171b..0bbef85f1 100644 --- a/src/abacus-ts/websocket/orderbook.ts +++ b/src/abacus-ts/websocket/orderbook.ts @@ -66,8 +66,7 @@ function orderbookWebsocketValue( } const selectMarketAndWsInfo = createAppSelector( - selectWebsocketUrl, - (state) => state.perpetuals.currentMarketId, + [selectWebsocketUrl, (state) => state.perpetuals.currentMarketId], (wsUrl, currentMarketId) => ({ wsUrl, currentMarketId }) ); diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index b753e3575..af8f90e43 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -166,8 +166,7 @@ function accountWebsocketValue( } const selectParentSubaccount = createAppSelector( - selectWebsocketUrl, - selectParentSubaccountInfo, + [selectWebsocketUrl, selectParentSubaccountInfo], (wsUrl, { wallet, subaccount }) => ({ wsUrl, wallet, subaccount }) ); From c41903425aabd141207f094fe3830a9611ce3fa0 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 18:16:48 -0500 Subject: [PATCH 39/65] more calc --- src/abacus-ts/calculators/account.ts | 135 +++++++++++++++++++++++---- src/abacus-ts/summaryTypes.ts | 20 ++-- 2 files changed, 126 insertions(+), 29 deletions(-) diff --git a/src/abacus-ts/calculators/account.ts b/src/abacus-ts/calculators/account.ts index a603bb18b..cf9360c1b 100644 --- a/src/abacus-ts/calculators/account.ts +++ b/src/abacus-ts/calculators/account.ts @@ -9,7 +9,17 @@ import { calc } from '@/lib/do'; import { MaybeBigNumber, MustBigNumber } from '@/lib/numbers'; import { ChildSubaccountData, MarketsData } from '../rawTypes'; -import { SubaccountPositionDerivedCore, SubaccountSummaryCore } from '../summaryTypes'; +import { + SubaccountPositionDerivedCore, + SubaccountPositionDerivedExtra, + SubaccountSummary, + SubaccountSummaryCore, + SubaccountSummaryDerived, +} from '../summaryTypes'; + +const NUM_PARENT_SUBACCOUNTS = 128; +const BN_0 = MustBigNumber(0); +const BN_1 = MustBigNumber(1); export function calculateSubaccountSummaryCore( subaccountData: ChildSubaccountData, @@ -17,14 +27,14 @@ export function calculateSubaccountSummaryCore( ): SubaccountSummaryCore { const quoteBalance = calc(() => { const usdcPosition = subaccountData.assetPositions.USDC; - if (!usdcPosition?.size) return MustBigNumber(0); + if (!usdcPosition?.size) return BN_0; const size = MustBigNumber(usdcPosition.size); return usdcPosition.side === IndexerPositionSide.LONG ? size : size.negated(); }); // Calculate totals from perpetual positions - const { valueTotal, initialRiskTotal } = Object.values( + const { valueTotal, notionalTotal, initialRiskTotal, maintenanceRiskTotal } = Object.values( subaccountData.openPerpetualPositions ).reduce( (acc, position) => { @@ -32,63 +42,148 @@ export function calculateSubaccountSummaryCore( if (market == null) { return acc; } - const { value: positionValue, initialRiskTotal: positionRisk } = getDerivedPositionInfo( - position, - market - ); + const { + value: positionValue, + notional: positionNotional, + initialRisk: positionInitialRisk, + maintenanceRisk: positionMaintenanceRisk, + } = calculateDerivedPositionCore(position, market); return { valueTotal: acc.valueTotal.plus(positionValue), - initialRiskTotal: acc.initialRiskTotal.plus(positionRisk), + notionalTotal: acc.notionalTotal.plus(positionNotional), + initialRiskTotal: acc.initialRiskTotal.plus(positionInitialRisk), + maintenanceRiskTotal: acc.maintenanceRiskTotal.plus(positionMaintenanceRisk), }; }, { - valueTotal: MustBigNumber(0), - initialRiskTotal: MustBigNumber(0), + valueTotal: BN_0, + notionalTotal: BN_0, + initialRiskTotal: BN_0, + maintenanceRiskTotal: BN_0, } ); return { quoteBalance, valueTotal, + notionalTotal, initialRiskTotal, + maintenanceRiskTotal, }; } -const NUM_PARENT_SUBACCOUNTS = 128; +function calculateSubaccountSummaryDerived(core: SubaccountSummaryCore): SubaccountSummaryDerived { + const { initialRiskTotal, notionalTotal, quoteBalance, valueTotal } = core; + const equity = valueTotal.plus(quoteBalance); + + const freeCollateral = equity.minus(initialRiskTotal); + + let leverage = null; + let marginUsage = null; + + if (equity.gt(0)) { + leverage = notionalTotal.div(equity); + marginUsage = BN_1.minus(freeCollateral.div(equity)); + } -function getDerivedPositionInfo( + return { + freeCollateral, + equity, + leverage, + marginUsage, + }; +} + +function calculateDerivedPositionCore( position: IndexerPerpetualPositionResponseObject, market: IndexerPerpetualMarketResponseObject ): SubaccountPositionDerivedCore { const marginMode = position.subaccountNumber < NUM_PARENT_SUBACCOUNTS ? 'CROSS' : 'ISOLATED'; - const effectiveImf = getMarketEffectiveInitialMarginForMarket(market) ?? MustBigNumber(0); + const effectiveImf = getMarketEffectiveInitialMarginForMarket(market) ?? BN_0; + const effectiveMmf = MaybeBigNumber(market.maintenanceMarginFraction) ?? BN_0; // indexer position size is already signed I think but we will be extra sure - const size = MustBigNumber(position.size).abs(); + const unsignedSize = MustBigNumber(position.size).abs(); const oracle = MustBigNumber(market.oraclePrice); - const signedSize = position.side === IndexerPositionSide.SHORT ? size.negated() : size; + const signedSize = + position.side === IndexerPositionSide.SHORT ? unsignedSize.negated() : unsignedSize; - const notional = size.times(oracle); + const notional = unsignedSize.times(oracle); const value = signedSize.times(oracle); return { marginMode, - size, + unsignedSize, signedSize, value, notional, - initialRiskTotal: notional.times(effectiveImf), + initialRisk: notional.times(effectiveImf), + maintenanceRisk: notional.times(effectiveMmf), adjustedImf: effectiveImf, - adjustedMmf: MaybeBigNumber(market.maintenanceMarginFraction) ?? MustBigNumber(0), + adjustedMmf: effectiveMmf, maxLeverage: calc(() => { if (effectiveImf.isZero()) { return null; } - return MustBigNumber(1).div(effectiveImf); + return BN_1.div(effectiveImf); }), }; } +export function calculatePositionDerivedExtra( + basePosition: IndexerPerpetualPositionResponseObject, + position: SubaccountPositionDerivedCore, + subaccountSummary: SubaccountSummary +): SubaccountPositionDerivedExtra { + const { equity, maintenanceRiskTotal } = subaccountSummary; + const { signedSize, notional, value, marginMode, adjustedMmf, maintenanceRisk } = position; + + const leverage = equity.gt(0) ? notional.div(equity) : null; + + const marginValue = marginMode === 'ISOLATED' ? equity : notional.times(adjustedMmf); + + const liquidationPrice = calc(() => { + const otherPositionsRisk = maintenanceRiskTotal.minus(maintenanceRisk); + + // Calculate denominator based on position size + const denominator = signedSize.gt(0) + ? signedSize.minus(signedSize.times(adjustedMmf)) + : signedSize.plus(signedSize.times(adjustedMmf)); + + if (denominator.isZero()) { + return null; + } + + const liquidationPriceInner = otherPositionsRisk.plus(value).minus(equity).div(denominator); + + // Return null if liquidation price would be negative + return liquidationPriceInner.lt(0) ? null : liquidationPriceInner; + }); + + const { + unrealizedPnlInner: updatedUnrealizedPnl, + unrealizedPnlPercentInner: updatedUnrealizedPnlPercent, + } = calc(() => { + const entryValue = signedSize.multipliedBy(MustBigNumber(basePosition.entryPrice)); + const unrealizedPnlInner = value.minus(entryValue).plus(MustBigNumber(basePosition.netFunding)); + + const scaledLeverage = leverage ? BigNumber.max(leverage.abs(), BN_1) : BN_1; + + const unrealizedPnlPercentInner = !entryValue.isZero() + ? unrealizedPnlInner.dividedBy(entryValue.abs()).multipliedBy(scaledLeverage) + : null; + return { unrealizedPnlInner, unrealizedPnlPercentInner }; + }); + + return { + leverage, + marginValue, + liquidationPrice, + updatedUnrealizedPnl, + updatedUnrealizedPnlPercent, + }; +} + function getMarketEffectiveInitialMarginForMarket(config: IndexerPerpetualMarketResponseObject) { const initialMarginFraction = MaybeBigNumber(config.initialMarginFraction); const openInterest = MaybeBigNumber(config.openInterest); diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index 8a882e4bf..a20fbc5d1 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -17,17 +17,17 @@ type ConvertStringToBigNumber> = { export type SubaccountSummaryCore = { quoteBalance: BigNumber; valueTotal: BigNumber; + notionalTotal: BigNumber; initialRiskTotal: BigNumber; + maintenanceRiskTotal: BigNumber; }; export type SubaccountSummaryDerived = { - notionalTotal: BigNumber; - freeCollateral: BigNumber; equity: BigNumber; - leverage: BigNumber; - marginUsage: BigNumber; + leverage: BigNumber | null; + marginUsage: BigNumber | null; }; export type SubaccountSummary = SubaccountSummaryCore & SubaccountSummaryDerived; @@ -60,24 +60,26 @@ export type SubaccountPositionDerivedArgs = { export type SubaccountPositionDerivedCore = { marginMode: 'ISOLATED' | 'CROSS'; + // indexer size is signed by default I think signedSize: BigNumber; - size: BigNumber; + unsignedSize: BigNumber; // always positive notional: BigNumber; // always positive value: BigNumber; // can be negative adjustedImf: BigNumber; adjustedMmf: BigNumber; - initialRiskTotal: BigNumber; + initialRisk: BigNumber; + maintenanceRisk: BigNumber; maxLeverage: BigNumber | null; }; export type SubaccountPositionDerivedExtra = { // all these depend on the subaccount being calculated - leverage: BigNumber; + leverage: BigNumber | null; marginValue: BigNumber; - liquidationPrice: BigNumber; + liquidationPrice: BigNumber | null; updatedUnrealizedPnl: BigNumber; - updatedUnrealizedPnlPercent: BigNumber; + updatedUnrealizedPnlPercent: BigNumber | null; }; From eadb0b441e35c88dcb69f08319c81ea47232775e Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 12 Dec 2024 20:23:53 -0500 Subject: [PATCH 40/65] fixes --- src/abacus-ts/calculators/account.ts | 115 +++++++++++++++++++++++---- src/abacus-ts/summaryTypes.ts | 51 ++++++------ src/lib/numbers.ts | 8 ++ 3 files changed, 132 insertions(+), 42 deletions(-) diff --git a/src/abacus-ts/calculators/account.ts b/src/abacus-ts/calculators/account.ts index cf9360c1b..6d2458e8e 100644 --- a/src/abacus-ts/calculators/account.ts +++ b/src/abacus-ts/calculators/account.ts @@ -4,12 +4,19 @@ import { IndexerPositionSide, } from '@/types/indexer/indexerApiGen'; import BigNumber from 'bignumber.js'; +import { mapValues } from 'lodash'; + +import { NUM_PARENT_SUBACCOUNTS } from '@/constants/account'; import { calc } from '@/lib/do'; -import { MaybeBigNumber, MustBigNumber } from '@/lib/numbers'; +import { MaybeBigNumber, MustBigNumber, ToBigNumber } from '@/lib/numbers'; +import { isPresent } from '@/lib/typeUtils'; -import { ChildSubaccountData, MarketsData } from '../rawTypes'; +import { ChildSubaccountData, MarketsData, ParentSubaccountData } from '../rawTypes'; import { + GroupedSubaccountSummary, + SubaccountPosition, + SubaccountPositionBase, SubaccountPositionDerivedCore, SubaccountPositionDerivedExtra, SubaccountSummary, @@ -17,11 +24,57 @@ import { SubaccountSummaryDerived, } from '../summaryTypes'; -const NUM_PARENT_SUBACCOUNTS = 128; const BN_0 = MustBigNumber(0); const BN_1 = MustBigNumber(1); -export function calculateSubaccountSummaryCore( +export function calculateParentSubaccountPositions( + parent: Omit, + markets: MarketsData +): SubaccountPosition[] { + return Object.values(parent.childSubaccounts) + .filter(isPresent) + .flatMap((child) => { + const subaccount = calculateSubaccountSummary(child, markets); + return Object.values(child.openPerpetualPositions) + .filter(isPresent) + .map((perp) => calculateSubaccountPosition(subaccount, perp, markets[perp.market])); + }); +} + +export function calculateParentSubaccountSummary( + parent: Omit, + markets: MarketsData +): GroupedSubaccountSummary { + const summaries = mapValues(parent.childSubaccounts, (subaccount) => + subaccount != null ? calculateSubaccountSummary(subaccount, markets) : subaccount + ); + const parentSummary = summaries[parent.parentSubaccount]; + if (parentSummary == null) { + throw new Error('Parent subaccount not found in ParentSubaccountData'); + } + return { + marginUsage: parentSummary.marginUsage, + leverage: parentSummary.leverage, + freeCollateral: parentSummary.freeCollateral, + equity: Object.values(summaries) + .filter(isPresent) + .map((s) => s.equity) + .reduce((a, b) => a.plus(b), BN_0), + }; +} + +function calculateSubaccountSummary( + subaccountData: ChildSubaccountData, + markets: MarketsData +): SubaccountSummary { + const core = calculateSubaccountSummaryCore(subaccountData, markets); + return { + ...core, + ...calculateSubaccountSummaryDerived(core), + }; +} + +function calculateSubaccountSummaryCore( subaccountData: ChildSubaccountData, markets: MarketsData ): SubaccountSummaryCore { @@ -47,7 +100,7 @@ export function calculateSubaccountSummaryCore( notional: positionNotional, initialRisk: positionInitialRisk, maintenanceRisk: positionMaintenanceRisk, - } = calculateDerivedPositionCore(position, market); + } = calculateDerivedPositionCore(getBnPosition(position), market); return { valueTotal: acc.valueTotal.plus(positionValue), notionalTotal: acc.notionalTotal.plus(positionNotional), @@ -94,17 +147,48 @@ function calculateSubaccountSummaryDerived(core: SubaccountSummaryCore): Subacco }; } -function calculateDerivedPositionCore( +function calculateSubaccountPosition( + subaccountSummary: SubaccountSummary, position: IndexerPerpetualPositionResponseObject, - market: IndexerPerpetualMarketResponseObject + market: IndexerPerpetualMarketResponseObject | undefined +): SubaccountPosition { + const bnPosition = getBnPosition(position); + const core = calculateDerivedPositionCore(bnPosition, market); + return { + ...bnPosition, + ...core, + ...calculatePositionDerivedExtra(core, subaccountSummary), + }; +} + +function getBnPosition(position: IndexerPerpetualPositionResponseObject): SubaccountPositionBase { + return { + ...position, + size: ToBigNumber(position.size), + maxSize: ToBigNumber(position.maxSize), + entryPrice: ToBigNumber(position.entryPrice), + realizedPnl: ToBigNumber(position.realizedPnl), + createdAtHeight: ToBigNumber(position.createdAtHeight), + sumOpen: ToBigNumber(position.sumOpen), + sumClose: ToBigNumber(position.sumClose), + netFunding: ToBigNumber(position.netFunding), + unrealizedPnl: ToBigNumber(position.unrealizedPnl), + exitPrice: position.exitPrice != null ? ToBigNumber(position.exitPrice) : position.exitPrice, + }; +} + +function calculateDerivedPositionCore( + position: SubaccountPositionBase, + market: IndexerPerpetualMarketResponseObject | undefined ): SubaccountPositionDerivedCore { const marginMode = position.subaccountNumber < NUM_PARENT_SUBACCOUNTS ? 'CROSS' : 'ISOLATED'; - const effectiveImf = getMarketEffectiveInitialMarginForMarket(market) ?? BN_0; - const effectiveMmf = MaybeBigNumber(market.maintenanceMarginFraction) ?? BN_0; + const effectiveImf = + market != null ? getMarketEffectiveInitialMarginForMarket(market) ?? BN_0 : BN_0; + const effectiveMmf = MaybeBigNumber(market?.maintenanceMarginFraction) ?? BN_0; // indexer position size is already signed I think but we will be extra sure - const unsignedSize = MustBigNumber(position.size).abs(); - const oracle = MustBigNumber(market.oraclePrice); + const unsignedSize = position.size.abs(); + const oracle = MaybeBigNumber(market?.oraclePrice) ?? BN_0; const signedSize = position.side === IndexerPositionSide.SHORT ? unsignedSize.negated() : unsignedSize; @@ -127,11 +211,12 @@ function calculateDerivedPositionCore( } return BN_1.div(effectiveImf); }), + baseEntryPrice: position.entryPrice, + baseNetFunding: position.netFunding, }; } -export function calculatePositionDerivedExtra( - basePosition: IndexerPerpetualPositionResponseObject, +function calculatePositionDerivedExtra( position: SubaccountPositionDerivedCore, subaccountSummary: SubaccountSummary ): SubaccountPositionDerivedExtra { @@ -164,8 +249,8 @@ export function calculatePositionDerivedExtra( unrealizedPnlInner: updatedUnrealizedPnl, unrealizedPnlPercentInner: updatedUnrealizedPnlPercent, } = calc(() => { - const entryValue = signedSize.multipliedBy(MustBigNumber(basePosition.entryPrice)); - const unrealizedPnlInner = value.minus(entryValue).plus(MustBigNumber(basePosition.netFunding)); + const entryValue = signedSize.multipliedBy(MustBigNumber(position.baseEntryPrice)); + const unrealizedPnlInner = value.minus(entryValue).plus(MustBigNumber(position.baseNetFunding)); const scaledLeverage = leverage ? BigNumber.max(leverage.abs(), BN_1) : BN_1; diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index a20fbc5d1..a2a2f9e8f 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -31,37 +31,26 @@ export type SubaccountSummaryDerived = { }; export type SubaccountSummary = SubaccountSummaryCore & SubaccountSummaryDerived; - -// type SubaccountPositionCore = ConvertStringToBigNumber< -// IndexerPerpetualPositionResponseObject, -// | 'size' -// | 'maxSize' -// | 'entryPrice' -// | 'realizedPnl' -// | 'createdAtHeight' -// | 'sumOpen' -// | 'sumClose' -// | 'netFunding' -// | 'unrealizedPnl' -// | 'exitPrice' -// >; - -export type SubaccountPositionBase = IndexerPerpetualPositionResponseObject; - -export type SubaccountPositionDerivedArgs = { - marketConfigs: { - effectiveInitialMarginFraction: BigNumber; - maintenanceMarginFraction: BigNumber; - }; - marketOraclePrice: BigNumber; - containingSubaccountInfo: SubaccountSummaryCore; -}; +export type GroupedSubaccountSummary = SubaccountSummaryDerived; + +export type SubaccountPositionBase = ConvertStringToBigNumber< + IndexerPerpetualPositionResponseObject, + | 'size' + | 'maxSize' + | 'entryPrice' + | 'realizedPnl' + | 'createdAtHeight' + | 'sumOpen' + | 'sumClose' + | 'netFunding' + | 'unrealizedPnl' + | 'exitPrice' +>; export type SubaccountPositionDerivedCore = { marginMode: 'ISOLATED' | 'CROSS'; - // indexer size is signed by default I think - signedSize: BigNumber; + signedSize: BigNumber; // indexer size is signed by default but we make it obvious here unsignedSize: BigNumber; // always positive notional: BigNumber; // always positive value: BigNumber; // can be negative @@ -72,6 +61,10 @@ export type SubaccountPositionDerivedCore = { initialRisk: BigNumber; maintenanceRisk: BigNumber; maxLeverage: BigNumber | null; + + // these are just copied from the perpetual position for aesthetic reasons honestly + baseEntryPrice: BigNumber; + baseNetFunding: BigNumber; }; export type SubaccountPositionDerivedExtra = { @@ -83,3 +76,7 @@ export type SubaccountPositionDerivedExtra = { updatedUnrealizedPnl: BigNumber; updatedUnrealizedPnlPercent: BigNumber | null; }; + +export type SubaccountPosition = SubaccountPositionBase & + SubaccountPositionDerivedCore & + SubaccountPositionDerivedExtra; diff --git a/src/lib/numbers.ts b/src/lib/numbers.ts index e51f78060..7723ad7d3 100644 --- a/src/lib/numbers.ts +++ b/src/lib/numbers.ts @@ -10,13 +10,21 @@ export const BIG_NUMBERS = { ONE: new BigNumber(1), }; +// defaults to zero if null or empty export const MustBigNumber = (amount?: BigNumberish | null): BigNumber => // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing new BigNumber(amount || 0); +// undefined if falsey otherwise a valid bignumber export const MaybeBigNumber = (amount?: BigNumberish | null): BigNumber | undefined => amount ? MustBigNumber(amount) : undefined; +// doesnt allow null, always returns big number +// empty string becomes null though +export const ToBigNumber = (amount: BigNumberish): BigNumber => { + return MustBigNumber(amount); +}; + /** * @description Rounds the input to the nearest multiple of `factor`, which must be non-zero. */ From e7d5a2a084601511d2990d00f8b01e781420038b Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 13 Dec 2024 16:16:21 -0500 Subject: [PATCH 41/65] order calculations --- src/abacus-ts/calculators/orders.ts | 159 ++++++++++++++++++ .../calculators/{account.ts => subaccount.ts} | 4 +- src/abacus-ts/rawTypes.ts | 3 +- src/abacus-ts/summaryTypes.ts | 53 +++++- src/state/raw.ts | 14 +- 5 files changed, 219 insertions(+), 14 deletions(-) create mode 100644 src/abacus-ts/calculators/orders.ts rename src/abacus-ts/calculators/{account.ts => subaccount.ts} (98%) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts new file mode 100644 index 000000000..0bf838d7d --- /dev/null +++ b/src/abacus-ts/calculators/orders.ts @@ -0,0 +1,159 @@ +import { IndexerBestEffortOpenedStatus, IndexerOrderStatus } from '@/types/indexer/indexerApiGen'; +import { IndexerCompositeOrderObject } from '@/types/indexer/indexerManual'; +import { maxBy, pickBy } from 'lodash'; + +import { SubaccountOrder } from '@/constants/abacus'; + +import { assertNever } from '@/lib/assertNever'; +import { MustBigNumber } from '@/lib/numbers'; + +import { Loadable } from '../lib/loadable'; +import { OrdersData } from '../rawTypes'; +import { OrderStatus } from '../summaryTypes'; + +const BN_0 = MustBigNumber(0); +const BN_1 = MustBigNumber(1); + +// todo these are calculating the same thing twice pasically +function calculateOpenOrders(liveOrders: Loadable, restOrders: Loadable) { + const getOpenOrders = (data: Loadable) => + mapLoadableData(data, (d) => + pickBy( + d, + (order) => + getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) === OrderStatus.Open + ) + ); + return calculateMergedOrders(getOpenOrders(liveOrders), getOpenOrders(restOrders)); +} + +function calculateOrderHistory(liveOrders: Loadable, restOrders: Loadable) { + const getNonOpenOrders = (data: Loadable) => + mapLoadableData(data, (d) => + pickBy( + d, + (order) => + getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) !== OrderStatus.Open + ) + ); + return calculateMergedOrders(getNonOpenOrders(liveOrders), getNonOpenOrders(restOrders)); +} + +function calculateSubaccountOrder( + order: IndexerCompositeOrderObject, + protocolHeight: number +): SubaccountOrder {} + +function getSimpleOrderStatus(status: OrderStatus) { + switch (status) { + case OrderStatus.Open: + case OrderStatus.Pending: + case OrderStatus.PartiallyFilled: + case OrderStatus.Untriggered: + case OrderStatus.Canceling: + return OrderStatus.Open; + case OrderStatus.Canceled: + case OrderStatus.PartiallyCanceled: + return OrderStatus.Canceled; + case OrderStatus.Filled: + return OrderStatus.Filled; + default: + assertNever(status); + return OrderStatus.Open; + } +} + +function calculateBaseOrderStatus(order: IndexerCompositeOrderObject): OrderStatus | undefined { + const status = order.status; + if (status == null) { + return undefined; + } + + if (status === IndexerBestEffortOpenedStatus.BESTEFFORTOPENED) { + return OrderStatus.Pending; + } + + // Calculate filled amounts + const size = MustBigNumber(order.size); + const totalFilled = MustBigNumber(order.totalFilled); + const remainingSize = size.minus(totalFilled); + const hasPartialFill = totalFilled.gt(0) && remainingSize.gt(0); + + // Handle partial fills + if (hasPartialFill) { + if (status === IndexerOrderStatus.OPEN) { + return OrderStatus.PartiallyFilled; + } + if (status === IndexerOrderStatus.CANCELED) { + return OrderStatus.PartiallyCanceled; + } + } + + // Handle short-term order edge case + const isShortTermOrder = order.orderFlags === '0'; + const isBestEffortCanceled = status === IndexerOrderStatus.BESTEFFORTCANCELED; + const isUserCanceled = + order.removalReason === 'USER_CANCELED' || + order.removalReason === 'ORDER_REMOVAL_REASON_USER_CANCELED'; + + if (isShortTermOrder && isBestEffortCanceled && !isUserCanceled) { + return OrderStatus.Pending; + } + + // Direct mapping for remaining cases + switch (status) { + case IndexerOrderStatus.OPEN: + return OrderStatus.Open; + case IndexerOrderStatus.FILLED: + return OrderStatus.Filled; + case IndexerOrderStatus.CANCELED: + return OrderStatus.Canceled; + case IndexerOrderStatus.BESTEFFORTCANCELED: + return OrderStatus.Canceling; + case IndexerOrderStatus.UNTRIGGERED: + return OrderStatus.Untriggered; + default: + assertNever(status); + return undefined; + } +} + +function calculateMergedOrders(liveOrders: Loadable, restOrders: Loadable) { + const liveData = liveOrders.data ?? {}; + const restData = restOrders.data ?? {}; + return mergeObjects( + liveData, + restData, + (a, b) => + maxBy([a, b], (o) => MustBigNumber(o.updatedAtHeight ?? o.createdAtHeight).toNumber())! + ); +} + +function mapLoadableData(load: Loadable, map: (obj: T) => R): Loadable { + return { + ...load, + data: load.data != null ? map(load.data) : undefined, + } as Loadable; +} + +type SimpleMap = { [key: string]: T }; +function mergeObjects(one: SimpleMap, two: SimpleMap, merge: (a: T, b: T) => T) { + const finalObj: SimpleMap = {}; + + [...Object.keys(one), ...Object.keys(two)].forEach((key) => { + if (finalObj[key] != null) { + return; + } + const obj = one[key]; + const otherObj = two[key]; + if (obj != null && otherObj != null) { + finalObj[key] = merge(obj, otherObj); + } else if (obj == null && otherObj == null) { + // do nothing + } else { + // we know one of them is non-null + finalObj[key] = (obj ?? otherObj)!; + } + }); + return finalObj; +} diff --git a/src/abacus-ts/calculators/account.ts b/src/abacus-ts/calculators/subaccount.ts similarity index 98% rename from src/abacus-ts/calculators/account.ts rename to src/abacus-ts/calculators/subaccount.ts index 6d2458e8e..190ee7a9a 100644 --- a/src/abacus-ts/calculators/account.ts +++ b/src/abacus-ts/calculators/subaccount.ts @@ -1,6 +1,7 @@ import { IndexerPerpetualMarketResponseObject, IndexerPerpetualPositionResponseObject, + IndexerPerpetualPositionStatus, IndexerPositionSide, } from '@/types/indexer/indexerApiGen'; import BigNumber from 'bignumber.js'; @@ -37,6 +38,7 @@ export function calculateParentSubaccountPositions( const subaccount = calculateSubaccountSummary(child, markets); return Object.values(child.openPerpetualPositions) .filter(isPresent) + .filter((p) => p.status === IndexerPerpetualPositionStatus.OPEN) .map((perp) => calculateSubaccountPosition(subaccount, perp, markets[perp.market])); }); } @@ -63,7 +65,7 @@ export function calculateParentSubaccountSummary( }; } -function calculateSubaccountSummary( +export function calculateSubaccountSummary( subaccountData: ChildSubaccountData, markets: MarketsData ): SubaccountSummary { diff --git a/src/abacus-ts/rawTypes.ts b/src/abacus-ts/rawTypes.ts index 975ad639d..b76ab671b 100644 --- a/src/abacus-ts/rawTypes.ts +++ b/src/abacus-ts/rawTypes.ts @@ -11,6 +11,7 @@ import { } from '@/types/indexer/indexerManual'; export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; +export type OrdersData = { [orderId: string]: IndexerCompositeOrderObject }; export type OrderbookData = { bids: { [price: string]: string }; @@ -28,7 +29,7 @@ export interface ParentSubaccountData { ephemeral: { tradingRewards?: IndexerHistoricalBlockTradingReward[]; fills?: IndexerCompositeFillObject[]; - orders?: { [orderId: string]: IndexerCompositeOrderObject }; + orders?: OrdersData; transfers?: IndexerTransferResponseObject[]; }; } diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index a2a2f9e8f..7af08164a 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -1,4 +1,9 @@ -import { IndexerPerpetualPositionResponseObject } from '@/types/indexer/indexerApiGen'; +import { + IndexerAPITimeInForce, + IndexerOrderSide, + IndexerOrderType, + IndexerPerpetualPositionResponseObject, +} from '@/types/indexer/indexerApiGen'; import { type BigNumber } from 'bignumber.js'; type ReplaceBigNumberInUnion = T extends string ? BigNumber : T; @@ -47,8 +52,10 @@ export type SubaccountPositionBase = ConvertStringToBigNumber< | 'exitPrice' >; +export type MarginMode = 'ISOLATED' | 'CROSS'; + export type SubaccountPositionDerivedCore = { - marginMode: 'ISOLATED' | 'CROSS'; + marginMode: MarginMode; signedSize: BigNumber; // indexer size is signed by default but we make it obvious here unsignedSize: BigNumber; // always positive @@ -80,3 +87,45 @@ export type SubaccountPositionDerivedExtra = { export type SubaccountPosition = SubaccountPositionBase & SubaccountPositionDerivedCore & SubaccountPositionDerivedExtra; + +export enum OrderStatus { + Canceled = 'CANCELED', + Canceling = 'BEST_EFFORT_CANCELED', + Filled = 'FILLED', + Open = 'OPEN', + Pending = 'PENDING', + Untriggered = 'UNTRIGGERED', + PartiallyFilled = 'PARTIALLY_FILLED', + PartiallyCanceled = 'PARTIALLY_CANCELED', +} + +export type SubaccountOrder = { + subaccountNumber: number; + id: string; + clientId: string | null; + type: IndexerOrderType; + side: IndexerOrderSide; + status: OrderStatus; + timeInForce: IndexerAPITimeInForce | null; + marketId: string; + displayId: string; + clobPairId: number | null; + orderFlags: string | null; + price: BigNumber; + triggerPrice: BigNumber | null; + trailingPercent: BigNumber | null; + size: BigNumber; + remainingSize: BigNumber | null; + totalFilled: BigNumber | null; + goodTilBlock: number | null; + goodTilBlockTime: number | null; + createdAtHeight: number | null; + createdAtMilliseconds: number | null; + unfillableAtMilliseconds: number | null; + expiresAtMilliseconds: number | null; + updatedAtMilliseconds: number | null; + postOnly: boolean; + reduceOnly: boolean; + cancelReason: string | null; + marginMode: MarginMode | null; +}; diff --git a/src/state/raw.ts b/src/state/raw.ts index a514699f7..df03eb04a 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,13 +1,10 @@ import { Loadable, loadableIdle } from '@/abacus-ts/lib/loadable'; -import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/rawTypes'; +import { MarketsData, OrderbookData, OrdersData, ParentSubaccountData } from '@/abacus-ts/rawTypes'; import { IndexerHistoricalBlockTradingRewardsResponse, IndexerParentSubaccountTransferResponse, } from '@/types/indexer/indexerApiGen'; -import { - IndexerCompositeFillResponse, - IndexerCompositeOrderObject, -} from '@/types/indexer/indexerManual'; +import { IndexerCompositeFillResponse } from '@/types/indexer/indexerManual'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; export interface RawDataState { @@ -18,7 +15,7 @@ export interface RawDataState { account: { parentSubaccount: Loadable; fills: Loadable; - orders: Loadable<{ [id: string]: IndexerCompositeOrderObject }>; + orders: Loadable; transfers: Loadable; blockTradingRewards: Loadable; }; @@ -66,10 +63,7 @@ export const rawSlice = createSlice({ ) => { state.account.blockTradingRewards = action.payload; }, - setAccountOrdersRaw: ( - state, - action: PayloadAction> - ) => { + setAccountOrdersRaw: (state, action: PayloadAction>) => { state.account.orders = action.payload; }, }, From 2c7563a9cf9cefa54614d110d4956e9d91734021 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 13 Dec 2024 16:17:30 -0500 Subject: [PATCH 42/65] fix --- src/abacus-ts/calculators/orders.ts | 35 +++-------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts index 0bf838d7d..c1dd7807f 100644 --- a/src/abacus-ts/calculators/orders.ts +++ b/src/abacus-ts/calculators/orders.ts @@ -8,12 +8,11 @@ import { assertNever } from '@/lib/assertNever'; import { MustBigNumber } from '@/lib/numbers'; import { Loadable } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; +import { mergeObjects } from '../lib/mergeObjects'; import { OrdersData } from '../rawTypes'; import { OrderStatus } from '../summaryTypes'; -const BN_0 = MustBigNumber(0); -const BN_1 = MustBigNumber(1); - // todo these are calculating the same thing twice pasically function calculateOpenOrders(liveOrders: Loadable, restOrders: Loadable) { const getOpenOrders = (data: Loadable) => @@ -59,6 +58,7 @@ function getSimpleOrderStatus(status: OrderStatus) { return OrderStatus.Filled; default: assertNever(status); + // should never happen since we made OrderStatus manually return OrderStatus.Open; } } @@ -128,32 +128,3 @@ function calculateMergedOrders(liveOrders: Loadable, restOrders: Loa maxBy([a, b], (o) => MustBigNumber(o.updatedAtHeight ?? o.createdAtHeight).toNumber())! ); } - -function mapLoadableData(load: Loadable, map: (obj: T) => R): Loadable { - return { - ...load, - data: load.data != null ? map(load.data) : undefined, - } as Loadable; -} - -type SimpleMap = { [key: string]: T }; -function mergeObjects(one: SimpleMap, two: SimpleMap, merge: (a: T, b: T) => T) { - const finalObj: SimpleMap = {}; - - [...Object.keys(one), ...Object.keys(two)].forEach((key) => { - if (finalObj[key] != null) { - return; - } - const obj = one[key]; - const otherObj = two[key]; - if (obj != null && otherObj != null) { - finalObj[key] = merge(obj, otherObj); - } else if (obj == null && otherObj == null) { - // do nothing - } else { - // we know one of them is non-null - finalObj[key] = (obj ?? otherObj)!; - } - }); - return finalObj; -} From dc2500a055c115c075082c11c3029e793b4127ea Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 13 Dec 2024 16:34:35 -0500 Subject: [PATCH 43/65] move stuff around --- src/abacus-ts/calculators/blockRewards.ts | 21 +++++++++++++++++++++ src/abacus-ts/calculators/fills.ts | 21 +++++++++++++++++++++ src/abacus-ts/calculators/transfers.ts | 21 +++++++++++++++++++++ src/abacus-ts/lib/mapLoadable.ts | 8 ++++++++ src/abacus-ts/lib/mergeObjects.ts | 21 +++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 src/abacus-ts/calculators/blockRewards.ts create mode 100644 src/abacus-ts/calculators/fills.ts create mode 100644 src/abacus-ts/calculators/transfers.ts create mode 100644 src/abacus-ts/lib/mapLoadable.ts create mode 100644 src/abacus-ts/lib/mergeObjects.ts diff --git a/src/abacus-ts/calculators/blockRewards.ts b/src/abacus-ts/calculators/blockRewards.ts new file mode 100644 index 000000000..ff08b36ab --- /dev/null +++ b/src/abacus-ts/calculators/blockRewards.ts @@ -0,0 +1,21 @@ +import { IndexerHistoricalBlockTradingReward } from '@/types/indexer/indexerApiGen'; +import { keyBy, maxBy } from 'lodash'; + +import { MustBigNumber } from '@/lib/numbers'; + +import { Loadable } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; +import { mergeObjects } from '../lib/mergeObjects'; + +function calculateBlockRewards( + liveTransfers: Loadable, + restTransfers: Loadable +) { + const getRewardsById = (data: Loadable) => + mapLoadableData(data, (d) => keyBy(d, (reward) => reward.createdAtHeight)); + return mergeObjects( + getRewardsById(liveTransfers).data ?? {}, + getRewardsById(restTransfers).data ?? {}, + (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! + ); +} diff --git a/src/abacus-ts/calculators/fills.ts b/src/abacus-ts/calculators/fills.ts new file mode 100644 index 000000000..ae2fb76ca --- /dev/null +++ b/src/abacus-ts/calculators/fills.ts @@ -0,0 +1,21 @@ +import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual'; +import { keyBy, maxBy } from 'lodash'; + +import { MustBigNumber } from '@/lib/numbers'; + +import { Loadable } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; +import { mergeObjects } from '../lib/mergeObjects'; + +function calculateFills( + liveFills: Loadable, + restFills: Loadable +) { + const getFillsById = (data: Loadable) => + mapLoadableData(data, (d) => keyBy(d, (fill) => fill.id ?? '')); + return mergeObjects( + getFillsById(liveFills).data ?? {}, + getFillsById(restFills).data ?? {}, + (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! + ); +} diff --git a/src/abacus-ts/calculators/transfers.ts b/src/abacus-ts/calculators/transfers.ts new file mode 100644 index 000000000..af4b86b7c --- /dev/null +++ b/src/abacus-ts/calculators/transfers.ts @@ -0,0 +1,21 @@ +import { IndexerTransferResponseObject } from '@/types/indexer/indexerApiGen'; +import { keyBy, maxBy } from 'lodash'; + +import { MustBigNumber } from '@/lib/numbers'; + +import { Loadable } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; +import { mergeObjects } from '../lib/mergeObjects'; + +function calculateTransfers( + liveTransfers: Loadable, + restTransfers: Loadable +) { + const getTransfersById = (data: Loadable) => + mapLoadableData(data, (d) => keyBy(d, (transfer) => transfer.id)); + return mergeObjects( + getTransfersById(liveTransfers).data ?? {}, + getTransfersById(restTransfers).data ?? {}, + (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! + ); +} diff --git a/src/abacus-ts/lib/mapLoadable.ts b/src/abacus-ts/lib/mapLoadable.ts new file mode 100644 index 000000000..b41c2e3ec --- /dev/null +++ b/src/abacus-ts/lib/mapLoadable.ts @@ -0,0 +1,8 @@ +import { Loadable } from './loadable'; + +export function mapLoadableData(load: Loadable, map: (obj: T) => R): Loadable { + return { + ...load, + data: load.data != null ? map(load.data) : undefined, + } as Loadable; +} diff --git a/src/abacus-ts/lib/mergeObjects.ts b/src/abacus-ts/lib/mergeObjects.ts new file mode 100644 index 000000000..50f40ac13 --- /dev/null +++ b/src/abacus-ts/lib/mergeObjects.ts @@ -0,0 +1,21 @@ +type SimpleMap = { [key: string]: T }; +export function mergeObjects(one: SimpleMap, two: SimpleMap, merge: (a: T, b: T) => T) { + const finalObj: SimpleMap = {}; + + [...Object.keys(one), ...Object.keys(two)].forEach((key) => { + if (finalObj[key] != null) { + return; + } + const obj = one[key]; + const otherObj = two[key]; + if (obj != null && otherObj != null) { + finalObj[key] = merge(obj, otherObj); + } else if (obj == null && otherObj == null) { + // do nothing + } else { + // we know one of them is non-null + finalObj[key] = (obj ?? otherObj)!; + } + }); + return finalObj; +} From d1e187c8aa83d088128ea1b25759fab605724c0f Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 16 Dec 2024 18:14:08 -0500 Subject: [PATCH 44/65] fix --- src/abacus-ts/calculators/blockRewards.ts | 2 +- src/abacus-ts/calculators/fills.ts | 2 +- src/abacus-ts/calculators/transfers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/abacus-ts/calculators/blockRewards.ts b/src/abacus-ts/calculators/blockRewards.ts index ff08b36ab..09c9b6e4b 100644 --- a/src/abacus-ts/calculators/blockRewards.ts +++ b/src/abacus-ts/calculators/blockRewards.ts @@ -7,7 +7,7 @@ import { Loadable } from '../lib/loadable'; import { mapLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; -function calculateBlockRewards( +export function calculateBlockRewards( liveTransfers: Loadable, restTransfers: Loadable ) { diff --git a/src/abacus-ts/calculators/fills.ts b/src/abacus-ts/calculators/fills.ts index ae2fb76ca..9818015af 100644 --- a/src/abacus-ts/calculators/fills.ts +++ b/src/abacus-ts/calculators/fills.ts @@ -7,7 +7,7 @@ import { Loadable } from '../lib/loadable'; import { mapLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; -function calculateFills( +export function calculateFills( liveFills: Loadable, restFills: Loadable ) { diff --git a/src/abacus-ts/calculators/transfers.ts b/src/abacus-ts/calculators/transfers.ts index af4b86b7c..2b99ed84b 100644 --- a/src/abacus-ts/calculators/transfers.ts +++ b/src/abacus-ts/calculators/transfers.ts @@ -7,7 +7,7 @@ import { Loadable } from '../lib/loadable'; import { mapLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; -function calculateTransfers( +export function calculateTransfers( liveTransfers: Loadable, restTransfers: Loadable ) { From 2bbe7afa7afbc6e577f77d2f55ca32ceb434ff20 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 16 Dec 2024 18:17:42 -0500 Subject: [PATCH 45/65] add validator calls --- src/abacus-ts/lib/mapLoadable.ts | 8 + src/abacus-ts/rest/height.ts | 59 +++++++ .../rest/lib/compositeClientManager.ts | 149 ++++++++++++++++++ .../rest/lib/indexerClientManager.ts | 10 -- .../rest/lib/indexerQueryStoreEffect.ts | 99 ++++++++++-- .../rest/lib/queryResultToLoadable.ts | 10 ++ src/abacus-ts/socketSelectors.ts | 15 ++ src/abacus-ts/storeLifecycles.ts | 5 + src/state/raw.ts | 39 +++++ 9 files changed, 368 insertions(+), 26 deletions(-) create mode 100644 src/abacus-ts/lib/mapLoadable.ts create mode 100644 src/abacus-ts/rest/height.ts create mode 100644 src/abacus-ts/rest/lib/compositeClientManager.ts delete mode 100644 src/abacus-ts/rest/lib/indexerClientManager.ts create mode 100644 src/abacus-ts/rest/lib/queryResultToLoadable.ts diff --git a/src/abacus-ts/lib/mapLoadable.ts b/src/abacus-ts/lib/mapLoadable.ts new file mode 100644 index 000000000..b41c2e3ec --- /dev/null +++ b/src/abacus-ts/lib/mapLoadable.ts @@ -0,0 +1,8 @@ +import { Loadable } from './loadable'; + +export function mapLoadableData(load: Loadable, map: (obj: T) => R): Loadable { + return { + ...load, + data: load.data != null ? map(load.data) : undefined, + } as Loadable; +} diff --git a/src/abacus-ts/rest/height.ts b/src/abacus-ts/rest/height.ts new file mode 100644 index 000000000..3e9ea745e --- /dev/null +++ b/src/abacus-ts/rest/height.ts @@ -0,0 +1,59 @@ +import { timeUnits } from '@/constants/time'; + +import { type RootStore } from '@/state/_store'; +import { setIndexerHeightRaw, setValidatorHeightRaw } from '@/state/raw'; + +import { loadableIdle } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; +import { + createIndexerQueryStoreEffect, + createValidatorQueryStoreEffect, +} from './lib/indexerQueryStoreEffect'; +import { queryResultToLoadable } from './lib/queryResultToLoadable'; + +export function setUpIndexerHeightQuery(store: RootStore) { + const cleanupEffect = createIndexerQueryStoreEffect(store, { + selector: () => true, + getQueryKey: () => ['height'], + getQueryFn: (indexerClient) => { + return () => indexerClient.utility.getHeight(); + }, + onResult: (height) => { + store.dispatch(setIndexerHeightRaw(queryResultToLoadable(height))); + }, + onNoQuery: () => store.dispatch(setIndexerHeightRaw(loadableIdle())), + refetchInterval: timeUnits.second * 10, + staleTime: timeUnits.second * 10, + }); + return () => { + cleanupEffect(); + store.dispatch(setIndexerHeightRaw(loadableIdle())); + }; +} + +export function setUpValidatorHeightQuery(store: RootStore) { + const cleanupEffect = createValidatorQueryStoreEffect(store, { + selector: () => true, + getQueryKey: () => ['height'], + getQueryFn: (compositeClient) => { + return () => compositeClient.validatorClient.get.latestBlock(); + }, + onResult: (height) => { + store.dispatch( + setValidatorHeightRaw( + mapLoadableData(queryResultToLoadable(height), (d) => ({ + height: d.header.height, + time: d.header.time, + })) + ) + ); + }, + onNoQuery: () => store.dispatch(setValidatorHeightRaw(loadableIdle())), + refetchInterval: timeUnits.second * 10, + staleTime: timeUnits.second * 10, + }); + return () => { + cleanupEffect(); + store.dispatch(setValidatorHeightRaw(loadableIdle())); + }; +} diff --git a/src/abacus-ts/rest/lib/compositeClientManager.ts b/src/abacus-ts/rest/lib/compositeClientManager.ts new file mode 100644 index 000000000..e0b60914e --- /dev/null +++ b/src/abacus-ts/rest/lib/compositeClientManager.ts @@ -0,0 +1,149 @@ +import { createStoreEffect } from '@/abacus-ts/lib/createStoreEffect'; +import { ResourceCacheManager } from '@/abacus-ts/lib/resourceCacheManager'; +import { + CompositeClient, + IndexerClient, + IndexerConfig, + Network, + NetworkOptimizer, + ValidatorConfig, +} from '@dydxprotocol/v4-client-js'; + +import { DEFAULT_TRANSACTION_MEMO } from '@/constants/analytics'; +import { + DydxChainId, + DydxNetwork, + ENVIRONMENT_CONFIG_MAP, + TOKEN_CONFIG_MAP, +} from '@/constants/networks'; + +import { type RootStore } from '@/state/_store'; +import { getSelectedNetwork } from '@/state/appSelectors'; +import { setNetworkStateRaw } from '@/state/raw'; + +import { getStatsigConfigAsync } from '@/lib/statsig'; + +type CompositeClientWrapper = { + dead?: boolean; + compositeClient?: CompositeClient; + indexer?: IndexerClient; + tearDown: () => void; +}; + +function makeCompositeClient({ + network, + store, +}: { + network: DydxNetwork; + store: RootStore; +}): CompositeClientWrapper { + const networkConfig = ENVIRONMENT_CONFIG_MAP[network]; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!networkConfig) { + throw new Error(`Unknown network: ${network}`); + } + const chainId = networkConfig.dydxChainId as DydxChainId; + const tokens = TOKEN_CONFIG_MAP[chainId]; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (tokens == null) { + throw new Error(`Unknown chain id: ${chainId}`); + } + + const clientWrapper: CompositeClientWrapper = { + tearDown: () => { + clientWrapper.dead = true; + store.dispatch( + setNetworkStateRaw({ + networkId: network, + stateToMerge: { compositeClientReady: false, indexerClientReady: false }, + }) + ); + }, + }; + + store.dispatch( + setNetworkStateRaw({ + networkId: network, + stateToMerge: { compositeClientReady: false, indexerClientReady: false }, + }) + ); + + (async () => { + const networkOptimizer = new NetworkOptimizer(); + const indexerUrl = networkConfig.endpoints.indexers[0]; + if (indexerUrl == null) { + throw new Error('No indexer urls found'); + } + const validatorUrl = await networkOptimizer.findOptimalNode( + networkConfig.endpoints.validators, + chainId + ); + if (clientWrapper.dead) { + return; + } + const indexerConfig = new IndexerConfig(indexerUrl.api, indexerUrl.socket); + clientWrapper.indexer = new IndexerClient(indexerConfig); + store.dispatch( + setNetworkStateRaw({ + networkId: network, + stateToMerge: { indexerClientReady: true }, + }) + ); + const statsigFlags = await getStatsigConfigAsync(); + const compositeClient = await CompositeClient.connect( + new Network( + chainId, + indexerConfig, + new ValidatorConfig( + validatorUrl, + chainId, + { + USDC_DENOM: tokens.usdc.denom, + USDC_DECIMALS: tokens.usdc.decimals, + USDC_GAS_DENOM: tokens.usdc.gasDenom, + CHAINTOKEN_DENOM: tokens.chain.denom, + CHAINTOKEN_DECIMALS: tokens.chain.decimals, + }, + { + broadcastPollIntervalMs: 3_000, + broadcastTimeoutMs: 60_000, + }, + DEFAULT_TRANSACTION_MEMO, + statsigFlags.ff_enable_timestamp_nonce + ) + ) + ); + // this shouldn't be necessary - can actually be false + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (clientWrapper.dead) { + return; + } + clientWrapper.compositeClient = compositeClient; + store.dispatch( + setNetworkStateRaw({ + networkId: network, + stateToMerge: { compositeClientReady: true }, + }) + ); + })(); + return clientWrapper; +} + +export const CompositeClientManager = new ResourceCacheManager({ + constructor: (config: { network: DydxNetwork; store: RootStore }) => makeCompositeClient(config), + destroyer: (instance) => { + instance.tearDown(); + }, + // store not part of serialization, assumed immutable + keySerializer: ({ network }) => network, +}); + +// this just makes things simpler +export function alwaysUseCurrentNetworkClient(store: RootStore) { + return createStoreEffect(store, getSelectedNetwork, (network) => { + CompositeClientManager.use({ network, store }); + return () => { + CompositeClientManager.markDone({ network, store }); + }; + }); +} diff --git a/src/abacus-ts/rest/lib/indexerClientManager.ts b/src/abacus-ts/rest/lib/indexerClientManager.ts deleted file mode 100644 index a0bd54fde..000000000 --- a/src/abacus-ts/rest/lib/indexerClientManager.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IndexerClient, IndexerConfig } from '@dydxprotocol/v4-client-js'; - -import { ResourceCacheManager } from '../../lib/resourceCacheManager'; - -export const IndexerClientManager = new ResourceCacheManager({ - constructor: ({ wsUrl, url }: { url: string; wsUrl: string }) => - new IndexerClient(new IndexerConfig(url, wsUrl)), - destroyer: () => null, - keySerializer: ({ url, wsUrl }) => `${url}/////////${wsUrl}`, -}); diff --git a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts index 22783a72b..b345a7e2d 100644 --- a/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts +++ b/src/abacus-ts/rest/lib/indexerQueryStoreEffect.ts @@ -1,16 +1,17 @@ import { logAbacusTsError } from '@/abacus-ts/logs'; -import { IndexerClient } from '@dydxprotocol/v4-client-js'; +import { selectCompositeClientReady, selectIndexerReady } from '@/abacus-ts/socketSelectors'; +import { CompositeClient, IndexerClient } from '@dydxprotocol/v4-client-js'; import { QueryObserver, QueryObserverOptions, QueryObserverResult } from '@tanstack/react-query'; import { timeUnits } from '@/constants/time'; import { type RootState, type RootStore } from '@/state/_store'; import { appQueryClient } from '@/state/appQueryClient'; +import { getSelectedNetwork } from '@/state/appSelectors'; import { createAppSelector } from '@/state/appTypes'; import { createStoreEffect } from '../../lib/createStoreEffect'; -import { selectIndexerUrl, selectWebsocketUrl } from '../../socketSelectors'; -import { IndexerClientManager } from './indexerClientManager'; +import { CompositeClientManager } from './compositeClientManager'; type PassedQueryOptions = Pick< QueryObserverOptions, @@ -23,10 +24,10 @@ type PassedQueryOptions = Pick< | 'refetchOnMount' >; -type QuerySetupConfig = { +type QuerySetupConfig = { selector: (state: RootState) => T; getQueryKey: (selectorResult: NoInfer) => any[]; - getQueryFn: (client: IndexerClient, selectorResult: NoInfer) => (() => Promise) | null; + getQueryFn: (client: ClientType, selectorResult: NoInfer) => (() => Promise) | null; onResult: (result: NoInfer>) => void; onNoQuery: () => void; } & PassedQueryOptions; @@ -38,12 +39,12 @@ const baseOptions: PassedQueryOptions = { export function createIndexerQueryStoreEffect( store: RootStore, - config: QuerySetupConfig + config: QuerySetupConfig ) { const fullSelector = createAppSelector( - [selectWebsocketUrl, selectIndexerUrl, config.selector], - (wsUrl, indexerUrl, selectorResult) => ({ - infrastructure: { wsUrl, indexerUrl }, + [getSelectedNetwork, selectIndexerReady, config.selector], + (network, indexerReady, selectorResult) => ({ + infrastructure: { network, indexerReady }, queryData: selectorResult, }) ); @@ -51,15 +52,20 @@ export function createIndexerQueryStoreEffect( return createStoreEffect(store, fullSelector, (fullResult) => { const { infrastructure, queryData } = fullResult; - const indexerClientConfig = { - url: infrastructure.indexerUrl, - wsUrl: infrastructure.wsUrl, + if (!infrastructure.indexerReady) { + config.onNoQuery(); + return undefined; + } + + const clientConfig = { + network: infrastructure.network, + store, }; - const indexerClient = IndexerClientManager.use(indexerClientConfig); + const indexerClient = CompositeClientManager.use(clientConfig).indexer!; const queryFn = config.getQueryFn(indexerClient, queryData); if (!queryFn) { - IndexerClientManager.markDone(indexerClientConfig); + CompositeClientManager.markDone(clientConfig); config.onNoQuery(); return undefined; } @@ -67,7 +73,7 @@ export function createIndexerQueryStoreEffect( // eslint-disable-next-line @typescript-eslint/no-unused-vars const { selector, getQueryKey, getQueryFn, onResult, ...otherOpts } = config; const observer = new QueryObserver(appQueryClient, { - queryKey: ['indexer', ...config.getQueryKey(queryData), indexerClientConfig], + queryKey: ['indexer', ...config.getQueryKey(queryData), clientConfig.network], queryFn, ...baseOptions, ...otherOpts, @@ -88,7 +94,68 @@ export function createIndexerQueryStoreEffect( return () => { unsubscribe(); - IndexerClientManager.markDone(indexerClientConfig); + CompositeClientManager.markDone(clientConfig); + }; + }); +} + +export function createValidatorQueryStoreEffect( + store: RootStore, + config: QuerySetupConfig +) { + const fullSelector = createAppSelector( + [getSelectedNetwork, selectCompositeClientReady, config.selector], + (network, compositeClientReady, selectorResult) => ({ + infrastructure: { network, compositeClientReady }, + queryData: selectorResult, + }) + ); + + return createStoreEffect(store, fullSelector, (fullResult) => { + const { infrastructure, queryData } = fullResult; + + if (!infrastructure.compositeClientReady) { + config.onNoQuery(); + return undefined; + } + const clientConfig = { + network: infrastructure.network, + store, + }; + const compositeClient = CompositeClientManager.use(clientConfig).compositeClient!; + + const queryFn = config.getQueryFn(compositeClient, queryData); + if (!queryFn) { + CompositeClientManager.markDone(clientConfig); + config.onNoQuery(); + return undefined; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { selector, getQueryKey, getQueryFn, onResult, ...otherOpts } = config; + const observer = new QueryObserver(appQueryClient, { + queryKey: ['validator', ...config.getQueryKey(queryData), clientConfig.network], + queryFn, + ...baseOptions, + ...otherOpts, + }); + + const unsubscribe = observer.subscribe((result) => { + try { + config.onResult(result); + } catch (e) { + logAbacusTsError( + 'ValidatorQueryStoreEffect', + 'Error handling result from react query store effect', + e, + result + ); + } + }); + + return () => { + unsubscribe(); + CompositeClientManager.markDone(clientConfig); }; }); } diff --git a/src/abacus-ts/rest/lib/queryResultToLoadable.ts b/src/abacus-ts/rest/lib/queryResultToLoadable.ts new file mode 100644 index 000000000..59ace962c --- /dev/null +++ b/src/abacus-ts/rest/lib/queryResultToLoadable.ts @@ -0,0 +1,10 @@ +import { Loadable } from '@/abacus-ts/lib/loadable'; +import { QueryObserverResult } from '@tanstack/react-query'; + +export function queryResultToLoadable(arg: QueryObserverResult): Loadable { + return { + status: arg.status, + data: arg.data, + error: arg.error, + } as Loadable; +} diff --git a/src/abacus-ts/socketSelectors.ts b/src/abacus-ts/socketSelectors.ts index 2cc5da442..36e72193a 100644 --- a/src/abacus-ts/socketSelectors.ts +++ b/src/abacus-ts/socketSelectors.ts @@ -2,6 +2,7 @@ import { ENVIRONMENT_CONFIG_MAP } from '@/constants/networks'; import { EndpointsConfig } from '@/hooks/useEndpointsConfig'; +import { type RootState } from '@/state/_store'; import { getUserSubaccountNumber, getUserWalletAddress } from '@/state/accountSelectors'; import { getSelectedNetwork } from '@/state/appSelectors'; import { createAppSelector } from '@/state/appTypes'; @@ -21,3 +22,17 @@ export const selectParentSubaccountInfo = createAppSelector( [getUserWalletAddress, getUserSubaccountNumber], (wallet, subaccount) => ({ wallet, subaccount }) ); + +export const selectIndexerReady = createAppSelector( + [getSelectedNetwork, (state: RootState) => state.raw.network], + (network, networks) => { + return !!networks[network]?.indexerClientReady; + } +); + +export const selectCompositeClientReady = createAppSelector( + [getSelectedNetwork, (state: RootState) => state.raw.network], + (network, networks) => { + return !!networks[network]?.compositeClientReady; + } +); diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index 92e86673b..426d09338 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -1,5 +1,7 @@ import { setUpBlockTradingRewardsQuery } from './rest/blockTradingRewards'; import { setUpFillsQuery } from './rest/fills'; +import { setUpIndexerHeightQuery, setUpValidatorHeightQuery } from './rest/height'; +import { alwaysUseCurrentNetworkClient } from './rest/lib/compositeClientManager'; import { setUpOrdersQuery } from './rest/orders'; import { setUpTransfersQuery } from './rest/transfers'; import { setUpMarkets } from './websocket/markets'; @@ -7,6 +9,7 @@ import { setUpOrderbook } from './websocket/orderbook'; import { setUpParentSubaccount } from './websocket/parentSubaccount'; export const storeLifecycles = [ + alwaysUseCurrentNetworkClient, setUpMarkets, setUpParentSubaccount, setUpFillsQuery, @@ -14,4 +17,6 @@ export const storeLifecycles = [ setUpTransfersQuery, setUpBlockTradingRewardsQuery, setUpOrderbook, + setUpIndexerHeightQuery, + setUpValidatorHeightQuery, ] as const; diff --git a/src/state/raw.ts b/src/state/raw.ts index a514699f7..863db2c76 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -8,8 +8,16 @@ import { IndexerCompositeFillResponse, IndexerCompositeOrderObject, } from '@/types/indexer/indexerManual'; +import { HeightResponse } from '@dydxprotocol/v4-client-js'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { DydxNetwork } from '@/constants/networks'; + +interface NetworkState { + indexerClientReady: boolean; + compositeClientReady: boolean; +} + export interface RawDataState { markets: { allMarkets: Loadable; @@ -22,6 +30,13 @@ export interface RawDataState { transfers: Loadable; blockTradingRewards: Loadable; }; + network: { + [networkId: string]: NetworkState; + }; + heights: { + indexerHeight: Loadable; + validatorHeight: Loadable; + }; } const initialState: RawDataState = { @@ -33,6 +48,11 @@ const initialState: RawDataState = { transfers: loadableIdle(), blockTradingRewards: loadableIdle(), }, + network: {}, + heights: { + indexerHeight: loadableIdle(), + validatorHeight: loadableIdle(), + }, }; export const rawSlice = createSlice({ @@ -72,6 +92,22 @@ export const rawSlice = createSlice({ ) => { state.account.orders = action.payload; }, + setNetworkStateRaw: ( + state, + action: PayloadAction<{ networkId: DydxNetwork; stateToMerge: Partial }> + ) => { + const { networkId, stateToMerge } = action.payload; + state.network[networkId] = { + ...(state.network[networkId] ?? { compositeClientReady: false, indexerClientReady: false }), + ...stateToMerge, + }; + }, + setIndexerHeightRaw: (state, action: PayloadAction>) => { + state.heights.indexerHeight = action.payload; + }, + setValidatorHeightRaw: (state, action: PayloadAction>) => { + state.heights.validatorHeight = action.payload; + }, }, }); @@ -83,4 +119,7 @@ export const { setAccountOrdersRaw, setAccountTransfersRaw, setAccountBlockTradingRewardsRaw, + setNetworkStateRaw, + setIndexerHeightRaw, + setValidatorHeightRaw, } = rawSlice.actions; From 488299386a530fc04a7f4a45e882e5ad165409f3 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 16 Dec 2024 19:26:01 -0500 Subject: [PATCH 46/65] fix order calcs --- src/abacus-ts/calculators/orders.ts | 144 ++++++++++++++++++------ src/abacus-ts/calculators/subaccount.ts | 33 +++--- src/abacus-ts/lib/mapLoadable.ts | 12 ++ src/abacus-ts/summaryTypes.ts | 35 +++--- src/types/indexer/indexerManual.ts | 16 +-- 5 files changed, 164 insertions(+), 76 deletions(-) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts index c1dd7807f..02902fb8d 100644 --- a/src/abacus-ts/calculators/orders.ts +++ b/src/abacus-ts/calculators/orders.ts @@ -1,47 +1,87 @@ import { IndexerBestEffortOpenedStatus, IndexerOrderStatus } from '@/types/indexer/indexerApiGen'; import { IndexerCompositeOrderObject } from '@/types/indexer/indexerManual'; -import { maxBy, pickBy } from 'lodash'; - -import { SubaccountOrder } from '@/constants/abacus'; +import { HeightResponse } from '@dydxprotocol/v4-client-js'; +import { mapValues, maxBy, pickBy } from 'lodash'; import { assertNever } from '@/lib/assertNever'; -import { MustBigNumber } from '@/lib/numbers'; +import { getDisplayableTickerFromMarket } from '@/lib/assetUtils'; +import { mapIfPresent } from '@/lib/do'; +import { MaybeBigNumber, MustBigNumber } from '@/lib/numbers'; import { Loadable } from '../lib/loadable'; -import { mapLoadableData } from '../lib/mapLoadable'; +import { mapLoadableData, mergeLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; import { OrdersData } from '../rawTypes'; -import { OrderStatus } from '../summaryTypes'; - -// todo these are calculating the same thing twice pasically -function calculateOpenOrders(liveOrders: Loadable, restOrders: Loadable) { - const getOpenOrders = (data: Loadable) => - mapLoadableData(data, (d) => - pickBy( - d, - (order) => - getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) === OrderStatus.Open - ) - ); - return calculateMergedOrders(getOpenOrders(liveOrders), getOpenOrders(restOrders)); +import { OrderStatus, SubaccountOrder, SubaccountOrdersData } from '../summaryTypes'; + +export function calculateOpenOrders(orders: Loadable) { + return mapLoadableData(orders, (d) => + pickBy( + d, + (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) === OrderStatus.Open + ) + ); +} + +export function calculateOrderHistory(orders: Loadable) { + return mapLoadableData(orders, (d) => + pickBy( + d, + (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) !== OrderStatus.Open + ) + ); } -function calculateOrderHistory(liveOrders: Loadable, restOrders: Loadable) { - const getNonOpenOrders = (data: Loadable) => - mapLoadableData(data, (d) => - pickBy( - d, - (order) => - getSimpleOrderStatus(calculateOrderStatus(order) ?? OrderStatus.Open) !== OrderStatus.Open - ) - ); - return calculateMergedOrders(getNonOpenOrders(liveOrders), getNonOpenOrders(restOrders)); +export function calculateAllOrders( + liveOrders: Loadable, + restOrders: Loadable, + height: HeightResponse +): Loadable { + const merged = mergeLoadableData(liveOrders, restOrders); + const actuallyMerged = mapLoadableData(merged, ([a, b]) => + calculateMergedOrders(a ?? {}, b ?? {}) + ); + const mapped = mapLoadableData(actuallyMerged, (d) => + mapValues(d, (order) => calculateSubaccountOrder(order, height)) + ); + return mapped; } function calculateSubaccountOrder( - order: IndexerCompositeOrderObject, - protocolHeight: number -): SubaccountOrder {} + base: IndexerCompositeOrderObject, + protocolHeight: HeightResponse +): SubaccountOrder { + let order: SubaccountOrder = { + marketId: base.ticker, + status: calculateBaseOrderStatus(base), + displayId: getDisplayableTickerFromMarket(base.ticker), + expiresAtMilliseconds: mapIfPresent(base.goodTilBlockTime, (u) => new Date(u).valueOf()), + updatedAtMilliseconds: mapIfPresent(base.updatedAt, (u) => new Date(u).valueOf()), + updatedAtHeight: MaybeBigNumber(base.updatedAtHeight)?.toNumber(), + marginMode: undefined, + subaccountNumber: base.subaccountNumber, + id: base.id, + clientId: base.clientId, + type: base.type, + side: base.side, + timeInForce: base.timeInForce, + clobPairId: MaybeBigNumber(base.clobPairId)?.toNumber(), + orderFlags: base.orderFlags, + price: MustBigNumber(base.price), + triggerPrice: MaybeBigNumber(base.triggerPrice), + size: MustBigNumber(base.size), + totalFilled: MustBigNumber(base.totalFilled), + goodTilBlock: MaybeBigNumber(base.goodTilBlock)?.toNumber(), + goodTilBlockTime: mapIfPresent(base.goodTilBlockTime, (u) => new Date(u).valueOf()), + createdAtHeight: MaybeBigNumber(base.createdAtHeight)?.toNumber(), + postOnly: !!base.postOnly, + reduceOnly: !!base.reduceOnly, + remainingSize: MustBigNumber(base.size).minus(MustBigNumber(base.totalFilled)), + removalReason: base.removalReason, + }; + order = maybeUpdateOrderIfExpired(order, protocolHeight); + return order; +} function getSimpleOrderStatus(status: OrderStatus) { switch (status) { @@ -63,6 +103,44 @@ function getSimpleOrderStatus(status: OrderStatus) { } } +function maybeUpdateOrderIfExpired( + order: SubaccountOrder, + height: HeightResponse +): SubaccountOrder { + if (order.status == null) { + return order; + } + // todo: why not handle Open? + if ( + ![OrderStatus.Pending, OrderStatus.Canceling, OrderStatus.PartiallyFilled].includes( + order.status + ) + ) { + return order; + } + + // Check if order has expired based on goodTilBlock + if (order.goodTilBlock && order.goodTilBlock !== 0 && height.height >= order.goodTilBlock) { + let status = OrderStatus.Canceled; + + // Check for partial fills + if (order.totalFilled != null && order.totalFilled.gt(0)) { + const remainingSize = order.size.minus(order.totalFilled); + if (order.totalFilled.gt(0) && remainingSize.gt(0)) { + status = OrderStatus.PartiallyCanceled; + } + } + + return { + ...order, + status, + updatedAtMilliseconds: new Date(height.time).valueOf(), + }; + } + + return order; +} + function calculateBaseOrderStatus(order: IndexerCompositeOrderObject): OrderStatus | undefined { const status = order.status; if (status == null) { @@ -118,9 +196,7 @@ function calculateBaseOrderStatus(order: IndexerCompositeOrderObject): OrderStat } } -function calculateMergedOrders(liveOrders: Loadable, restOrders: Loadable) { - const liveData = liveOrders.data ?? {}; - const restData = restOrders.data ?? {}; +function calculateMergedOrders(liveData: OrdersData, restData: OrdersData) { return mergeObjects( liveData, restData, diff --git a/src/abacus-ts/calculators/subaccount.ts b/src/abacus-ts/calculators/subaccount.ts index 190ee7a9a..98e5a7c2a 100644 --- a/src/abacus-ts/calculators/subaccount.ts +++ b/src/abacus-ts/calculators/subaccount.ts @@ -10,7 +10,7 @@ import { mapValues } from 'lodash'; import { NUM_PARENT_SUBACCOUNTS } from '@/constants/account'; import { calc } from '@/lib/do'; -import { MaybeBigNumber, MustBigNumber, ToBigNumber } from '@/lib/numbers'; +import { BIG_NUMBERS, MaybeBigNumber, MustBigNumber, ToBigNumber } from '@/lib/numbers'; import { isPresent } from '@/lib/typeUtils'; import { ChildSubaccountData, MarketsData, ParentSubaccountData } from '../rawTypes'; @@ -25,9 +25,6 @@ import { SubaccountSummaryDerived, } from '../summaryTypes'; -const BN_0 = MustBigNumber(0); -const BN_1 = MustBigNumber(1); - export function calculateParentSubaccountPositions( parent: Omit, markets: MarketsData @@ -61,7 +58,7 @@ export function calculateParentSubaccountSummary( equity: Object.values(summaries) .filter(isPresent) .map((s) => s.equity) - .reduce((a, b) => a.plus(b), BN_0), + .reduce((a, b) => a.plus(b), BIG_NUMBERS.ZERO), }; } @@ -82,7 +79,7 @@ function calculateSubaccountSummaryCore( ): SubaccountSummaryCore { const quoteBalance = calc(() => { const usdcPosition = subaccountData.assetPositions.USDC; - if (!usdcPosition?.size) return BN_0; + if (!usdcPosition?.size) return BIG_NUMBERS.ZERO; const size = MustBigNumber(usdcPosition.size); return usdcPosition.side === IndexerPositionSide.LONG ? size : size.negated(); @@ -111,10 +108,10 @@ function calculateSubaccountSummaryCore( }; }, { - valueTotal: BN_0, - notionalTotal: BN_0, - initialRiskTotal: BN_0, - maintenanceRiskTotal: BN_0, + valueTotal: BIG_NUMBERS.ZERO, + notionalTotal: BIG_NUMBERS.ZERO, + initialRiskTotal: BIG_NUMBERS.ZERO, + maintenanceRiskTotal: BIG_NUMBERS.ZERO, } ); @@ -138,7 +135,7 @@ function calculateSubaccountSummaryDerived(core: SubaccountSummaryCore): Subacco if (equity.gt(0)) { leverage = notionalTotal.div(equity); - marginUsage = BN_1.minus(freeCollateral.div(equity)); + marginUsage = BIG_NUMBERS.ONE.minus(freeCollateral.div(equity)); } return { @@ -185,12 +182,14 @@ function calculateDerivedPositionCore( ): SubaccountPositionDerivedCore { const marginMode = position.subaccountNumber < NUM_PARENT_SUBACCOUNTS ? 'CROSS' : 'ISOLATED'; const effectiveImf = - market != null ? getMarketEffectiveInitialMarginForMarket(market) ?? BN_0 : BN_0; - const effectiveMmf = MaybeBigNumber(market?.maintenanceMarginFraction) ?? BN_0; + market != null + ? getMarketEffectiveInitialMarginForMarket(market) ?? BIG_NUMBERS.ZERO + : BIG_NUMBERS.ZERO; + const effectiveMmf = MaybeBigNumber(market?.maintenanceMarginFraction) ?? BIG_NUMBERS.ZERO; // indexer position size is already signed I think but we will be extra sure const unsignedSize = position.size.abs(); - const oracle = MaybeBigNumber(market?.oraclePrice) ?? BN_0; + const oracle = MaybeBigNumber(market?.oraclePrice) ?? BIG_NUMBERS.ZERO; const signedSize = position.side === IndexerPositionSide.SHORT ? unsignedSize.negated() : unsignedSize; @@ -211,7 +210,7 @@ function calculateDerivedPositionCore( if (effectiveImf.isZero()) { return null; } - return BN_1.div(effectiveImf); + return BIG_NUMBERS.ONE.div(effectiveImf); }), baseEntryPrice: position.entryPrice, baseNetFunding: position.netFunding, @@ -254,7 +253,9 @@ function calculatePositionDerivedExtra( const entryValue = signedSize.multipliedBy(MustBigNumber(position.baseEntryPrice)); const unrealizedPnlInner = value.minus(entryValue).plus(MustBigNumber(position.baseNetFunding)); - const scaledLeverage = leverage ? BigNumber.max(leverage.abs(), BN_1) : BN_1; + const scaledLeverage = leverage + ? BigNumber.max(leverage.abs(), BIG_NUMBERS.ONE) + : BIG_NUMBERS.ONE; const unrealizedPnlPercentInner = !entryValue.isZero() ? unrealizedPnlInner.dividedBy(entryValue.abs()).multipliedBy(scaledLeverage) diff --git a/src/abacus-ts/lib/mapLoadable.ts b/src/abacus-ts/lib/mapLoadable.ts index b41c2e3ec..a47479fbc 100644 --- a/src/abacus-ts/lib/mapLoadable.ts +++ b/src/abacus-ts/lib/mapLoadable.ts @@ -6,3 +6,15 @@ export function mapLoadableData(load: Loadable, map: (obj: T) => R): Lo data: load.data != null ? map(load.data) : undefined, } as Loadable; } + +export function mergeLoadableData( + one: Loadable, + two: Loadable +): Loadable<[T | undefined, R | undefined]> { + const priority = ['pending', 'error', 'success', 'idle'] as const; + return { + status: priority[Math.min(priority.indexOf(one.status), priority.indexOf(two.status))]!, + error: (one as any).error ?? (two as any).error ?? undefined, + data: [one.data, two.data], + } as any; +} diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index 7af08164a..aecfa86c1 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -102,30 +102,29 @@ export enum OrderStatus { export type SubaccountOrder = { subaccountNumber: number; id: string; - clientId: string | null; + clientId: string | undefined; type: IndexerOrderType; side: IndexerOrderSide; - status: OrderStatus; - timeInForce: IndexerAPITimeInForce | null; + status: OrderStatus | undefined; + timeInForce: IndexerAPITimeInForce | undefined; marketId: string; displayId: string; - clobPairId: number | null; - orderFlags: string | null; + clobPairId: number | undefined; + orderFlags: string | undefined; price: BigNumber; - triggerPrice: BigNumber | null; - trailingPercent: BigNumber | null; + triggerPrice: BigNumber | undefined; size: BigNumber; - remainingSize: BigNumber | null; - totalFilled: BigNumber | null; - goodTilBlock: number | null; - goodTilBlockTime: number | null; - createdAtHeight: number | null; - createdAtMilliseconds: number | null; - unfillableAtMilliseconds: number | null; - expiresAtMilliseconds: number | null; - updatedAtMilliseconds: number | null; + remainingSize: BigNumber | undefined; + totalFilled: BigNumber | undefined; + goodTilBlock: number | undefined; + goodTilBlockTime: number | undefined; + createdAtHeight: number | undefined; + expiresAtMilliseconds: number | undefined; + updatedAtMilliseconds: number | undefined; + updatedAtHeight: number | undefined; postOnly: boolean; reduceOnly: boolean; - cancelReason: string | null; - marginMode: MarginMode | null; + removalReason: string | undefined; + marginMode: MarginMode | undefined; }; +export type SubaccountOrdersData = { [orderId: string]: SubaccountOrder }; diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 5592f2f50..70c1fefcd 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -25,15 +25,15 @@ export interface IndexerCompositeFillResponse { } export interface IndexerCompositeOrderObject { - id?: string; + id: string; subaccountId?: string; clientId?: string; clobPairId?: string; - side?: IndexerOrderSide; - size?: string; - totalFilled?: string; - price?: string; - type?: IndexerOrderType; + side: IndexerOrderSide; + size: string; + totalFilled: string; + price: string; + type: IndexerOrderType; reduceOnly?: boolean; orderFlags?: string; goodTilBlock?: string | null; @@ -44,10 +44,10 @@ export interface IndexerCompositeOrderObject { timeInForce?: IndexerAPITimeInForce; status?: IndexerAPIOrderStatus; postOnly?: boolean; - ticker?: string; + ticker: string; updatedAt?: IndexerIsoString | null; updatedAtHeight?: string | null; - subaccountNumber?: number; + subaccountNumber: number; removalReason?: string; totalOptimisticFilled?: string; } From 4399e36c870f2972258739984111e075ae6c1464 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 16 Dec 2024 19:31:28 -0500 Subject: [PATCH 47/65] dedupe --- pnpm-lock.yaml | 404 ++++++++++++------------------------------------- 1 file changed, 96 insertions(+), 308 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc4a752d3..33b5733bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,22 +10,22 @@ overrides: dependencies: '@cosmjs/amino': specifier: ^0.32.1 - version: 0.32.3 + version: 0.32.4 '@cosmjs/crypto': specifier: ^0.32.1 version: 0.32.4 '@cosmjs/encoding': specifier: ^0.32.1 - version: 0.32.3 + version: 0.32.4 '@cosmjs/proto-signing': specifier: ^0.32.1 - version: 0.32.3 + version: 0.32.4 '@cosmjs/stargate': specifier: ^0.32.1 - version: 0.32.3 + version: 0.32.4 '@cosmjs/tendermint-rpc': specifier: ^0.32.1 - version: 0.32.3 + version: 0.32.4 '@datadog/browser-logs': specifier: ^5.23.3 version: 5.23.3 @@ -46,7 +46,7 @@ dependencies: version: 1.3.0 '@funkit/connect': specifier: ^4.0.2 - version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2)(wagmi@2.10.9) + version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9) '@hugocxl/react-to-image': specifier: ^0.0.9 version: 0.0.9(html-to-image@1.11.11)(react@18.2.0) @@ -55,13 +55,13 @@ dependencies: version: 5.5.3 '@keplr-wallet/types': specifier: ^0.12.121 - version: 0.12.121 + version: 0.12.162(starknet@6.11.0) '@privy-io/react-auth': specifier: ^1.73.0 version: 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.7.2) '@privy-io/wagmi': specifier: ^0.2.10 - version: 0.2.10(@privy-io/react-auth@1.73.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.16.2)(wagmi@2.10.9) + version: 0.2.10(@privy-io/react-auth@1.73.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.17.0)(wagmi@2.10.9) '@radix-ui/react-accordion': specifier: ^1.1.2 version: 1.1.2(@types/react-dom@18.2.6)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0) @@ -145,13 +145,13 @@ dependencies: version: 2.2.5(react-redux@9.1.2)(react@18.2.0) '@scure/bip32': specifier: ^1.3.0 - version: 1.3.1 + version: 1.4.0 '@scure/bip39': specifier: ^1.2.0 - version: 1.2.1 + version: 1.3.0 '@skip-go/client': specifier: 0.15.5 - version: 0.15.5(@solana/web3.js@1.93.2)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(starknet@6.11.0)(viem@2.16.2) + version: 0.15.5(@solana/web3.js@1.93.2)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(starknet@6.11.0)(viem@2.17.0) '@solana/web3.js': specifier: ^1.93.0 version: 1.93.2 @@ -235,7 +235,7 @@ dependencies: version: 2.1.0 graz: specifier: ^0.1.19 - version: 0.1.19(@cosmjs/amino@0.32.3)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.3)(@cosmjs/stargate@0.32.3)(@cosmjs/tendermint-rpc@0.32.3)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.6.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0) + version: 0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0) jsdom: specifier: ^24.1.0 version: 24.1.0 @@ -304,10 +304,10 @@ dependencies: version: 1.2.1(@types/react@18.3.3)(react@18.2.0) viem: specifier: ^2.16.2 - version: 2.16.2(typescript@5.7.2) + version: 2.17.0(typescript@5.7.2) wagmi: specifier: ^2.10.7 - version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) + version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) devDependencies: '@babel/core': @@ -381,7 +381,7 @@ devDependencies: version: 8.32.4 '@wdio/types': specifier: ^8.32.4 - version: 8.32.4 + version: 8.36.1 ajv: specifier: ^8.12.0 version: 8.12.0 @@ -390,7 +390,7 @@ devDependencies: version: 2.1.0 axios: specifier: ^1.6.7 - version: 1.6.7 + version: 1.7.7 babel-loader: specifier: ^9.1.2 version: 9.1.2(@babel/core@7.23.9)(webpack@5.91.0) @@ -462,7 +462,7 @@ devDependencies: version: 8.6.6 postcss: specifier: ^8.4.39 - version: 8.4.39 + version: 8.4.49 prettier: specifier: ^3.2.5 version: 3.2.5 @@ -2749,7 +2749,7 @@ packages: engines: {node: '>=v18'} dependencies: '@commitlint/types': 19.0.3 - semver: 7.6.2 + semver: 7.6.3 dev: true /@commitlint/lint@19.0.3: @@ -2873,15 +2873,6 @@ packages: '@cosmjs/utils': 0.31.3 dev: false - /@cosmjs/amino@0.32.3: - resolution: {integrity: sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA==} - dependencies: - '@cosmjs/crypto': 0.32.4 - '@cosmjs/encoding': 0.32.4 - '@cosmjs/math': 0.32.4 - '@cosmjs/utils': 0.32.4 - dev: false - /@cosmjs/amino@0.32.4: resolution: {integrity: sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==} dependencies: @@ -2965,14 +2956,6 @@ packages: readonly-date: 1.0.0 dev: false - /@cosmjs/encoding@0.32.3: - resolution: {integrity: sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w==} - dependencies: - base64-js: 1.5.1 - bech32: 1.1.4 - readonly-date: 1.0.0 - dev: false - /@cosmjs/encoding@0.32.4: resolution: {integrity: sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw==} dependencies: @@ -3039,17 +3022,6 @@ packages: long: 4.0.0 dev: false - /@cosmjs/proto-signing@0.32.3: - resolution: {integrity: sha512-kSZ0ZUY0DwcRT0NcIn2HkadH4NKlwjfZgbLj1ABwh/4l0RgeT84QCscZCu63tJYq3K6auwqTiZSZERwlO4/nbg==} - dependencies: - '@cosmjs/amino': 0.32.4 - '@cosmjs/crypto': 0.32.4 - '@cosmjs/encoding': 0.32.4 - '@cosmjs/math': 0.32.4 - '@cosmjs/utils': 0.32.4 - cosmjs-types: 0.9.0 - dev: false - /@cosmjs/proto-signing@0.32.4: resolution: {integrity: sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==} dependencies: @@ -3106,25 +3078,6 @@ packages: - utf-8-validate dev: false - /@cosmjs/stargate@0.32.3: - resolution: {integrity: sha512-OQWzO9YWKerUinPIxrO1MARbe84XkeXJAW0lyMIjXIEikajuXZ+PwftiKA5yA+8OyditVmHVLtPud6Pjna2s5w==} - dependencies: - '@confio/ics23': 0.6.8 - '@cosmjs/amino': 0.32.4 - '@cosmjs/encoding': 0.32.4 - '@cosmjs/math': 0.32.4 - '@cosmjs/proto-signing': 0.32.4 - '@cosmjs/stream': 0.32.4 - '@cosmjs/tendermint-rpc': 0.32.4 - '@cosmjs/utils': 0.32.4 - cosmjs-types: 0.9.0 - xstream: 11.14.0 - transitivePeerDependencies: - - bufferutil - - debug - - utf-8-validate - dev: false - /@cosmjs/stargate@0.32.4: resolution: {integrity: sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==} dependencies: @@ -3175,25 +3128,6 @@ packages: - utf-8-validate dev: false - /@cosmjs/tendermint-rpc@0.32.3: - resolution: {integrity: sha512-xeprW+VR9xKGstqZg0H/KBZoUp8/FfFyS9ljIUTLM/UINjP2MhiwncANPS2KScfJVepGufUKk0/phHUeIBSEkw==} - dependencies: - '@cosmjs/crypto': 0.32.4 - '@cosmjs/encoding': 0.32.4 - '@cosmjs/json-rpc': 0.32.4 - '@cosmjs/math': 0.32.4 - '@cosmjs/socket': 0.32.4 - '@cosmjs/stream': 0.32.4 - '@cosmjs/utils': 0.32.4 - axios: 1.7.7 - readonly-date: 1.0.0 - xstream: 11.14.0 - transitivePeerDependencies: - - bufferutil - - debug - - utf-8-validate - dev: false - /@cosmjs/tendermint-rpc@0.32.4: resolution: {integrity: sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==} dependencies: @@ -3240,14 +3174,14 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.9 - /@dao-dao/cosmiframe@0.1.0(@cosmjs/amino@0.32.3)(@cosmjs/proto-signing@0.32.3): + /@dao-dao/cosmiframe@0.1.0(@cosmjs/amino@0.32.4)(@cosmjs/proto-signing@0.32.4): resolution: {integrity: sha512-NW4pGt1ctqDfhn/A6RU2vwnFEu3O4aBNnBMrGnw31n+L35drYNEsA9ZB7KZsHmRRlkNx+jSuJSv2Fv0BFBDDJQ==} peerDependencies: '@cosmjs/amino': '>= ^0.32' '@cosmjs/proto-signing': '>= ^0.32' dependencies: - '@cosmjs/amino': 0.32.3 - '@cosmjs/proto-signing': 0.32.3 + '@cosmjs/amino': 0.32.4 + '@cosmjs/proto-signing': 0.32.4 uuid: 9.0.1 dev: false @@ -4461,7 +4395,7 @@ packages: big.js: 6.2.2 dev: false - /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2)(wagmi@2.10.9): + /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9): resolution: {integrity: sha512-aLUZD34S1MIl5k//UdNkhq+lbKoZkJG7Rk8wHpONFCzj3x7pYKDZyv82E1E3GnZsc50+4ONz05c1PL79HXg0vA==} engines: {node: '>=18'} peerDependencies: @@ -4484,7 +4418,7 @@ packages: '@vanilla-extract/css': 1.15.3(babel-plugin-macros@3.1.0) '@vanilla-extract/dynamic': 2.1.0 '@vanilla-extract/sprinkles': 1.6.1(@vanilla-extract/css@1.15.3) - '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) + '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) bech32: 2.0.0 clsx: 2.1.1 qrcode: 1.5.3 @@ -4494,8 +4428,8 @@ packages: react-virtuoso: 4.10.1(react-dom@18.2.0)(react@18.2.0) ua-parser-js: 1.0.37 uuid: 9.0.1 - viem: 2.16.2(typescript@5.7.2) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) + viem: 2.17.0(typescript@5.7.2) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) transitivePeerDependencies: - '@datadog/browser-rum' - '@ethersproject/address' @@ -5008,10 +4942,6 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - /@jridgewell/sourcemap-codec@1.5.0: resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -5235,12 +5165,12 @@ packages: - typescript dev: true - /@leapwallet/cosmos-social-login-capsule-provider@0.0.39(@cosmjs/encoding@0.32.3)(@cosmjs/proto-signing@0.32.3)(fp-ts@2.16.8): + /@leapwallet/cosmos-social-login-capsule-provider@0.0.39(@cosmjs/encoding@0.32.4)(@cosmjs/proto-signing@0.32.4)(fp-ts@2.16.8): resolution: {integrity: sha512-7u9ZhiBHK7MeCNFNcnN4ttS11LITL5P6NtBwZ331MppAsGqRkexJQq6fofDZIiGaKiBqAp4qsFKEVM0fohOZBA==} dependencies: '@cosmjs/amino': 0.31.3 '@leapwallet/cosmos-social-login-core': 0.0.1 - '@usecapsule/cosmjs-v0-integration': 1.10.0(@cosmjs/amino@0.31.3)(@cosmjs/encoding@0.32.3)(@cosmjs/proto-signing@0.32.3)(fp-ts@2.16.8) + '@usecapsule/cosmjs-v0-integration': 1.10.0(@cosmjs/amino@0.31.3)(@cosmjs/encoding@0.32.4)(@cosmjs/proto-signing@0.32.4)(fp-ts@2.16.8) '@usecapsule/web-sdk': 1.12.0(fp-ts@2.16.8) long: 5.2.3 transitivePeerDependencies: @@ -5593,7 +5523,7 @@ packages: dependencies: '@types/debug': 4.1.12 debug: 4.3.4(supports-color@5.5.0) - semver: 7.6.2 + semver: 7.6.3 superstruct: 1.0.4 transitivePeerDependencies: - supports-color @@ -5606,7 +5536,7 @@ packages: '@ethereumjs/tx': 4.2.0 '@types/debug': 4.1.12 debug: 4.3.4(supports-color@5.5.0) - semver: 7.6.2 + semver: 7.6.3 superstruct: 1.0.4 transitivePeerDependencies: - supports-color @@ -5622,7 +5552,7 @@ packages: '@types/debug': 4.1.12 debug: 4.3.4(supports-color@5.5.0) pony-cause: 2.1.10 - semver: 7.6.2 + semver: 7.6.3 superstruct: 1.0.4 uuid: 9.0.1 transitivePeerDependencies: @@ -6315,7 +6245,7 @@ packages: - utf-8-validate dev: false - /@privy-io/wagmi@0.2.10(@privy-io/react-auth@1.73.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.16.2)(wagmi@2.10.9): + /@privy-io/wagmi@0.2.10(@privy-io/react-auth@1.73.1)(react-dom@18.2.0)(react@18.2.0)(viem@2.17.0)(wagmi@2.10.9): resolution: {integrity: sha512-tU8ZMuLaGasvct8KmYpL/oPyvwiLh5n3FA2Se39BhGxKCK/OcFDGu1VxHdkc1WCx0DB0DCNNZJeJTimCke5Xpw==} peerDependencies: '@privy-io/react-auth': ^1.64.1 @@ -6327,8 +6257,8 @@ packages: '@privy-io/react-auth': 1.73.1(@babel/core@7.23.9)(@types/react@18.3.3)(react-dom@18.2.0)(react-is@18.3.1)(react@18.2.0)(typescript@5.7.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - viem: 2.16.2(typescript@5.7.2) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) + viem: 2.17.0(typescript@5.7.2) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) dev: false /@promptbook/utils@0.50.0-10: @@ -9412,9 +9342,9 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.3(rollup@2.79.1) + '@rollup/pluginutils': 5.1.3(rollup@2.79.1) estree-walker: 2.0.2 - magic-string: 0.30.8 + magic-string: 0.30.14 rollup: 2.79.1 dev: true @@ -9430,21 +9360,6 @@ packages: rollup: 2.79.1 dev: true - /@rollup/pluginutils@5.0.3(rollup@2.79.1): - resolution: {integrity: sha512-hfllNN4a80rwNQ9QCxhxuHCGHMAvabXqxNdaChUSSadMre7t4iEUI6fFAhBOn/eIYTgYVhBv7vCLsAJ4u3lf3g==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - rollup: 2.79.1 - dev: true - /@rollup/pluginutils@5.1.3(rollup@2.79.1): resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} engines: {node: '>=14.0.0'} @@ -9832,7 +9747,7 @@ packages: '@sinonjs/commons': 3.0.1 dev: false - /@skip-go/client@0.15.5(@solana/web3.js@1.93.2)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(starknet@6.11.0)(viem@2.16.2): + /@skip-go/client@0.15.5(@solana/web3.js@1.93.2)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0)(starknet@6.11.0)(viem@2.17.0): resolution: {integrity: sha512-BYTCO/SSYhXJjzChVwPge/U2TctxGd8g3JSN0HNbLVkUnj3g5bXvsOL+WB/bQQ0D/4K+1tVQVJs3r98HDxzCxw==} peerDependencies: '@solana/web3.js': ^1.95.8 @@ -9854,7 +9769,7 @@ packages: cosmjs-types: 0.9.0 create-hash: 1.2.0 keccak: 3.0.4 - viem: 2.16.2(typescript@5.7.2) + viem: 2.17.0(typescript@5.7.2) transitivePeerDependencies: - '@types/react' - bufferutil @@ -10773,15 +10688,15 @@ packages: resolution: {integrity: sha512-P5XgYoAw/vfW65byBbJQCw+cagdXDT/qH6wmABiLt4v4YBT2q2vqCOhihe+D1Nt325F/S/0Tkv6C5z0Lv+VBQQ==} dev: false - /@terra-money/station-connector@1.1.4(@cosmjs/amino@0.32.3)(axios@1.6.7): + /@terra-money/station-connector@1.1.4(@cosmjs/amino@0.32.4)(axios@1.7.7): resolution: {integrity: sha512-0xQ1haSJnY6ltjhptFoVa1yhNUIBsbCAEQCUukSY93GSo6tt+DN4RAku9i1ulfY/UizXnxH/mn+6aJyTCZGGcg==} engines: {node: '>=16'} peerDependencies: '@cosmjs/amino': ^0.31.0 axios: ^0.27.2 dependencies: - '@cosmjs/amino': 0.32.3 - axios: 1.6.7 + '@cosmjs/amino': 0.32.4 + axios: 1.7.7 bech32: 2.0.0 dev: false @@ -11015,10 +10930,6 @@ packages: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: true - /@types/estree@1.0.5: - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: true - /@types/estree@1.0.6: resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} dev: true @@ -11287,7 +11198,7 @@ packages: graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.7.2) typescript: 5.7.2 transitivePeerDependencies: @@ -11363,7 +11274,7 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.7.2) typescript: 5.7.2 transitivePeerDependencies: @@ -11383,7 +11294,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) eslint: 8.57.0 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -11537,7 +11448,7 @@ packages: - fp-ts dev: false - /@usecapsule/cosmjs-v0-integration@1.10.0(@cosmjs/amino@0.31.3)(@cosmjs/encoding@0.32.3)(@cosmjs/proto-signing@0.32.3)(fp-ts@2.16.8): + /@usecapsule/cosmjs-v0-integration@1.10.0(@cosmjs/amino@0.31.3)(@cosmjs/encoding@0.32.4)(@cosmjs/proto-signing@0.32.4)(fp-ts@2.16.8): resolution: {integrity: sha512-T/BXzJ61oAjDu5rs16FxdepUvTZ8e+Af3risRJR2kbdRzSqVAUPXRhfCS4DqdrVAP3bN8UtVzFopQFkHm1kVwQ==} peerDependencies: '@cosmjs/amino': '>= 0.31.3 < 1' @@ -11545,8 +11456,8 @@ packages: '@cosmjs/proto-signing': '>= 0.31.3 < 1' dependencies: '@cosmjs/amino': 0.31.3 - '@cosmjs/encoding': 0.32.3 - '@cosmjs/proto-signing': 0.32.3 + '@cosmjs/encoding': 0.32.4 + '@cosmjs/proto-signing': 0.32.4 '@usecapsule/core-sdk': 1.10.0(fp-ts@2.16.8) transitivePeerDependencies: - debug @@ -11590,7 +11501,7 @@ packages: deepmerge: 4.3.1 media-query-parser: 2.0.2 modern-ahocorasick: 1.0.1 - picocolors: 1.0.1 + picocolors: 1.1.1 transitivePeerDependencies: - babel-plugin-macros dev: false @@ -11964,8 +11875,8 @@ packages: /@vitest/snapshot@1.4.0: resolution: {integrity: sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==} dependencies: - magic-string: 0.30.8 - pathe: 1.1.1 + magic-string: 0.30.14 + pathe: 1.1.2 pretty-format: 29.7.0 dev: true @@ -11984,7 +11895,7 @@ packages: pretty-format: 29.7.0 dev: true - /@wagmi/connectors@5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2): + /@wagmi/connectors@5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-lbjXEv6HhOa9nXZ5r6NGFJdaadCt2Yj9hSWHjKuiTobrE6dEGQqG16mCQS17yXcvXpI62Q/sW6SL347JrBju/Q==} peerDependencies: '@wagmi/core': 2.11.6 @@ -11998,12 +11909,12 @@ packages: '@metamask/sdk': 0.26.4(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1) '@safe-global/safe-apps-provider': 0.18.1(typescript@5.7.2) '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.7.2) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) '@walletconnect/ethereum-provider': 2.13.0(@types/react@18.3.3)(react@18.2.0) '@walletconnect/modal': 2.6.2(@types/react@18.3.3)(react@18.2.0) cbw-sdk: /@coinbase/wallet-sdk@3.9.3 typescript: 5.7.2 - viem: 2.16.2(typescript@5.7.2) + viem: 2.17.0(typescript@5.7.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -12029,7 +11940,7 @@ packages: - zod dev: false - /@wagmi/core@2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2): + /@wagmi/core@2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-Ohk7Bh+Q8kjzxEHImIq98CnPduz8n1a5bdwJi6F7zU3h62crhlVq7fZBYoBhoDgmX0ROVOMr8WW3XU3XhRwUOw==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -12044,7 +11955,7 @@ packages: eventemitter3: 5.0.1 mipd: 0.0.5(typescript@5.7.2) typescript: 5.7.2 - viem: 2.16.2(typescript@5.7.2) + viem: 2.17.0(typescript@5.7.2) zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) transitivePeerDependencies: - '@types/react' @@ -12055,29 +11966,6 @@ packages: - zod dev: false - /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2): - resolution: {integrity: sha512-bX84cpLq3WWQgGthJlSgcWPAOdLzrP/W0jnbz5XowkCUn6j/T77WyxN5pBb+HmLoJf3ei9tkX9zWhMpczTc3cA==} - peerDependencies: - '@tanstack/query-core': '>=5.0.0' - typescript: '>=5.0.4' - viem: 2.x - peerDependenciesMeta: - '@tanstack/query-core': - optional: true - typescript: - optional: true - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.7.2) - typescript: 5.7.2 - viem: 2.16.2(typescript@5.7.2) - zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) - transitivePeerDependencies: - - '@types/react' - - immer - - react - dev: false - /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-bX84cpLq3WWQgGthJlSgcWPAOdLzrP/W0jnbz5XowkCUn6j/T77WyxN5pBb+HmLoJf3ei9tkX9zWhMpczTc3cA==} peerDependencies: @@ -13240,20 +13128,6 @@ packages: typescript: 5.7.2 dev: false - /abitype@1.0.4(typescript@5.7.2): - resolution: {integrity: sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - dependencies: - typescript: 5.7.2 - dev: false - /abitype@1.0.5(typescript@5.7.2): resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} peerDependencies: @@ -13294,14 +13168,6 @@ packages: acorn: 8.14.0 dev: true - /acorn-jsx@5.3.2(acorn@8.11.3): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.11.3 - dev: true - /acorn-jsx@5.3.2(acorn@8.14.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -13314,12 +13180,7 @@ packages: resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} engines: {node: '>=0.4.0'} dependencies: - acorn: 8.11.3 - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true + acorn: 8.14.0 /acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} @@ -13815,15 +13676,6 @@ packages: - debug dev: false - /axios@1.6.7: - resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} - dependencies: - follow-redirects: 1.15.3(debug@4.3.4) - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - /axios@1.7.7: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} dependencies: @@ -13832,7 +13684,6 @@ packages: proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - dev: false /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} @@ -14383,7 +14234,7 @@ packages: /builtins@5.1.0: resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} dependencies: - semver: 7.6.2 + semver: 7.6.3 dev: true /bundle-name@3.0.0: @@ -16391,7 +16242,7 @@ packages: eslint: '>=6.0.0' dependencies: eslint: 8.57.0 - semver: 7.6.2 + semver: 7.6.3 dev: true /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): @@ -16643,7 +16494,7 @@ packages: is-core-module: 2.13.1 minimatch: 3.1.2 resolve: 1.22.8 - semver: 7.6.2 + semver: 7.6.3 dev: true /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): @@ -16736,6 +16587,7 @@ packages: /eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) @@ -16794,8 +16646,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 3.4.3 dev: true @@ -18042,7 +17894,7 @@ packages: resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - /graz@0.1.19(@cosmjs/amino@0.32.3)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.3)(@cosmjs/stargate@0.32.3)(@cosmjs/tendermint-rpc@0.32.3)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.6.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0): + /graz@0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0): resolution: {integrity: sha512-KaRQJ7HTQp3vbX/bG2Oc9T3t/KyaIuU5dLoGU2QNFirNjIpRbhkBtCll9Li5A6+zw3O9bHkbZ1aUaKfuVyBS8w==} hasBin: true peerDependencies: @@ -18055,20 +17907,20 @@ packages: '@leapwallet/cosmos-social-login-capsule-provider': ^0.0.39 react: '>=17' dependencies: - '@cosmjs/amino': 0.32.3 + '@cosmjs/amino': 0.32.4 '@cosmjs/cosmwasm-stargate': 0.32.4 '@cosmjs/launchpad': 0.27.1 - '@cosmjs/proto-signing': 0.32.3 - '@cosmjs/stargate': 0.32.3 - '@cosmjs/tendermint-rpc': 0.32.3 + '@cosmjs/proto-signing': 0.32.4 + '@cosmjs/stargate': 0.32.4 + '@cosmjs/tendermint-rpc': 0.32.4 '@cosmsnap/snapper': 0.1.31 - '@dao-dao/cosmiframe': 0.1.0(@cosmjs/amino@0.32.3)(@cosmjs/proto-signing@0.32.3) + '@dao-dao/cosmiframe': 0.1.0(@cosmjs/amino@0.32.4)(@cosmjs/proto-signing@0.32.4) '@keplr-wallet/cosmos': 0.12.121 '@keplr-wallet/types': 0.12.162(starknet@6.11.0) - '@leapwallet/cosmos-social-login-capsule-provider': 0.0.39(@cosmjs/encoding@0.32.3)(@cosmjs/proto-signing@0.32.3)(fp-ts@2.16.8) + '@leapwallet/cosmos-social-login-capsule-provider': 0.0.39(@cosmjs/encoding@0.32.4)(@cosmjs/proto-signing@0.32.4)(fp-ts@2.16.8) '@metamask/providers': 12.0.0 '@tanstack/react-query': 4.36.1(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0) - '@terra-money/station-connector': 1.1.4(@cosmjs/amino@0.32.3)(axios@1.6.7) + '@terra-money/station-connector': 1.1.4(@cosmjs/amino@0.32.4)(axios@1.7.7) '@vectis/extension-client': 0.7.2 '@walletconnect/sign-client': 2.13.3(encoding@0.1.13) '@walletconnect/types': 2.13.3 @@ -20238,7 +20090,7 @@ packages: resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} dependencies: - mlly: 1.4.2 + mlly: 1.7.3 pkg-types: 1.2.1 dev: true @@ -20512,13 +20364,6 @@ packages: '@jridgewell/sourcemap-codec': 1.5.0 dev: true - /magic-string@0.30.8: - resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -21578,15 +21423,6 @@ packages: hasBin: true dev: false - /mlly@1.4.2: - resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} - dependencies: - acorn: 8.14.0 - pathe: 1.1.2 - pkg-types: 1.2.1 - ufo: 1.5.4 - dev: true - /mlly@1.7.3: resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} dependencies: @@ -21958,7 +21794,7 @@ packages: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.13.1 - semver: 7.6.2 + semver: 7.6.3 validate-npm-package-license: 3.0.4 dev: true @@ -21968,7 +21804,7 @@ packages: dependencies: hosted-git-info: 7.0.1 is-core-module: 2.13.1 - semver: 7.6.2 + semver: 7.6.3 validate-npm-package-license: 3.0.4 dev: true @@ -22535,10 +22371,6 @@ packages: engines: {node: '>=12'} dev: true - /pathe@1.1.1: - resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} - dev: true - /pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -22585,9 +22417,6 @@ packages: is-reference: 3.0.1 dev: true - /picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -22733,27 +22562,27 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - /postcss-import@15.1.0(postcss@8.4.39): + /postcss-import@15.1.0(postcss@8.4.49): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} peerDependencies: postcss: ^8.0.0 dependencies: - postcss: 8.4.39 + postcss: 8.4.49 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - /postcss-js@4.0.1(postcss@8.4.39): + /postcss-js@4.0.1(postcss@8.4.49): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.4.21 dependencies: camelcase-css: 2.0.1 - postcss: 8.4.39 + postcss: 8.4.49 - /postcss-load-config@4.0.2(postcss@8.4.39)(ts-node@10.9.2): + /postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2): resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} peerDependencies: @@ -22766,17 +22595,17 @@ packages: optional: true dependencies: lilconfig: 3.1.2 - postcss: 8.4.39 + postcss: 8.4.49 ts-node: 10.9.2(@types/node@20.12.13)(typescript@5.7.2) yaml: 2.4.5 - /postcss-nested@6.2.0(postcss@8.4.39): + /postcss-nested@6.2.0(postcss@8.4.49): resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 dependencies: - postcss: 8.4.39 + postcss: 8.4.49 postcss-selector-parser: 6.1.1 /postcss-selector-parser@6.1.1: @@ -22797,14 +22626,6 @@ packages: picocolors: 1.1.1 source-map-js: 1.2.1 - /postcss@8.4.39: - resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - /postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -22812,7 +22633,6 @@ packages: nanoid: 3.3.7 picocolors: 1.1.1 source-map-js: 1.2.1 - dev: true /preact@10.17.0: resolution: {integrity: sha512-SNsI8cbaCcUS5tbv9nlXuCfIXnJ9ysBMWk0WnB6UWwcVA3qZ2O6FxqDFECMAMttvLQcW/HaNZUe2BLidyvrVYw==} @@ -24453,11 +24273,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - /semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - /semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -24773,10 +24588,6 @@ packages: atomic-sleep: 1.0.0 dev: false - /source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} - /source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -25298,12 +25109,12 @@ packages: micromatch: 4.0.5 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.0.1 - postcss: 8.4.39 - postcss-import: 15.1.0(postcss@8.4.39) - postcss-js: 4.0.1(postcss@8.4.39) - postcss-load-config: 4.0.2(postcss@8.4.39)(ts-node@10.9.2) - postcss-nested: 6.2.0(postcss@8.4.39) + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-import: 15.1.0(postcss@8.4.49) + postcss-js: 4.0.1(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2) + postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.1 resolve: 1.22.8 sucrase: 3.35.0 @@ -26462,29 +26273,6 @@ packages: - zod dev: false - /viem@2.16.2(typescript@5.7.2): - resolution: {integrity: sha512-qor3v1cJFR3jcPtcJxPbKfKURAH2agNf2IWZIaSReV6teNLERiu4Sr7kbqpkIeTAEpiDCVQwg336M+mub1m+pg==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 - abitype: 1.0.4(typescript@5.7.2) - isows: 1.0.4(ws@8.17.1) - typescript: 5.7.2 - ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - dev: false - /viem@2.17.0(typescript@5.7.2): resolution: {integrity: sha512-+gaVlsfDsHL1oYdjpatdRxW1WK/slLYVvpOws3fEdLfQFUToezKI6YLC9l1g2uKm4Hg3OdGX1KQy/G7/58tTKQ==} peerDependencies: @@ -26516,7 +26304,7 @@ packages: cac: 6.7.14 debug: 4.3.4(supports-color@5.5.0) pathe: 1.1.2 - picocolors: 1.0.1 + picocolors: 1.1.1 vite: 5.0.12(@types/node@20.12.13) transitivePeerDependencies: - '@types/node' @@ -26556,7 +26344,7 @@ packages: peerDependencies: vite: ^2.6.0 || 3 || 4 dependencies: - '@rollup/pluginutils': 5.0.3(rollup@2.79.1) + '@rollup/pluginutils': 5.1.3(rollup@2.79.1) '@svgr/core': 7.0.0(typescript@5.7.2) '@svgr/plugin-jsx': 7.0.0 vite: 4.3.9(@types/node@20.12.13) @@ -26610,7 +26398,7 @@ packages: dependencies: '@types/node': 20.12.13 esbuild: 0.17.19 - postcss: 8.4.39 + postcss: 8.4.49 rollup: 3.28.0 optionalDependencies: fsevents: 2.3.3 @@ -26738,9 +26526,9 @@ packages: execa: 8.0.1 jsdom: 24.1.0 local-pkg: 0.5.0 - magic-string: 0.30.8 - pathe: 1.1.1 - picocolors: 1.0.1 + magic-string: 0.30.14 + pathe: 1.1.2 + picocolors: 1.1.1 std-env: 3.6.0 strip-literal: 2.1.0 tinybench: 2.9.0 @@ -26786,7 +26574,7 @@ packages: - supports-color dev: true - /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2): + /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-pYGTLmVIAC4q/a90i+vlrkJL86n5Kf/gwhhi65XtQklpsUQWrKDmn4dsY1/yFeAmZ/1yx1mpxYpX3LI97eTuWA==} peerDependencies: '@tanstack/react-query': '>=5.0.0' @@ -26798,12 +26586,12 @@ packages: optional: true dependencies: '@tanstack/react-query': 5.37.1(react@18.2.0) - '@wagmi/connectors': 5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.16.2) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.16.2) + '@wagmi/connectors': 5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) react: 18.2.0 typescript: 5.7.2 use-sync-external-store: 1.2.0(react@18.2.0) - viem: 2.16.2(typescript@5.7.2) + viem: 2.17.0(typescript@5.7.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' From a226648815e7d97514b8b0fcce7d79b6c92c3b48 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 16 Dec 2024 20:10:24 -0500 Subject: [PATCH 48/65] fix --- src/abacus-ts/calculators/orders.ts | 4 +++- src/abacus-ts/calculators/subaccount.ts | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts index 02902fb8d..4c4b0b87b 100644 --- a/src/abacus-ts/calculators/orders.ts +++ b/src/abacus-ts/calculators/orders.ts @@ -3,6 +3,8 @@ import { IndexerCompositeOrderObject } from '@/types/indexer/indexerManual'; import { HeightResponse } from '@dydxprotocol/v4-client-js'; import { mapValues, maxBy, pickBy } from 'lodash'; +import { NUM_PARENT_SUBACCOUNTS } from '@/constants/account'; + import { assertNever } from '@/lib/assertNever'; import { getDisplayableTickerFromMarket } from '@/lib/assetUtils'; import { mapIfPresent } from '@/lib/do'; @@ -58,7 +60,7 @@ function calculateSubaccountOrder( expiresAtMilliseconds: mapIfPresent(base.goodTilBlockTime, (u) => new Date(u).valueOf()), updatedAtMilliseconds: mapIfPresent(base.updatedAt, (u) => new Date(u).valueOf()), updatedAtHeight: MaybeBigNumber(base.updatedAtHeight)?.toNumber(), - marginMode: undefined, + marginMode: base.subaccountNumber >= NUM_PARENT_SUBACCOUNTS ? 'ISOLATED' : 'CROSS', subaccountNumber: base.subaccountNumber, id: base.id, clientId: base.clientId, diff --git a/src/abacus-ts/calculators/subaccount.ts b/src/abacus-ts/calculators/subaccount.ts index 98e5a7c2a..48ddaaae2 100644 --- a/src/abacus-ts/calculators/subaccount.ts +++ b/src/abacus-ts/calculators/subaccount.ts @@ -62,7 +62,15 @@ export function calculateParentSubaccountSummary( }; } -export function calculateSubaccountSummary( +export function calculateMarketsNeededForSubaccount( + parent: Omit +) { + return Object.values(parent.childSubaccounts).flatMap((o) => + Object.values(o?.openPerpetualPositions ?? {}).map((p) => p.market) + ); +} + +function calculateSubaccountSummary( subaccountData: ChildSubaccountData, markets: MarketsData ): SubaccountSummary { From 684de6bd7ad5ad8dd3d2632fe4fcc2d153733b3b Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 10:22:10 -0500 Subject: [PATCH 49/65] fix --- src/abacus-ts/storeLifecycles.ts | 2 ++ src/state/raw.ts | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/abacus-ts/storeLifecycles.ts b/src/abacus-ts/storeLifecycles.ts index 426d09338..42a357abb 100644 --- a/src/abacus-ts/storeLifecycles.ts +++ b/src/abacus-ts/storeLifecycles.ts @@ -1,3 +1,4 @@ +import { setUpAssetsQuery } from './rest/assets'; import { setUpBlockTradingRewardsQuery } from './rest/blockTradingRewards'; import { setUpFillsQuery } from './rest/fills'; import { setUpIndexerHeightQuery, setUpValidatorHeightQuery } from './rest/height'; @@ -11,6 +12,7 @@ import { setUpParentSubaccount } from './websocket/parentSubaccount'; export const storeLifecycles = [ alwaysUseCurrentNetworkClient, setUpMarkets, + setUpAssetsQuery, setUpParentSubaccount, setUpFillsQuery, setUpOrdersQuery, diff --git a/src/state/raw.ts b/src/state/raw.ts index 863db2c76..1cdce1d49 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -11,6 +11,7 @@ import { import { HeightResponse } from '@dydxprotocol/v4-client-js'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { MetadataServiceInfoResponse } from '@/constants/assetMetadata'; import { DydxNetwork } from '@/constants/networks'; interface NetworkState { @@ -21,6 +22,7 @@ interface NetworkState { export interface RawDataState { markets: { allMarkets: Loadable; + assets: Loadable; orderbooks: { [marketId: string]: Loadable }; }; account: { @@ -40,7 +42,7 @@ export interface RawDataState { } const initialState: RawDataState = { - markets: { allMarkets: loadableIdle(), orderbooks: {} }, + markets: { allMarkets: loadableIdle(), assets: loadableIdle(), orderbooks: {} }, account: { parentSubaccount: loadableIdle(), fills: loadableIdle(), @@ -62,6 +64,9 @@ export const rawSlice = createSlice({ setAllMarketsRaw: (state, action: PayloadAction>) => { state.markets.allMarkets = action.payload; }, + setAllAssetsRaw: (state, action: PayloadAction>) => { + state.markets.assets = action.payload; + }, setOrderbookRaw: ( state, action: PayloadAction<{ marketId: string; data: Loadable }> @@ -114,6 +119,7 @@ export const rawSlice = createSlice({ export const { setOrderbookRaw, setAllMarketsRaw, + setAllAssetsRaw, setParentSubaccountRaw, setAccountFillsRaw, setAccountOrdersRaw, From 5fbe0764046cc129af97e6f29caa2745d274f935 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 10:23:56 -0500 Subject: [PATCH 50/65] add --- src/abacus-ts/rest/assets.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/abacus-ts/rest/assets.ts diff --git a/src/abacus-ts/rest/assets.ts b/src/abacus-ts/rest/assets.ts new file mode 100644 index 000000000..6ac96ba20 --- /dev/null +++ b/src/abacus-ts/rest/assets.ts @@ -0,0 +1,34 @@ +import { QueryObserver } from '@tanstack/react-query'; + +import { timeUnits } from '@/constants/time'; + +import { type RootStore } from '@/state/_store'; +import { appQueryClient } from '@/state/appQueryClient'; +import { setAllAssetsRaw } from '@/state/raw'; + +import metadataClient from '@/clients/metadataService'; + +import { loadableIdle } from '../lib/loadable'; +import { logAbacusTsError } from '../logs'; +import { queryResultToLoadable } from './lib/queryResultToLoadable'; + +export function setUpAssetsQuery(store: RootStore) { + const observer = new QueryObserver(appQueryClient, { + queryKey: ['metadata', 'assets'], + queryFn: () => metadataClient.getAssetInfo(), + refetchInterval: timeUnits.minute * 5, + staleTime: timeUnits.minute * 5, + }); + + const unsubscribe = observer.subscribe((result) => { + try { + store.dispatch(setAllAssetsRaw(queryResultToLoadable(result))); + } catch (e) { + logAbacusTsError('setUpAssetsQuery', 'Error handling result from react query', e, result); + } + }); + return () => { + unsubscribe(); + store.dispatch(setAllAssetsRaw(loadableIdle())); + }; +} From 517bd47d188d3c0ddc14b3ab06560c5fd7f0ed41 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 10:25:51 -0500 Subject: [PATCH 51/65] fix --- src/abacus-ts/calculators/orders.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts index 4c4b0b87b..b64436344 100644 --- a/src/abacus-ts/calculators/orders.ts +++ b/src/abacus-ts/calculators/orders.ts @@ -137,6 +137,7 @@ function maybeUpdateOrderIfExpired( ...order, status, updatedAtMilliseconds: new Date(height.time).valueOf(), + updatedAtHeight: height.height, }; } From c8684967fb5cdce33ea7e2e12903e84270904c2a Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 11:37:41 -0500 Subject: [PATCH 52/65] fix --- src/abacus-ts/selectors/account.ts | 56 ++++++++++++++++++++ src/abacus-ts/selectors/base.ts | 13 +++-- src/views/AccountInfo/AccountInfoSection.tsx | 2 + 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/abacus-ts/selectors/account.ts b/src/abacus-ts/selectors/account.ts index e69de29bb..8331f8712 100644 --- a/src/abacus-ts/selectors/account.ts +++ b/src/abacus-ts/selectors/account.ts @@ -0,0 +1,56 @@ +import { pick } from 'lodash'; +import { shallowEqual } from 'react-redux'; + +import { createAppSelector } from '@/state/appTypes'; + +import { + calculateMarketsNeededForSubaccount, + calculateParentSubaccountPositions, + calculateParentSubaccountSummary, +} from '../calculators/subaccount'; +import { selectRawMarketsData, selectRawParentSubaccountData } from './base'; + +const selectRelevantMarketsList = createAppSelector( + [selectRawParentSubaccountData], + (parentSubaccount) => { + if (parentSubaccount == null) { + return undefined; + } + return calculateMarketsNeededForSubaccount(parentSubaccount); + } +); + +const selectRelevantMarketsData = createAppSelector( + [selectRelevantMarketsList, selectRawMarketsData], + (marketIds, markets) => { + if (markets == null || marketIds == null) { + return undefined; + } + return pick(markets, ...marketIds); + }, + { + // use shallow equal for result so that we only update when these specific keys differ + memoizeOptions: { resultEqualityCheck: shallowEqual }, + } +); + +export const selectParentSubaccountSummary = createAppSelector( + [selectRawParentSubaccountData, selectRelevantMarketsData], + (parentSubaccount, markets) => { + if (parentSubaccount == null || markets == null) { + return undefined; + } + const result = calculateParentSubaccountSummary(parentSubaccount, markets); + return result; + } +); + +export const selectParentSubaccountPositions = createAppSelector( + [selectRawParentSubaccountData, selectRelevantMarketsData], + (parentSubaccount, markets) => { + if (parentSubaccount == null || markets == null) { + return undefined; + } + return calculateParentSubaccountPositions(parentSubaccount, markets); + } +); diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts index f925855b1..157c5a480 100644 --- a/src/abacus-ts/selectors/base.ts +++ b/src/abacus-ts/selectors/base.ts @@ -5,11 +5,14 @@ export const selectRawState = (state: RootState) => state.raw; export const selectRawAccountState = (state: RootState) => state.raw.account; export const selectRawMarketsState = (state: RootState) => state.raw.markets.allMarkets; +export const selectRawMarketsData = (state: RootState) => state.raw.markets.allMarkets.data; -export const selectParentSubaccountData = (state: RootState) => +export const selectRawParentSubaccount = (state: RootState) => state.raw.account.parentSubaccount; +export const selectRawParentSubaccountData = (state: RootState) => state.raw.account.parentSubaccount.data; -export const selectFillsData = (state: RootState) => state.raw.account.fills.data; -export const selectOrdersData = (state: RootState) => state.raw.account.orders.data; -export const selectTransfersData = (state: RootState) => state.raw.account.transfers.data; -export const selectBlockTradingRewardsData = (state: RootState) => + +export const selectRawFillsData = (state: RootState) => state.raw.account.fills.data; +export const selectRawOrdersData = (state: RootState) => state.raw.account.orders.data; +export const selectRawTransfersData = (state: RootState) => state.raw.account.transfers.data; +export const selectRawBlockTradingRewardsData = (state: RootState) => state.raw.account.blockTradingRewards.data; diff --git a/src/views/AccountInfo/AccountInfoSection.tsx b/src/views/AccountInfo/AccountInfoSection.tsx index cf8962d3e..367bbee67 100644 --- a/src/views/AccountInfo/AccountInfoSection.tsx +++ b/src/views/AccountInfo/AccountInfoSection.tsx @@ -1,3 +1,4 @@ +import { selectParentSubaccountSummary } from '@/abacus-ts/selectors/account'; import { shallowEqual } from 'react-redux'; import styled, { css } from 'styled-components'; @@ -54,6 +55,7 @@ export const AccountInfoSection = () => { const { complianceState } = useComplianceState(); const { dydxAccounts } = useAccounts(); + const otherSubaccount = useAppSelector(selectParentSubaccountSummary); const subAccount = useAppSelector(getSubaccount, shallowEqual); const isLoading = useAppSelector(calculateIsAccountLoading); From d628fd065a1643c6871231125fa3e4b28c2fb2cc Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 11:41:59 -0500 Subject: [PATCH 53/65] fix --- src/views/AccountInfo/AccountInfoSection.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/views/AccountInfo/AccountInfoSection.tsx b/src/views/AccountInfo/AccountInfoSection.tsx index 367bbee67..cf8962d3e 100644 --- a/src/views/AccountInfo/AccountInfoSection.tsx +++ b/src/views/AccountInfo/AccountInfoSection.tsx @@ -1,4 +1,3 @@ -import { selectParentSubaccountSummary } from '@/abacus-ts/selectors/account'; import { shallowEqual } from 'react-redux'; import styled, { css } from 'styled-components'; @@ -55,7 +54,6 @@ export const AccountInfoSection = () => { const { complianceState } = useComplianceState(); const { dydxAccounts } = useAccounts(); - const otherSubaccount = useAppSelector(selectParentSubaccountSummary); const subAccount = useAppSelector(getSubaccount, shallowEqual); const isLoading = useAppSelector(calculateIsAccountLoading); From 1a9928cfd3c8a394e4fe0f05eb0a976e40b62b62 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 12:02:21 -0500 Subject: [PATCH 54/65] fix --- src/abacus-ts/calculators/orders.ts | 37 +++++++++---------------- src/abacus-ts/selectors/account.ts | 43 ++++++++++++++++++++++++++++- src/abacus-ts/selectors/base.ts | 21 +++++++++++--- 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/abacus-ts/calculators/orders.ts b/src/abacus-ts/calculators/orders.ts index b64436344..41bd2c655 100644 --- a/src/abacus-ts/calculators/orders.ts +++ b/src/abacus-ts/calculators/orders.ts @@ -10,42 +10,31 @@ import { getDisplayableTickerFromMarket } from '@/lib/assetUtils'; import { mapIfPresent } from '@/lib/do'; import { MaybeBigNumber, MustBigNumber } from '@/lib/numbers'; -import { Loadable } from '../lib/loadable'; -import { mapLoadableData, mergeLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; import { OrdersData } from '../rawTypes'; import { OrderStatus, SubaccountOrder, SubaccountOrdersData } from '../summaryTypes'; -export function calculateOpenOrders(orders: Loadable) { - return mapLoadableData(orders, (d) => - pickBy( - d, - (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) === OrderStatus.Open - ) +export function calculateOpenOrders(orders: SubaccountOrdersData) { + return pickBy( + orders, + (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) === OrderStatus.Open ); } -export function calculateOrderHistory(orders: Loadable) { - return mapLoadableData(orders, (d) => - pickBy( - d, - (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) !== OrderStatus.Open - ) +export function calculateOrderHistory(orders: SubaccountOrdersData) { + return pickBy( + orders, + (order) => getSimpleOrderStatus(order.status ?? OrderStatus.Open) !== OrderStatus.Open ); } export function calculateAllOrders( - liveOrders: Loadable, - restOrders: Loadable, + liveOrders: OrdersData | undefined, + restOrders: OrdersData | undefined, height: HeightResponse -): Loadable { - const merged = mergeLoadableData(liveOrders, restOrders); - const actuallyMerged = mapLoadableData(merged, ([a, b]) => - calculateMergedOrders(a ?? {}, b ?? {}) - ); - const mapped = mapLoadableData(actuallyMerged, (d) => - mapValues(d, (order) => calculateSubaccountOrder(order, height)) - ); +): SubaccountOrdersData { + const actuallyMerged = calculateMergedOrders(liveOrders ?? {}, restOrders ?? {}); + const mapped = mapValues(actuallyMerged, (order) => calculateSubaccountOrder(order, height)); return mapped; } diff --git a/src/abacus-ts/selectors/account.ts b/src/abacus-ts/selectors/account.ts index 8331f8712..9f3fae3e5 100644 --- a/src/abacus-ts/selectors/account.ts +++ b/src/abacus-ts/selectors/account.ts @@ -1,14 +1,27 @@ +import { IndexerPerpetualPositionStatus } from '@/types/indexer/indexerApiGen'; import { pick } from 'lodash'; import { shallowEqual } from 'react-redux'; import { createAppSelector } from '@/state/appTypes'; +import { + calculateAllOrders, + calculateOpenOrders, + calculateOrderHistory, +} from '../calculators/orders'; import { calculateMarketsNeededForSubaccount, calculateParentSubaccountPositions, calculateParentSubaccountSummary, } from '../calculators/subaccount'; -import { selectRawMarketsData, selectRawParentSubaccountData } from './base'; +import { + selectRawIndexerHeight, + selectRawMarketsData, + selectRawOrdersLiveData, + selectRawOrdersRestData, + selectRawParentSubaccountData, + selectRawValidatorHeight, +} from './base'; const selectRelevantMarketsList = createAppSelector( [selectRawParentSubaccountData], @@ -54,3 +67,31 @@ export const selectParentSubaccountPositions = createAppSelector( return calculateParentSubaccountPositions(parentSubaccount, markets); } ); + +export const selectParentSubaccountOpenPositions = createAppSelector( + [selectParentSubaccountPositions], + (positions) => { + return positions?.filter((p) => p.status === IndexerPerpetualPositionStatus.OPEN); + } +); + +const baseTime = { height: 0, time: '1971-01-01T00:00:00Z' }; +export const selectAccountOrders = createAppSelector( + [ + selectRawOrdersRestData, + selectRawOrdersLiveData, + selectRawValidatorHeight, + selectRawIndexerHeight, + ], + (rest, live, indexerHeight, validatorHeight) => { + return calculateAllOrders(rest, live, validatorHeight ?? indexerHeight ?? baseTime); + } +); + +export const selectOpenOrders = createAppSelector([selectAccountOrders], (orders) => { + return calculateOpenOrders(orders); +}); + +export const selectOrderHistory = createAppSelector([selectAccountOrders], (orders) => { + return calculateOrderHistory(orders); +}); diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts index 157c5a480..182ec13d5 100644 --- a/src/abacus-ts/selectors/base.ts +++ b/src/abacus-ts/selectors/base.ts @@ -11,8 +11,21 @@ export const selectRawParentSubaccount = (state: RootState) => state.raw.account export const selectRawParentSubaccountData = (state: RootState) => state.raw.account.parentSubaccount.data; -export const selectRawFillsData = (state: RootState) => state.raw.account.fills.data; -export const selectRawOrdersData = (state: RootState) => state.raw.account.orders.data; -export const selectRawTransfersData = (state: RootState) => state.raw.account.transfers.data; -export const selectRawBlockTradingRewardsData = (state: RootState) => +export const selectRawFillsRestData = (state: RootState) => state.raw.account.fills.data; +export const selectRawOrdersRestData = (state: RootState) => state.raw.account.orders.data; +export const selectRawTransfersRestData = (state: RootState) => state.raw.account.transfers.data; +export const selectRawBlockTradingRewardsRestData = (state: RootState) => state.raw.account.blockTradingRewards.data; + +export const selectRawFillsLiveData = (state: RootState) => + state.raw.account.parentSubaccount.data?.ephemeral.fills; +export const selectRawOrdersLiveData = (state: RootState) => + state.raw.account.parentSubaccount.data?.ephemeral.orders; +export const selectRawTransfersLiveData = (state: RootState) => + state.raw.account.parentSubaccount.data?.ephemeral.transfers; +export const selectRawBlockTradingRewardsLiveData = (state: RootState) => + state.raw.account.parentSubaccount.data?.ephemeral.tradingRewards; + +export const selectRawIndexerHeight = (state: RootState) => state.raw.heights.indexerHeight.data; +export const selectRawValidatorHeight = (state: RootState) => + state.raw.heights.validatorHeight.data; From 6e2dff3452aac5c8e5812d840623d55ba84ff119 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 12:21:34 -0500 Subject: [PATCH 55/65] fix --- src/abacus-ts/calculators/fills.ts | 15 ++++--- src/abacus-ts/calculators/transfers.ts | 16 +++---- src/abacus-ts/lib/mapLoadable.ts | 16 +++++++ src/abacus-ts/selectors/account.ts | 58 +++++++++++++++++++++++++- src/abacus-ts/selectors/base.ts | 16 +++++-- 5 files changed, 100 insertions(+), 21 deletions(-) diff --git a/src/abacus-ts/calculators/fills.ts b/src/abacus-ts/calculators/fills.ts index 9818015af..88fbc68e8 100644 --- a/src/abacus-ts/calculators/fills.ts +++ b/src/abacus-ts/calculators/fills.ts @@ -1,21 +1,20 @@ import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual'; import { keyBy, maxBy } from 'lodash'; +import { EMPTY_ARR } from '@/constants/objects'; + import { MustBigNumber } from '@/lib/numbers'; -import { Loadable } from '../lib/loadable'; -import { mapLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; export function calculateFills( - liveFills: Loadable, - restFills: Loadable + liveFills: IndexerCompositeFillObject[] | undefined, + restFills: IndexerCompositeFillObject[] | undefined ) { - const getFillsById = (data: Loadable) => - mapLoadableData(data, (d) => keyBy(d, (fill) => fill.id ?? '')); + const getFillsById = (data: IndexerCompositeFillObject[]) => keyBy(data, (fill) => fill.id ?? ''); return mergeObjects( - getFillsById(liveFills).data ?? {}, - getFillsById(restFills).data ?? {}, + getFillsById(liveFills ?? EMPTY_ARR), + getFillsById(restFills ?? EMPTY_ARR), (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! ); } diff --git a/src/abacus-ts/calculators/transfers.ts b/src/abacus-ts/calculators/transfers.ts index 2b99ed84b..1fac414b0 100644 --- a/src/abacus-ts/calculators/transfers.ts +++ b/src/abacus-ts/calculators/transfers.ts @@ -1,21 +1,21 @@ import { IndexerTransferResponseObject } from '@/types/indexer/indexerApiGen'; import { keyBy, maxBy } from 'lodash'; +import { EMPTY_ARR } from '@/constants/objects'; + import { MustBigNumber } from '@/lib/numbers'; -import { Loadable } from '../lib/loadable'; -import { mapLoadableData } from '../lib/mapLoadable'; import { mergeObjects } from '../lib/mergeObjects'; export function calculateTransfers( - liveTransfers: Loadable, - restTransfers: Loadable + liveTransfers: IndexerTransferResponseObject[] | undefined, + restTransfers: IndexerTransferResponseObject[] | undefined ) { - const getTransfersById = (data: Loadable) => - mapLoadableData(data, (d) => keyBy(d, (transfer) => transfer.id)); + const getTransfersById = (data: IndexerTransferResponseObject[]) => + keyBy(data, (transfer) => transfer.id); return mergeObjects( - getTransfersById(liveTransfers).data ?? {}, - getTransfersById(restTransfers).data ?? {}, + getTransfersById(liveTransfers ?? EMPTY_ARR), + getTransfersById(restTransfers ?? EMPTY_ARR), (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! ); } diff --git a/src/abacus-ts/lib/mapLoadable.ts b/src/abacus-ts/lib/mapLoadable.ts index a47479fbc..27cdfa162 100644 --- a/src/abacus-ts/lib/mapLoadable.ts +++ b/src/abacus-ts/lib/mapLoadable.ts @@ -18,3 +18,19 @@ export function mergeLoadableData( data: [one.data, two.data], } as any; } + +// converts idle to pending and if a status has valid data is counts as success +export function mergeLoadableStatus( + ...status: Array> +): Exclude['status'], 'idle'> { + if (status.some((s) => s.status === 'error' && s.data == null)) { + return 'error'; + } + if (status.some((s) => s.status === 'idle')) { + return 'pending'; + } + if (status.some((s) => s.status === 'pending' && s.data == null)) { + return 'pending'; + } + return 'success'; +} diff --git a/src/abacus-ts/selectors/account.ts b/src/abacus-ts/selectors/account.ts index 9f3fae3e5..527eef9ac 100644 --- a/src/abacus-ts/selectors/account.ts +++ b/src/abacus-ts/selectors/account.ts @@ -4,6 +4,7 @@ import { shallowEqual } from 'react-redux'; import { createAppSelector } from '@/state/appTypes'; +import { calculateFills } from '../calculators/fills'; import { calculateAllOrders, calculateOpenOrders, @@ -14,13 +15,26 @@ import { calculateParentSubaccountPositions, calculateParentSubaccountSummary, } from '../calculators/subaccount'; +import { calculateTransfers } from '../calculators/transfers'; +import { mergeLoadableStatus } from '../lib/mapLoadable'; import { + selectRawFillsLiveData, + selectRawFillsRest, + selectRawFillsRestData, selectRawIndexerHeight, + selectRawIndexerHeightData, + selectRawMarkets, selectRawMarketsData, selectRawOrdersLiveData, + selectRawOrdersRest, selectRawOrdersRestData, + selectRawParentSubaccount, selectRawParentSubaccountData, + selectRawTransfersLiveData, + selectRawTransfersRest, + selectRawTransfersRestData, selectRawValidatorHeight, + selectRawValidatorHeightData, } from './base'; const selectRelevantMarketsList = createAppSelector( @@ -68,20 +82,26 @@ export const selectParentSubaccountPositions = createAppSelector( } ); +export const selectParentSubaccountSummaryLoading = createAppSelector( + [selectRawParentSubaccount, selectRawMarkets], + mergeLoadableStatus +); + export const selectParentSubaccountOpenPositions = createAppSelector( [selectParentSubaccountPositions], (positions) => { return positions?.filter((p) => p.status === IndexerPerpetualPositionStatus.OPEN); } ); +export const selectParentSubaccountOpenPositionsLoading = selectParentSubaccountSummaryLoading; const baseTime = { height: 0, time: '1971-01-01T00:00:00Z' }; export const selectAccountOrders = createAppSelector( [ selectRawOrdersRestData, selectRawOrdersLiveData, - selectRawValidatorHeight, - selectRawIndexerHeight, + selectRawValidatorHeightData, + selectRawIndexerHeightData, ], (rest, live, indexerHeight, validatorHeight) => { return calculateAllOrders(rest, live, validatorHeight ?? indexerHeight ?? baseTime); @@ -95,3 +115,37 @@ export const selectOpenOrders = createAppSelector([selectAccountOrders], (orders export const selectOrderHistory = createAppSelector([selectAccountOrders], (orders) => { return calculateOrderHistory(orders); }); + +export const selectAccountOrdersLoading = createAppSelector( + [ + selectRawOrdersRest, + selectRawParentSubaccount, + selectRawValidatorHeight, + selectRawIndexerHeight, + ], + mergeLoadableStatus +); + +export const selectAccountFills = createAppSelector( + [selectRawFillsRestData, selectRawFillsLiveData], + (rest, live) => { + return calculateFills(rest?.fills, live); + } +); + +export const selectAccountFillsLoading = createAppSelector( + [selectRawFillsRest, selectRawParentSubaccount], + mergeLoadableStatus +); + +export const selectAccountTransfers = createAppSelector( + [selectRawTransfersRestData, selectRawTransfersLiveData], + (rest, live) => { + return calculateTransfers(rest?.transfers, live); + } +); + +export const selectAccountTransfersLoading = createAppSelector( + [selectRawTransfersRest, selectRawParentSubaccount], + mergeLoadableStatus +); diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts index 182ec13d5..dd99e7b46 100644 --- a/src/abacus-ts/selectors/base.ts +++ b/src/abacus-ts/selectors/base.ts @@ -4,7 +4,7 @@ export const selectRawState = (state: RootState) => state.raw; export const selectRawAccountState = (state: RootState) => state.raw.account; -export const selectRawMarketsState = (state: RootState) => state.raw.markets.allMarkets; +export const selectRawMarkets = (state: RootState) => state.raw.markets.allMarkets; export const selectRawMarketsData = (state: RootState) => state.raw.markets.allMarkets.data; export const selectRawParentSubaccount = (state: RootState) => state.raw.account.parentSubaccount; @@ -26,6 +26,16 @@ export const selectRawTransfersLiveData = (state: RootState) => export const selectRawBlockTradingRewardsLiveData = (state: RootState) => state.raw.account.parentSubaccount.data?.ephemeral.tradingRewards; -export const selectRawIndexerHeight = (state: RootState) => state.raw.heights.indexerHeight.data; -export const selectRawValidatorHeight = (state: RootState) => +export const selectRawIndexerHeightData = (state: RootState) => + state.raw.heights.indexerHeight.data; +export const selectRawValidatorHeightData = (state: RootState) => state.raw.heights.validatorHeight.data; + +export const selectRawFillsRest = (state: RootState) => state.raw.account.fills; +export const selectRawOrdersRest = (state: RootState) => state.raw.account.orders; +export const selectRawTransfersRest = (state: RootState) => state.raw.account.transfers; +export const selectRawBlockTradingRewardsRest = (state: RootState) => + state.raw.account.blockTradingRewards; + +export const selectRawIndexerHeight = (state: RootState) => state.raw.heights.indexerHeight; +export const selectRawValidatorHeight = (state: RootState) => state.raw.heights.validatorHeight; From 3f023311717c2cca6b7b8c2dc8072c8611a6a436 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 16:07:56 -0500 Subject: [PATCH 56/65] fix --- src/abacus-ts/selectors/base.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/abacus-ts/selectors/base.ts b/src/abacus-ts/selectors/base.ts index dd99e7b46..22ac21179 100644 --- a/src/abacus-ts/selectors/base.ts +++ b/src/abacus-ts/selectors/base.ts @@ -6,6 +6,7 @@ export const selectRawAccountState = (state: RootState) => state.raw.account; export const selectRawMarkets = (state: RootState) => state.raw.markets.allMarkets; export const selectRawMarketsData = (state: RootState) => state.raw.markets.allMarkets.data; +export const selectRawAssetsData = (state: RootState) => state.raw.markets.assets.data; export const selectRawParentSubaccount = (state: RootState) => state.raw.account.parentSubaccount; export const selectRawParentSubaccountData = (state: RootState) => From 2c3419d012916579b4120dcab696883722ff6cb4 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 16:12:13 -0500 Subject: [PATCH 57/65] small fix --- src/abacus-ts/calculators/subaccount.ts | 26 +++++++++++++++++-------- src/abacus-ts/summaryTypes.ts | 5 ++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/abacus-ts/calculators/subaccount.ts b/src/abacus-ts/calculators/subaccount.ts index 48ddaaae2..151d2dd24 100644 --- a/src/abacus-ts/calculators/subaccount.ts +++ b/src/abacus-ts/calculators/subaccount.ts @@ -5,10 +5,11 @@ import { IndexerPositionSide, } from '@/types/indexer/indexerApiGen'; import BigNumber from 'bignumber.js'; -import { mapValues } from 'lodash'; +import { mapValues, orderBy } from 'lodash'; import { NUM_PARENT_SUBACCOUNTS } from '@/constants/account'; +import { getAssetFromMarketId } from '@/lib/assetUtils'; import { calc } from '@/lib/do'; import { BIG_NUMBERS, MaybeBigNumber, MustBigNumber, ToBigNumber } from '@/lib/numbers'; import { isPresent } from '@/lib/typeUtils'; @@ -33,10 +34,14 @@ export function calculateParentSubaccountPositions( .filter(isPresent) .flatMap((child) => { const subaccount = calculateSubaccountSummary(child, markets); - return Object.values(child.openPerpetualPositions) - .filter(isPresent) - .filter((p) => p.status === IndexerPerpetualPositionStatus.OPEN) - .map((perp) => calculateSubaccountPosition(subaccount, perp, markets[perp.market])); + return orderBy( + Object.values(child.openPerpetualPositions) + .filter(isPresent) + .filter((p) => p.status === IndexerPerpetualPositionStatus.OPEN) + .map((perp) => calculateSubaccountPosition(subaccount, perp, markets[perp.market])), + [(f) => f.createdAt], + ['desc'] + ); }); } @@ -205,6 +210,8 @@ function calculateDerivedPositionCore( const value = signedSize.times(oracle); return { + uniqueId: `${position.market}-${position.subaccountNumber}`, + assetId: getAssetFromMarketId(position.market), marginMode, unsignedSize, signedSize, @@ -230,11 +237,13 @@ function calculatePositionDerivedExtra( subaccountSummary: SubaccountSummary ): SubaccountPositionDerivedExtra { const { equity, maintenanceRiskTotal } = subaccountSummary; - const { signedSize, notional, value, marginMode, adjustedMmf, maintenanceRisk } = position; + const { signedSize, notional, value, marginMode, adjustedMmf, adjustedImf, maintenanceRisk } = + position; const leverage = equity.gt(0) ? notional.div(equity) : null; - const marginValue = marginMode === 'ISOLATED' ? equity : notional.times(adjustedMmf); + const marginValueMaintenance = marginMode === 'ISOLATED' ? equity : notional.times(adjustedMmf); + const marginValueInitial = marginMode === 'ISOLATED' ? equity : notional.times(adjustedImf); const liquidationPrice = calc(() => { const otherPositionsRisk = maintenanceRiskTotal.minus(maintenanceRisk); @@ -273,7 +282,8 @@ function calculatePositionDerivedExtra( return { leverage, - marginValue, + marginValueMaintenance, + marginValueInitial, liquidationPrice, updatedUnrealizedPnl, updatedUnrealizedPnlPercent, diff --git a/src/abacus-ts/summaryTypes.ts b/src/abacus-ts/summaryTypes.ts index aecfa86c1..b3f257fae 100644 --- a/src/abacus-ts/summaryTypes.ts +++ b/src/abacus-ts/summaryTypes.ts @@ -55,6 +55,8 @@ export type SubaccountPositionBase = ConvertStringToBigNumber< export type MarginMode = 'ISOLATED' | 'CROSS'; export type SubaccountPositionDerivedCore = { + uniqueId: string; + assetId: string; marginMode: MarginMode; signedSize: BigNumber; // indexer size is signed by default but we make it obvious here @@ -77,7 +79,8 @@ export type SubaccountPositionDerivedCore = { export type SubaccountPositionDerivedExtra = { // all these depend on the subaccount being calculated leverage: BigNumber | null; - marginValue: BigNumber; + marginValueMaintenance: BigNumber; + marginValueInitial: BigNumber; liquidationPrice: BigNumber | null; updatedUnrealizedPnl: BigNumber; From bd867e94a8e2a04b53fe5f196d3e17a1f02a80f3 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 16:13:18 -0500 Subject: [PATCH 58/65] assets, immerjs, more changes --- package.json | 1 + pnpm-lock.yaml | 47 +++--- src/abacus-ts/rawTypes.ts | 5 + src/abacus-ts/rest/assets.ts | 10 +- src/abacus-ts/websocket/parentSubaccount.ts | 169 ++++++++++++-------- src/constants/assetMetadata.ts | 27 ++-- src/pages/trade/types.ts | 10 ++ src/state/raw.ts | 7 +- src/types/indexer/indexerManual.ts | 19 ++- 9 files changed, 185 insertions(+), 110 deletions(-) diff --git a/package.json b/package.json index b14af89fe..8665e7c7c 100644 --- a/package.json +++ b/package.json @@ -124,6 +124,7 @@ "export-to-csv": "^1.2.3", "fast-json-stable-stringify": "^2.1.0", "graz": "^0.1.19", + "immer": "^10.1.1", "jsdom": "^24.1.0", "lodash": "^4.17.21", "long": "^5.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33b5733bc..d495ac0a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ dependencies: version: 1.3.0 '@funkit/connect': specifier: ^4.0.2 - version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9) + version: 4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(immer@10.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9) '@hugocxl/react-to-image': specifier: ^0.0.9 version: 0.0.9(html-to-image@1.11.11)(react@18.2.0) @@ -235,7 +235,10 @@ dependencies: version: 2.1.0 graz: specifier: ^0.1.19 - version: 0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0) + version: 0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0) + immer: + specifier: ^10.1.1 + version: 10.1.1 jsdom: specifier: ^24.1.0 version: 24.1.0 @@ -307,7 +310,7 @@ dependencies: version: 2.17.0(typescript@5.7.2) wagmi: specifier: ^2.10.7 - version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) + version: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) devDependencies: '@babel/core': @@ -4395,7 +4398,7 @@ packages: big.js: 6.2.2 dev: false - /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9): + /@funkit/connect@4.0.2(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(babel-plugin-macros@3.1.0)(hardhat@2.22.13)(immer@10.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0)(wagmi@2.10.9): resolution: {integrity: sha512-aLUZD34S1MIl5k//UdNkhq+lbKoZkJG7Rk8wHpONFCzj3x7pYKDZyv82E1E3GnZsc50+4ONz05c1PL79HXg0vA==} engines: {node: '>=18'} peerDependencies: @@ -4409,7 +4412,7 @@ packages: '@funkit/api-base': 1.4.1 '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.7.2) '@funkit/utils': 1.0.2 - '@funkit/wagmi-tools': 3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2) + '@funkit/wagmi-tools': 3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(immer@10.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2) '@meshconnect/web-link-sdk': 2.1.1 '@moonpay/moonpay-react': 1.8.2(react@18.2.0) '@privy-io/js-sdk-core': 0.21.1 @@ -4418,7 +4421,7 @@ packages: '@vanilla-extract/css': 1.15.3(babel-plugin-macros@3.1.0) '@vanilla-extract/dynamic': 2.1.0 '@vanilla-extract/sprinkles': 1.6.1(@vanilla-extract/css@1.15.3) - '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) + '@wagmi/core': 2.13.8(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) bech32: 2.0.0 clsx: 2.1.1 qrcode: 1.5.3 @@ -4429,7 +4432,7 @@ packages: ua-parser-js: 1.0.37 uuid: 9.0.1 viem: 2.17.0(typescript@5.7.2) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) transitivePeerDependencies: - '@datadog/browser-rum' - '@ethersproject/address' @@ -4483,7 +4486,7 @@ packages: engines: {node: '>=18'} dev: false - /@funkit/wagmi-tools@3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2): + /@funkit/wagmi-tools@3.0.19(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(@types/react@18.3.3)(hardhat@2.22.13)(immer@10.1.1)(react-dom@18.2.0)(react@18.2.0)(typescript@5.7.2): resolution: {integrity: sha512-3k4df1OLkfSq5rh0J7tSXVFG3W82ux7kF8UT41pv4Lop2ZexLOkDLf6jiFhCYQ921YrMdzZCeu8Dh1DVV6Q4ZQ==} engines: {node: '>=18'} peerDependencies: @@ -4491,7 +4494,7 @@ packages: react-dom: ^18.3.0 dependencies: '@funkit/core': 2.2.8(@ethersproject/address@5.7.0)(@ethersproject/networks@5.7.1)(@ethersproject/solidity@5.7.0)(hardhat@2.22.13)(typescript@5.7.2) - '@wagmi/core': 2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) + '@wagmi/core': 2.13.8(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) viem: 2.17.0(typescript@5.7.2) @@ -6258,7 +6261,7 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) viem: 2.17.0(typescript@5.7.2) - wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) + wagmi: 2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) dev: false /@promptbook/utils@0.50.0-10: @@ -11909,7 +11912,7 @@ packages: '@metamask/sdk': 0.26.4(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1) '@safe-global/safe-apps-provider': 0.18.1(typescript@5.7.2) '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.7.2) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) '@walletconnect/ethereum-provider': 2.13.0(@types/react@18.3.3)(react@18.2.0) '@walletconnect/modal': 2.6.2(@types/react@18.3.3)(react@18.2.0) cbw-sdk: /@coinbase/wallet-sdk@3.9.3 @@ -11940,7 +11943,7 @@ packages: - zod dev: false - /@wagmi/core@2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): + /@wagmi/core@2.11.6(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-Ohk7Bh+Q8kjzxEHImIq98CnPduz8n1a5bdwJi6F7zU3h62crhlVq7fZBYoBhoDgmX0ROVOMr8WW3XU3XhRwUOw==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -11956,7 +11959,7 @@ packages: mipd: 0.0.5(typescript@5.7.2) typescript: 5.7.2 viem: 2.17.0(typescript@5.7.2) - zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) + zustand: 4.4.1(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0) transitivePeerDependencies: - '@types/react' - bufferutil @@ -11966,7 +11969,7 @@ packages: - zod dev: false - /@wagmi/core@2.13.8(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): + /@wagmi/core@2.13.8(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-bX84cpLq3WWQgGthJlSgcWPAOdLzrP/W0jnbz5XowkCUn6j/T77WyxN5pBb+HmLoJf3ei9tkX9zWhMpczTc3cA==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -11982,7 +11985,7 @@ packages: mipd: 0.0.7(typescript@5.7.2) typescript: 5.7.2 viem: 2.17.0(typescript@5.7.2) - zustand: 4.4.1(@types/react@18.3.3)(react@18.2.0) + zustand: 4.4.1(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer @@ -17894,7 +17897,7 @@ packages: resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - /graz@0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0): + /graz@0.1.19(@cosmjs/amino@0.32.4)(@cosmjs/cosmwasm-stargate@0.32.4)(@cosmjs/launchpad@0.27.1)(@cosmjs/proto-signing@0.32.4)(@cosmjs/stargate@0.32.4)(@cosmjs/tendermint-rpc@0.32.4)(@leapwallet/cosmos-social-login-capsule-provider@0.0.39)(@types/react@18.3.3)(axios@1.7.7)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(starknet@6.11.0): resolution: {integrity: sha512-KaRQJ7HTQp3vbX/bG2Oc9T3t/KyaIuU5dLoGU2QNFirNjIpRbhkBtCll9Li5A6+zw3O9bHkbZ1aUaKfuVyBS8w==} hasBin: true peerDependencies: @@ -17929,7 +17932,7 @@ packages: cosmos-directory-client: 0.0.6 long: 4.0.0 react: 18.2.0 - zustand: 4.5.4(@types/react@18.3.3)(react@18.2.0) + zustand: 4.5.4(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -26574,7 +26577,7 @@ packages: - supports-color dev: true - /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0): + /wagmi@2.10.9(@tanstack/react-query@5.37.1)(@types/react@18.3.3)(immer@10.1.1)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0): resolution: {integrity: sha512-pYGTLmVIAC4q/a90i+vlrkJL86n5Kf/gwhhi65XtQklpsUQWrKDmn4dsY1/yFeAmZ/1yx1mpxYpX3LI97eTuWA==} peerDependencies: '@tanstack/react-query': '>=5.0.0' @@ -26587,7 +26590,7 @@ packages: dependencies: '@tanstack/react-query': 5.37.1(react@18.2.0) '@wagmi/connectors': 5.0.21(@types/react@18.3.3)(@wagmi/core@2.11.6)(react-dom@18.2.0)(react-native@0.74.3)(react@18.2.0)(rollup@2.79.1)(typescript@5.7.2)(viem@2.17.0) - '@wagmi/core': 2.11.6(@types/react@18.3.3)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) + '@wagmi/core': 2.11.6(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0)(typescript@5.7.2)(viem@2.17.0) react: 18.2.0 typescript: 5.7.2 use-sync-external-store: 1.2.0(react@18.2.0) @@ -27549,7 +27552,7 @@ packages: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} dev: false - /zustand@4.4.1(@types/react@18.3.3)(react@18.2.0): + /zustand@4.4.1(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0): resolution: {integrity: sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==} engines: {node: '>=12.7.0'} peerDependencies: @@ -27565,11 +27568,12 @@ packages: optional: true dependencies: '@types/react': 18.3.3 + immer: 10.1.1 react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) dev: false - /zustand@4.5.4(@types/react@18.3.3)(react@18.2.0): + /zustand@4.5.4(@types/react@18.3.3)(immer@10.1.1)(react@18.2.0): resolution: {integrity: sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==} engines: {node: '>=12.7.0'} peerDependencies: @@ -27585,6 +27589,7 @@ packages: optional: true dependencies: '@types/react': 18.3.3 + immer: 10.1.1 react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) dev: false diff --git a/src/abacus-ts/rawTypes.ts b/src/abacus-ts/rawTypes.ts index 975ad639d..f4811418e 100644 --- a/src/abacus-ts/rawTypes.ts +++ b/src/abacus-ts/rawTypes.ts @@ -10,6 +10,8 @@ import { IndexerCompositeOrderObject, } from '@/types/indexer/indexerManual'; +import { MetadataServiceAssetInfo } from '@/constants/assetMetadata'; + export type MarketsData = { [marketId: string]: IndexerPerpetualMarketResponseObject }; export type OrderbookData = { @@ -42,3 +44,6 @@ export interface ChildSubaccountData { assetPositions: { [symbol: string]: IndexerAssetPositionResponseObject }; } + +export type AssetInfo = MetadataServiceAssetInfo & { id: string }; +export type AssetInfos = Record; diff --git a/src/abacus-ts/rest/assets.ts b/src/abacus-ts/rest/assets.ts index 6ac96ba20..ad4c18d30 100644 --- a/src/abacus-ts/rest/assets.ts +++ b/src/abacus-ts/rest/assets.ts @@ -1,4 +1,5 @@ import { QueryObserver } from '@tanstack/react-query'; +import { mapValues } from 'lodash'; import { timeUnits } from '@/constants/time'; @@ -9,6 +10,7 @@ import { setAllAssetsRaw } from '@/state/raw'; import metadataClient from '@/clients/metadataService'; import { loadableIdle } from '../lib/loadable'; +import { mapLoadableData } from '../lib/mapLoadable'; import { logAbacusTsError } from '../logs'; import { queryResultToLoadable } from './lib/queryResultToLoadable'; @@ -22,7 +24,13 @@ export function setUpAssetsQuery(store: RootStore) { const unsubscribe = observer.subscribe((result) => { try { - store.dispatch(setAllAssetsRaw(queryResultToLoadable(result))); + store.dispatch( + setAllAssetsRaw( + mapLoadableData(queryResultToLoadable(result), (map) => + mapValues(map, (v, id) => ({ ...v, id })) + ) + ) + ); } catch (e) { logAbacusTsError('setUpAssetsQuery', 'Error handling result from react query', e, result); } diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index af8f90e43..03fc346df 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -1,8 +1,15 @@ -import { IndexerSubaccountResponseObject } from '@/types/indexer/indexerApiGen'; +import { + IndexerAssetPositionResponseObject, + IndexerOrderResponseObject, + IndexerPerpetualPositionResponseObject, + IndexerSubaccountResponseObject, +} from '@/types/indexer/indexerApiGen'; import { isWsParentSubaccountSubscribed, isWsParentSubaccountUpdates, } from '@/types/indexer/indexerChecks'; +import { IndexerWsOrderUpdate } from '@/types/indexer/indexerManual'; +import { produce } from 'immer'; import { keyBy } from 'lodash'; import { type RootStore } from '@/state/_store'; @@ -91,73 +98,101 @@ function accountWebsocketValue( if (value.data == null || updates.length === 0 || subaccountNumber == null) { return value; } - const returnValue = { ...value.data }; - updates.forEach((update) => { - if (update.assetPositions != null) { - update.assetPositions.forEach((positionUpdate) => { - returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= - freshChildSubaccount({ - address, - subaccountNumber: positionUpdate.subaccountNumber, - }); - - returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.assetPositions[ - positionUpdate.assetId - ] = { - ...(returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.assetPositions[ - positionUpdate.assetId - ] ?? {}), - ...positionUpdate, - }; - }); - } - if (update.perpetualPositions != null) { - update.perpetualPositions.forEach((positionUpdate) => { - returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= - freshChildSubaccount({ - address, - subaccountNumber: positionUpdate.subaccountNumber, - }); - - returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.openPerpetualPositions[ - positionUpdate.market - ] = { - ...(returnValue.childSubaccounts[positionUpdate.subaccountNumber]! - .openPerpetualPositions[positionUpdate.market] ?? {}), - ...positionUpdate, - }; - }); - } - if (update.tradingReward != null) { - returnValue.ephemeral.tradingRewards ??= []; - returnValue.ephemeral.tradingRewards = [ - ...returnValue.ephemeral.tradingRewards, - update.tradingReward, - ]; - } - if (update.fills != null) { - returnValue.ephemeral.fills ??= []; - returnValue.ephemeral.fills = [ - ...returnValue.ephemeral.fills, - ...update.fills.map((f) => ({ ...f, subaccountNumber })), - ]; - } - if (update.orders != null) { - returnValue.ephemeral.orders ??= {}; - returnValue.ephemeral.orders = { - ...returnValue.ephemeral.orders, - ...keyBy(update.orders, (o) => o.id ?? ''), - }; - } - if (update.transfers != null) { - returnValue.ephemeral.transfers ??= []; - returnValue.ephemeral.transfers = [ - ...returnValue.ephemeral.transfers, - update.transfers, - ]; - } + const resultData = produce(value.data, (returnValue) => { + updates.forEach((update) => { + if (update.assetPositions != null) { + update.assetPositions.forEach((positionUpdate) => { + returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= + freshChildSubaccount({ + address, + subaccountNumber: positionUpdate.subaccountNumber, + }); + + const assetPositions = + returnValue.childSubaccounts[positionUpdate.subaccountNumber]!.assetPositions; + + if (assetPositions[positionUpdate.assetId] == null) { + assetPositions[positionUpdate.assetId] = + positionUpdate as IndexerAssetPositionResponseObject; + } else { + assetPositions[positionUpdate.assetId] = { + ...(assetPositions[ + positionUpdate.assetId + ] as IndexerAssetPositionResponseObject), + ...positionUpdate, + }; + } + }); + } + if (update.perpetualPositions != null) { + update.perpetualPositions.forEach((positionUpdate) => { + returnValue.childSubaccounts[positionUpdate.subaccountNumber] ??= + freshChildSubaccount({ + address, + subaccountNumber: positionUpdate.subaccountNumber, + }); + + const perpPositions = + returnValue.childSubaccounts[positionUpdate.subaccountNumber]! + .openPerpetualPositions; + + if (perpPositions[positionUpdate.market] == null) { + perpPositions[positionUpdate.market] = + positionUpdate as IndexerPerpetualPositionResponseObject; + } else { + perpPositions[positionUpdate.market] = { + ...(perpPositions[ + positionUpdate.market + ] as IndexerPerpetualPositionResponseObject), + ...positionUpdate, + }; + } + }); + } + if (update.tradingReward != null) { + returnValue.ephemeral.tradingRewards ??= []; + returnValue.ephemeral.tradingRewards = [ + ...returnValue.ephemeral.tradingRewards, + update.tradingReward, + ]; + } + if (update.fills != null) { + returnValue.ephemeral.fills ??= []; + returnValue.ephemeral.fills = [ + ...returnValue.ephemeral.fills, + ...update.fills.map((f) => ({ ...f, subaccountNumber })), + ]; + } + if (update.orders != null) { + returnValue.ephemeral.orders = { ...(returnValue.ephemeral.orders ?? {}) }; + const allOrders = returnValue.ephemeral.orders; + update.orders.forEach((o) => { + const previousOrder = allOrders[o.id]; + if (previousOrder == null) { + allOrders[o.id] = { + ...(o as IndexerOrderResponseObject), + subaccountNumber, + }; + } else { + allOrders[o.id] = { + ...(allOrders[o.id] as IndexerOrderResponseObject), + ...(o as IndexerWsOrderUpdate), + subaccountNumber, + }; + } + }); + } + if (update.transfers != null) { + returnValue.ephemeral.transfers ??= []; + returnValue.ephemeral.transfers = [ + ...returnValue.ephemeral.transfers, + update.transfers, + ]; + } + }); }); - return { ...value, data: returnValue }; + + return { ...value, data: resultData }; }, }, loadablePending(), diff --git a/src/constants/assetMetadata.ts b/src/constants/assetMetadata.ts index 14fa84e2c..6cc1256ae 100644 --- a/src/constants/assetMetadata.ts +++ b/src/constants/assetMetadata.ts @@ -1,17 +1,16 @@ -export type MetadataServiceInfoResponse = Record< - string, - { - name: string; - logo: string; - urls: { - website: string | null; - technical_doc: string | null; - cmc: string | null; - }; - sector_tags: string[] | null; - exchanges: any[] | null; - } ->; +export type MetadataServiceAssetInfo = { + name: string; + logo: string; + urls: { + website: string | null; + technical_doc: string | null; + cmc: string | null; + }; + sector_tags: string[] | null; + exchanges: any[] | null; +}; + +export type MetadataServiceInfoResponse = Record; export type MetadataServicePricesResponse = Record< string, diff --git a/src/pages/trade/types.ts b/src/pages/trade/types.ts index b1718ebb6..c72dc447d 100644 --- a/src/pages/trade/types.ts +++ b/src/pages/trade/types.ts @@ -1,3 +1,5 @@ +import { MarginMode } from '@/abacus-ts/summaryTypes'; + export enum MarketTypeFilter { AllMarkets = 'AllMarkets', Cross = 'Cross', @@ -12,6 +14,14 @@ export function marketTypeMatchesFilter(type: 'Isolated' | 'Cross', filter?: Mar (type === 'Cross' && filter === MarketTypeFilter.Cross) ); } +export function marginModeMatchesFilter(type: MarginMode, filter?: MarketTypeFilter) { + return ( + filter == null || + filter === MarketTypeFilter.AllMarkets || + (type === 'ISOLATED' && filter === MarketTypeFilter.Isolated) || + (type === 'CROSS' && filter === MarketTypeFilter.Cross) + ); +} export enum PanelView { AllMarkets = 'AllMarkets', diff --git a/src/state/raw.ts b/src/state/raw.ts index 1cdce1d49..651a81466 100644 --- a/src/state/raw.ts +++ b/src/state/raw.ts @@ -1,5 +1,5 @@ import { Loadable, loadableIdle } from '@/abacus-ts/lib/loadable'; -import { MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/rawTypes'; +import { AssetInfos, MarketsData, OrderbookData, ParentSubaccountData } from '@/abacus-ts/rawTypes'; import { IndexerHistoricalBlockTradingRewardsResponse, IndexerParentSubaccountTransferResponse, @@ -11,7 +11,6 @@ import { import { HeightResponse } from '@dydxprotocol/v4-client-js'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { MetadataServiceInfoResponse } from '@/constants/assetMetadata'; import { DydxNetwork } from '@/constants/networks'; interface NetworkState { @@ -22,7 +21,7 @@ interface NetworkState { export interface RawDataState { markets: { allMarkets: Loadable; - assets: Loadable; + assets: Loadable; orderbooks: { [marketId: string]: Loadable }; }; account: { @@ -64,7 +63,7 @@ export const rawSlice = createSlice({ setAllMarketsRaw: (state, action: PayloadAction>) => { state.markets.allMarkets = action.payload; }, - setAllAssetsRaw: (state, action: PayloadAction>) => { + setAllAssetsRaw: (state, action: PayloadAction>) => { state.markets.assets = action.payload; }, setOrderbookRaw: ( diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 5592f2f50..2894e68b3 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -128,12 +128,25 @@ export interface IndexerWsParentSubaccountSubscribedResponse { orders: IndexerOrderResponseObject[]; } +export type IndexerWsAssetUpdate = Partial & { + subaccountNumber: number; + assetId: string; +}; +export type IndexerWsPositionUpdate = Partial & { + subaccountNumber: number; + market: string; +}; + +export type IndexerWsOrderUpdate = { id: string } & Partial< + Omit +>; + export interface IndexerWsParentSubaccountUpdateObject { blockHeight: string; - assetPositions?: IndexerAssetPositionResponseObject[]; - perpetualPositions?: IndexerPerpetualPositionResponseObject[]; + assetPositions?: Array; + perpetualPositions?: Array; tradingReward?: IndexerHistoricalBlockTradingReward; fills?: IndexerCompositeFillObject[]; - orders?: IndexerCompositeOrderObject[]; + orders?: Array; transfers?: IndexerTransferResponseObject; } From 2ee4069cdb4bce59ad4d21ff3b112250ed92c236 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 16:16:52 -0500 Subject: [PATCH 59/65] fix --- src/pages/trade/types.ts | 10 ---------- src/types/indexer/indexerManual.ts | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/pages/trade/types.ts b/src/pages/trade/types.ts index c72dc447d..b1718ebb6 100644 --- a/src/pages/trade/types.ts +++ b/src/pages/trade/types.ts @@ -1,5 +1,3 @@ -import { MarginMode } from '@/abacus-ts/summaryTypes'; - export enum MarketTypeFilter { AllMarkets = 'AllMarkets', Cross = 'Cross', @@ -14,14 +12,6 @@ export function marketTypeMatchesFilter(type: 'Isolated' | 'Cross', filter?: Mar (type === 'Cross' && filter === MarketTypeFilter.Cross) ); } -export function marginModeMatchesFilter(type: MarginMode, filter?: MarketTypeFilter) { - return ( - filter == null || - filter === MarketTypeFilter.AllMarkets || - (type === 'ISOLATED' && filter === MarketTypeFilter.Isolated) || - (type === 'CROSS' && filter === MarketTypeFilter.Cross) - ); -} export enum PanelView { AllMarkets = 'AllMarkets', diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 2894e68b3..21a63347b 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -25,7 +25,7 @@ export interface IndexerCompositeFillResponse { } export interface IndexerCompositeOrderObject { - id?: string; + id: string; subaccountId?: string; clientId?: string; clobPairId?: string; @@ -137,9 +137,9 @@ export type IndexerWsPositionUpdate = Partial ->; +> & { id: string }; export interface IndexerWsParentSubaccountUpdateObject { blockHeight: string; From 78ab949b9006f54008620cc33fc8d792d28e6814 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 17:35:08 -0500 Subject: [PATCH 60/65] fills table --- src/components/OrderSideTag.tsx | 3 +- src/lib/orders.ts | 34 ++++- src/lib/testFlags.ts | 6 - src/state/_store.ts | 13 +- src/views/tables/FillsTable.tsx | 227 +++++++++++++++----------------- 5 files changed, 148 insertions(+), 135 deletions(-) diff --git a/src/components/OrderSideTag.tsx b/src/components/OrderSideTag.tsx index def4293cd..cb20386ef 100644 --- a/src/components/OrderSideTag.tsx +++ b/src/components/OrderSideTag.tsx @@ -1,3 +1,4 @@ +import { IndexerOrderSide } from '@/types/indexer/indexerApiGen'; import { OrderSide } from '@dydxprotocol/v4-client-js'; import { STRING_KEYS } from '@/constants/localization'; @@ -7,7 +8,7 @@ import { useStringGetter } from '@/hooks/useStringGetter'; import { Tag, TagSign, TagSize, TagType } from './Tag'; type ElementProps = { - orderSide: OrderSide; + orderSide: OrderSide | IndexerOrderSide; }; type StyleProps = { diff --git a/src/lib/orders.ts b/src/lib/orders.ts index 3d74fc882..68731d806 100644 --- a/src/lib/orders.ts +++ b/src/lib/orders.ts @@ -1,3 +1,5 @@ +import { AssetInfo, AssetInfos, MarketsData } from '@/abacus-ts/rawTypes'; +import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual'; import { OrderSide } from '@dydxprotocol/v4-client-js'; import BigNumber from 'bignumber.js'; @@ -8,12 +10,12 @@ import { AbacusOrderTypes, KotlinIrEnumValues, Nullable, + SubaccountFill, SubaccountFills, TRADE_TYPES, type Asset, type OrderStatus, type PerpetualMarket, - type SubaccountFill, type SubaccountFundingPayment, type SubaccountOrder, } from '@/constants/abacus'; @@ -22,6 +24,9 @@ import { IconName } from '@/components/Icon'; import { convertAbacusOrderSide } from '@/lib/abacus/conversions'; +import { getAssetFromMarketId } from './assetUtils'; +import { MaybeBigNumber } from './numbers'; + export const getOrderStatusInfo = ({ status }: { status: string }) => { switch (status) { case AbacusOrderStatus.Open.rawValue: { @@ -145,6 +150,33 @@ export const getHydratedTradingData = < ...('side' in data && { orderSide: convertAbacusOrderSide(data.side) }), }); +type NewAddedProps = { + asset: AssetInfo | undefined; + stepSizeDecimals: Nullable; + tickSizeDecimals: Nullable; +}; + +export const getHydratedFill = ({ + data, + assets, + perpetualMarkets, +}: { + data: IndexerCompositeFillObject; + assets: AssetInfos; + perpetualMarkets: MarketsData; +}): IndexerCompositeFillObject & NewAddedProps => { + return { + ...data, + asset: assets[getAssetFromMarketId(data.market ?? '')], + stepSizeDecimals: MaybeBigNumber( + perpetualMarkets[data.market ?? '']?.stepSize + )?.decimalPlaces(), + tickSizeDecimals: MaybeBigNumber( + perpetualMarkets[data.market ?? '']?.tickSize + )?.decimalPlaces(), + }; +}; + export const getTradeType = (orderType: string) => TRADE_TYPES[orderType as KotlinIrEnumValues]; diff --git a/src/lib/testFlags.ts b/src/lib/testFlags.ts index dc4499797..46ba5cbc5 100644 --- a/src/lib/testFlags.ts +++ b/src/lib/testFlags.ts @@ -1,5 +1,3 @@ -import { isDev } from '@/constants/networks'; - class TestFlags { public queryParams: { [key: string]: string }; @@ -62,10 +60,6 @@ class TestFlags { return !!this.queryParams.funkit_toggle; } - get useAbacusTs() { - return isDev; - } - get showNewDepositFlow() { return !!this.queryParams.deposit_rewrite; } diff --git a/src/state/_store.ts b/src/state/_store.ts index 59f0af63d..b5a4b5b8f 100644 --- a/src/state/_store.ts +++ b/src/state/_store.ts @@ -5,7 +5,6 @@ import storage from 'redux-persist/lib/storage'; import abacusStateManager from '@/lib/abacus'; import { runFn } from '@/lib/do'; -import { testFlags } from '@/lib/testFlags'; import { accountSlice } from './account'; import { affiliatesSlice } from './affiliates'; @@ -95,13 +94,11 @@ export const persistor = persistStore(store); // Set store so (Abacus & v4-Client) classes can getState and dispatch abacusStateManager.setStore(store); -if (testFlags.useAbacusTs) { - runFn(async () => { - const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); - // we ignore the cleanups for now since we want these running forever - storeLifecycles.forEach((fn) => fn(store)); - }); -} +runFn(async () => { + const { storeLifecycles } = await import('@/abacus-ts/storeLifecycles'); + // we ignore the cleanups for now since we want these running forever + storeLifecycles.forEach((fn) => fn(store)); +}); export type RootStore = typeof store; export type RootState = ReturnType; diff --git a/src/views/tables/FillsTable.tsx b/src/views/tables/FillsTable.tsx index 43d108394..20b8daaad 100644 --- a/src/views/tables/FillsTable.tsx +++ b/src/views/tables/FillsTable.tsx @@ -1,16 +1,18 @@ import { forwardRef, Key, useEffect, useMemo } from 'react'; +import { AssetInfo } from '@/abacus-ts/rawTypes'; +import { getCurrentMarketAccountFills, selectAccountFills } from '@/abacus-ts/selectors/account'; +import { selectRawAssetsData, selectRawMarketsData } from '@/abacus-ts/selectors/base'; +import { IndexerFillType, IndexerLiquidity, IndexerOrderSide } from '@/types/indexer/indexerApiGen'; +import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual'; import { Nullable } from '@dydxprotocol/v4-abacus'; -import { OrderSide } from '@dydxprotocol/v4-client-js'; import type { ColumnSize } from '@react-types/table'; -import { shallowEqual } from 'react-redux'; import styled, { css } from 'styled-components'; import tw from 'twin.macro'; -import { type Asset, type SubaccountFill } from '@/constants/abacus'; +import { Asset } from '@/constants/abacus'; import { DialogTypes } from '@/constants/dialogs'; import { STRING_KEYS, type StringGetterFunction } from '@/constants/localization'; -import { EMPTY_ARR } from '@/constants/objects'; import { useBreakpoints } from '@/hooks/useBreakpoints'; import { useStringGetter } from '@/hooks/useStringGetter'; @@ -29,15 +31,14 @@ import { PageSize } from '@/components/Table/TablePaginationRow'; import { TagSize } from '@/components/Tag'; import { viewedFills } from '@/state/account'; -import { getCurrentMarketFills, getSubaccountFills } from '@/state/accountSelectors'; import { useAppDispatch, useAppSelector } from '@/state/appTypes'; -import { getAssets } from '@/state/assetsSelectors'; import { openDialog } from '@/state/dialogs'; -import { getPerpetualMarkets } from '@/state/perpetualsSelectors'; +import { assertNever } from '@/lib/assertNever'; +import { getAssetFromMarketId } from '@/lib/assetUtils'; import { mapIfPresent } from '@/lib/do'; import { MustBigNumber } from '@/lib/numbers'; -import { getHydratedTradingData } from '@/lib/orders'; +import { getHydratedFill } from '@/lib/orders'; import { orEmptyRecord } from '@/lib/typeUtils'; const MOBILE_FILLS_PER_PAGE = 50; @@ -47,7 +48,6 @@ export enum FillsTableColumnKey { Market = 'Market', Action = 'Action', Side = 'Side', - SideLongShort = 'Side-LongShort', Type = 'Type', Price = 'Price', Liquidity = 'Liquidity', @@ -55,10 +55,6 @@ export enum FillsTableColumnKey { AmountTag = 'Amount-Tag', Total = 'Total', Fee = 'Fee', - TypeLiquidity = 'Type-Liquidity', - - // TODO: CT-1292 remove deprecated fields - TotalFee = 'Total-Fee', // Tablet Only TypeAmount = 'Type-Amount', @@ -66,11 +62,10 @@ export enum FillsTableColumnKey { } export type FillTableRow = { - asset: Nullable; + asset: Nullable; stepSizeDecimals: Nullable; tickSizeDecimals: Nullable; - orderSide?: Nullable; -} & SubaccountFill; +} & IndexerCompositeFillObject; const getFillsTableColumnDef = ({ key, @@ -95,19 +90,13 @@ const getFillsTableColumnDef = ({ {stringGetter({ key: STRING_KEYS.AMOUNT })} ), - renderCell: ({ resources, size, stepSizeDecimals, asset }) => ( + renderCell: ({ size, type, stepSizeDecimals, asset }) => ( - } + slotLeft={} > - {resources.typeStringKey ? stringGetter({ key: resources.typeStringKey }) : null} + {type != null ? stringGetter({ key: getIndexerFillTypeStringKey(type) }) : null} {stringGetter({ key: STRING_KEYS.FEE })} ), - renderCell: ({ fee, orderSide, price, resources, tickSizeDecimals }) => ( + renderCell: ({ fee, side, price, tickSizeDecimals, liquidity }) => ( <$InlineRow> - <$Side side={orderSide}> - {resources.sideStringKey ? stringGetter({ key: resources.sideStringKey }) : null} + <$Side side={side}> + {side != null ? stringGetter({ key: getIndexerOrderSideStringKey(side) }) : null} @ <$InlineRow> - {resources.liquidityStringKey - ? stringGetter({ key: resources.liquidityStringKey }) + {liquidity != null + ? stringGetter({ key: getIndexerLiquidityStringKey(liquidity) }) : null} @@ -154,36 +143,47 @@ const getFillsTableColumnDef = ({ }, [FillsTableColumnKey.Time]: { columnKey: 'time', - getCellValue: (row) => row.createdAtMilliseconds, + getCellValue: (row) => row.createdAt, label: stringGetter({ key: STRING_KEYS.TIME }), - renderCell: ({ createdAtMilliseconds }) => ( + renderCell: ({ createdAt }) => ( ), }, [FillsTableColumnKey.Market]: { columnKey: 'market', - getCellValue: (row) => row.marketId, + getCellValue: (row) => row.market, label: stringGetter({ key: STRING_KEYS.MARKET }), - renderCell: ({ asset }) => , + renderCell: ({ asset }) => ( + + ), }, [FillsTableColumnKey.Action]: { columnKey: 'market-simple', - getCellValue: (row) => row.marketId, + getCellValue: (row) => row.market, label: stringGetter({ key: STRING_KEYS.ACTION }), - renderCell: ({ asset, orderSide }) => ( + renderCell: ({ asset, side }) => ( - {orderSide && ( - <$Side side={orderSide}> + {side != null && ( + <$Side side={side}> {stringGetter({ - key: { - [OrderSide.BUY]: STRING_KEYS.BUY, - [OrderSide.SELL]: STRING_KEYS.SELL, - }[orderSide], + key: getIndexerOrderSideStringKey(side), })} )} @@ -193,34 +193,21 @@ const getFillsTableColumnDef = ({ }, [FillsTableColumnKey.Liquidity]: { columnKey: 'liquidity', - getCellValue: (row) => row.liquidity.rawValue, + getCellValue: (row) => row.liquidity, label: stringGetter({ key: STRING_KEYS.LIQUIDITY }), - renderCell: ({ resources }) => - resources.liquidityStringKey ? stringGetter({ key: resources.liquidityStringKey }) : null, - }, - [FillsTableColumnKey.TotalFee]: { - columnKey: 'totalFee', - getCellValue: (row) => MustBigNumber(row.price).times(row.size).toNumber(), - label: ( - - {stringGetter({ key: STRING_KEYS.TOTAL })} - {stringGetter({ key: STRING_KEYS.FEE })} - - ), - renderCell: ({ size, fee, price }) => ( - - - - - ), + renderCell: ({ liquidity }) => + liquidity != null ? stringGetter({ key: getIndexerLiquidityStringKey(liquidity) }) : null, }, [FillsTableColumnKey.Total]: { columnKey: 'total', - getCellValue: (row) => MustBigNumber(row.price).times(row.size).toNumber(), + getCellValue: (row) => + MustBigNumber(row.price) + .times(row.size ?? 0) + .toNumber(), label: stringGetter({ key: STRING_KEYS.TOTAL }), renderCell: ({ size, price }) => ( - + ), }, @@ -236,10 +223,10 @@ const getFillsTableColumnDef = ({ }, [FillsTableColumnKey.Type]: { columnKey: 'type', - getCellValue: (row) => row.type.rawValue, + getCellValue: (row) => row.type, label: stringGetter({ key: STRING_KEYS.TYPE }), - renderCell: ({ resources }) => - resources.typeStringKey ? stringGetter({ key: resources.typeStringKey }) : null, + renderCell: ({ type }) => + type != null ? stringGetter({ key: getIndexerFillTypeStringKey(type) }) : null, }, [FillsTableColumnKey.Price]: { columnKey: 'price', @@ -265,27 +252,11 @@ const getFillsTableColumnDef = ({ }, [FillsTableColumnKey.Side]: { columnKey: 'side', - getCellValue: (row) => row.orderSide, + getCellValue: (row) => row.side, label: stringGetter({ key: STRING_KEYS.SIDE }), - renderCell: ({ orderSide }) => - orderSide && , - }, - [FillsTableColumnKey.SideLongShort]: { - columnKey: 'side', - getCellValue: (row) => row.orderSide, - label: stringGetter({ key: STRING_KEYS.SIDE }), - renderCell: ({ orderSide }) => ( - - ), + renderCell: ({ side }) => side && , }, + [FillsTableColumnKey.AmountPrice]: { columnKey: 'sizePrice', getCellValue: (row) => row.size, @@ -307,32 +278,47 @@ const getFillsTableColumnDef = ({ ), }, - [FillsTableColumnKey.TypeLiquidity]: { - columnKey: 'typeLiquidity', - getCellValue: (row) => row.type.rawValue, - label: ( - - {stringGetter({ key: STRING_KEYS.TYPE })} - {stringGetter({ key: STRING_KEYS.LIQUIDITY })} - - ), - renderCell: ({ resources }) => ( - - - {resources.typeStringKey ? stringGetter({ key: resources.typeStringKey }) : null} - - - {resources.liquidityStringKey - ? stringGetter({ key: resources.liquidityStringKey }) - : null} - - - ), - }, } satisfies Record> )[key], }); +function getIndexerFillTypeStringKey(fillType: IndexerFillType): string { + switch (fillType) { + case IndexerFillType.LIMIT: + return STRING_KEYS.LIMIT_ORDER_SHORT; + case IndexerFillType.LIQUIDATED: + return STRING_KEYS.LIQUIDATED; + case IndexerFillType.LIQUIDATION: + return STRING_KEYS.LIQUIDATION; + case IndexerFillType.DELEVERAGED: + return STRING_KEYS.DELEVERAGED; + case IndexerFillType.OFFSETTING: + return STRING_KEYS.OFFSETTING; + default: + assertNever(fillType); + return STRING_KEYS.LIMIT_ORDER_SHORT; + } +} + +function getIndexerLiquidityStringKey(liquidity: IndexerLiquidity): string { + switch (liquidity) { + case IndexerLiquidity.MAKER: + return STRING_KEYS.MAKER; + case IndexerLiquidity.TAKER: + return STRING_KEYS.TAKER; + default: + assertNever(liquidity); + return STRING_KEYS.MAKER; + } +} + +function getIndexerOrderSideStringKey(side: IndexerOrderSide) { + if (side === IndexerOrderSide.BUY) { + return STRING_KEYS.BUY; + } + return STRING_KEYS.SELL; +} + type ElementProps = { columnKeys: FillsTableColumnKey[]; columnWidths?: Partial>; @@ -363,12 +349,12 @@ export const FillsTable = forwardRef( const dispatch = useAppDispatch(); const { isMobile } = useBreakpoints(); - const marketFills = useAppSelector(getCurrentMarketFills, shallowEqual) ?? EMPTY_ARR; - const allFills = useAppSelector(getSubaccountFills, shallowEqual) ?? EMPTY_ARR; + const marketFills = useAppSelector(getCurrentMarketAccountFills); + const allFills = useAppSelector(selectAccountFills); const fills = currentMarket ? marketFills : allFills; - const allPerpetualMarkets = orEmptyRecord(useAppSelector(getPerpetualMarkets, shallowEqual)); - const allAssets = orEmptyRecord(useAppSelector(getAssets, shallowEqual)); + const allPerpetualMarkets = orEmptyRecord(useAppSelector(selectRawMarketsData)); + const allAssets = orEmptyRecord(useAppSelector(selectRawAssetsData)); useEffect(() => { // marked fills as seen both on mount and dismount (i.e. new fill came in while fills table is being shown) @@ -379,14 +365,17 @@ export const FillsTable = forwardRef( }, [currentMarket, dispatch]); const symbol = mapIfPresent(currentMarket, (market) => - mapIfPresent(allPerpetualMarkets[market]?.assetId, (assetId) => allAssets[assetId]?.id) + mapIfPresent( + allPerpetualMarkets[market]?.ticker, + (ticker) => allAssets[getAssetFromMarketId(ticker)]?.id + ) ); const fillsData = useMemo( () => fills.map( - (fill: SubaccountFill): FillTableRow => - getHydratedTradingData({ + (fill: IndexerCompositeFillObject): FillTableRow => + getHydratedFill({ data: fill, assets: allAssets, perpetualMarkets: allPerpetualMarkets, @@ -402,7 +391,7 @@ export const FillsTable = forwardRef( data={ isMobile && withGradientCardRows ? fillsData.slice(0, MOBILE_FILLS_PER_PAGE) : fillsData } - getRowKey={(row: FillTableRow) => row.id} + getRowKey={(row: FillTableRow) => row.id ?? ''} onRowAction={(key: Key) => dispatch(openDialog(DialogTypes.FillDetails({ fillId: `${key}` }))) } @@ -434,14 +423,14 @@ const $Table = styled(Table)` ${tradeViewMixins.horizontalTable} ` as typeof Table; const $InlineRow = tw.div`inlineRow`; -const $Side = styled.span<{ side: Nullable }>` +const $Side = styled.span<{ side: Nullable }>` ${({ side }) => side && { - [OrderSide.BUY]: css` + [IndexerOrderSide.BUY]: css` color: var(--color-positive); `, - [OrderSide.SELL]: css` + [IndexerOrderSide.SELL]: css` color: var(--color-negative); `, }[side]}; From fcc53065bcd9cc7537b1439080a1c7f43cb5a910 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 17:37:13 -0500 Subject: [PATCH 61/65] fix --- src/abacus-ts/calculators/fills.ts | 5 +++-- src/abacus-ts/selectors/account.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/abacus-ts/calculators/fills.ts b/src/abacus-ts/calculators/fills.ts index 88fbc68e8..97b893d07 100644 --- a/src/abacus-ts/calculators/fills.ts +++ b/src/abacus-ts/calculators/fills.ts @@ -1,5 +1,5 @@ import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual'; -import { keyBy, maxBy } from 'lodash'; +import { keyBy, maxBy, orderBy } from 'lodash'; import { EMPTY_ARR } from '@/constants/objects'; @@ -12,9 +12,10 @@ export function calculateFills( restFills: IndexerCompositeFillObject[] | undefined ) { const getFillsById = (data: IndexerCompositeFillObject[]) => keyBy(data, (fill) => fill.id ?? ''); - return mergeObjects( + const merged = mergeObjects( getFillsById(liveFills ?? EMPTY_ARR), getFillsById(restFills ?? EMPTY_ARR), (first, second) => maxBy([first, second], (f) => MustBigNumber(f.createdAtHeight).toNumber())! ); + return orderBy(Object.values(merged), [(f) => f.createdAtHeight], ['desc']); } diff --git a/src/abacus-ts/selectors/account.ts b/src/abacus-ts/selectors/account.ts index 527eef9ac..d4427ecdf 100644 --- a/src/abacus-ts/selectors/account.ts +++ b/src/abacus-ts/selectors/account.ts @@ -2,7 +2,10 @@ import { IndexerPerpetualPositionStatus } from '@/types/indexer/indexerApiGen'; import { pick } from 'lodash'; import { shallowEqual } from 'react-redux'; +import { EMPTY_ARR } from '@/constants/objects'; + import { createAppSelector } from '@/state/appTypes'; +import { getCurrentMarketId } from '@/state/perpetualsSelectors'; import { calculateFills } from '../calculators/fills'; import { @@ -133,6 +136,12 @@ export const selectAccountFills = createAppSelector( } ); +export const getCurrentMarketAccountFills = createAppSelector( + [getCurrentMarketId, selectAccountFills], + (currentMarketId, fills) => + !currentMarketId ? EMPTY_ARR : fills.filter((f) => f.market === currentMarketId) +); + export const selectAccountFillsLoading = createAppSelector( [selectRawFillsRest, selectRawParentSubaccount], mergeLoadableStatus From c9b8375c742031130d8d106c0cc852524de20eeb Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 17 Dec 2024 17:37:53 -0500 Subject: [PATCH 62/65] fix --- src/abacus-ts/websocket/parentSubaccount.ts | 7 ++++++- src/types/indexer/indexerManual.ts | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/abacus-ts/websocket/parentSubaccount.ts b/src/abacus-ts/websocket/parentSubaccount.ts index 03fc346df..7c4ed94ed 100644 --- a/src/abacus-ts/websocket/parentSubaccount.ts +++ b/src/abacus-ts/websocket/parentSubaccount.ts @@ -160,7 +160,12 @@ function accountWebsocketValue( returnValue.ephemeral.fills ??= []; returnValue.ephemeral.fills = [ ...returnValue.ephemeral.fills, - ...update.fills.map((f) => ({ ...f, subaccountNumber })), + ...update.fills.map((f) => ({ + ...f, + subaccountNumber, + // NOTE: provides ticker in ws response instead of market for soem reason + market: f.market ?? ((f as any).ticker as string), + })), ]; } if (update.orders != null) { diff --git a/src/types/indexer/indexerManual.ts b/src/types/indexer/indexerManual.ts index 21a63347b..f7d4dc28a 100644 --- a/src/types/indexer/indexerManual.ts +++ b/src/types/indexer/indexerManual.ts @@ -108,7 +108,6 @@ export interface IndexerCompositeFillObject { side?: IndexerOrderSide; liquidity?: IndexerLiquidity; type?: IndexerFillType; - market?: string; marketType?: IndexerMarketType; price?: string; size?: string; @@ -119,7 +118,7 @@ export interface IndexerCompositeFillObject { orderId?: string | null; clientMetadata?: string | null; subaccountNumber?: number; - ticker?: string; + market?: string; } export interface IndexerWsParentSubaccountSubscribedResponse { From 59cf4c07a0fe39b11a698de7d6f940678b7a9034 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 19 Dec 2024 13:58:50 -0500 Subject: [PATCH 63/65] fix --- src/state/accountSelectors.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index 49337c144..646aea047 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -1,3 +1,4 @@ +import { selectAccountFills } from '@/abacus-ts/selectors/account'; import { selectRawIndexerHeightData } from '@/abacus-ts/selectors/base'; import { OrderSide } from '@dydxprotocol/v4-client-js'; import BigNumber from 'bignumber.js'; @@ -735,15 +736,14 @@ export const createGetUnseenFillsCount = () => [ getCurrentAccountMemory, selectRawIndexerHeightData, - getSubaccountFills, + selectAccountFills, (state, market: string | undefined) => market, ], (memory, height, fills, market) => { if (height == null) { return 0; } - const ourFills = - (market == null ? fills : fills?.filter((o) => o.marketId === market)) ?? EMPTY_ARR; + const ourFills = market == null ? fills : fills.filter((o) => o.market === market); if (ourFills.length === 0) { return 0; } @@ -752,9 +752,9 @@ export const createGetUnseenFillsCount = () => } const unseen = ourFills.filter( (o) => - o.createdAtMilliseconds > + (mapIfPresent(o.createdAt, (c) => new Date(c).valueOf()) ?? 0) > (mapIfPresent( - (memory.seenFills[o.marketId] ?? memory.seenFills[ALL_MARKETS_STRING])?.time, + (memory.seenFills[o.market ?? ''] ?? memory.seenFills[ALL_MARKETS_STRING])?.time, (t) => new Date(t).valueOf() ) ?? 0) ); From 7f67a333831cbe408c1dad35ea7b473906f0480a Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 19 Dec 2024 15:19:22 -0500 Subject: [PATCH 64/65] fix --- src/abacus-ts/lib/mapLoadable.ts | 11 ++++------- src/pages/trade/HorizontalPanel.tsx | 14 ++++++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/abacus-ts/lib/mapLoadable.ts b/src/abacus-ts/lib/mapLoadable.ts index 27cdfa162..92954d453 100644 --- a/src/abacus-ts/lib/mapLoadable.ts +++ b/src/abacus-ts/lib/mapLoadable.ts @@ -19,18 +19,15 @@ export function mergeLoadableData( } as any; } -// converts idle to pending and if a status has valid data is counts as success -export function mergeLoadableStatus( - ...status: Array> -): Exclude['status'], 'idle'> { +export function mergeLoadableStatus(...status: Array>): Loadable['status'] { if (status.some((s) => s.status === 'error' && s.data == null)) { return 'error'; } - if (status.some((s) => s.status === 'idle')) { - return 'pending'; - } if (status.some((s) => s.status === 'pending' && s.data == null)) { return 'pending'; } + if (status.some((s) => s.status === 'idle')) { + return 'idle'; + } return 'success'; } diff --git a/src/pages/trade/HorizontalPanel.tsx b/src/pages/trade/HorizontalPanel.tsx index 1694de597..06f312064 100644 --- a/src/pages/trade/HorizontalPanel.tsx +++ b/src/pages/trade/HorizontalPanel.tsx @@ -1,5 +1,6 @@ import { useCallback, useMemo, useState } from 'react'; +import { selectAccountFillsLoading } from '@/abacus-ts/selectors/account'; import { shallowEqual } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import styled from 'styled-components'; @@ -90,6 +91,7 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => { ); const hasUnseenOrderUpdates = unseenOrders > 0; + const areFillsLoading = useAppSelector(selectAccountFillsLoading) === 'pending'; const numUnseenFills = useParameterizedSelector( createGetUnseenFillsCount, showCurrentMarket ? currentMarketId : undefined @@ -227,10 +229,14 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => { value: InfoSection.Fills, label: stringGetter({ key: STRING_KEYS.FILLS }), - slotRight: fillsTagNumber && ( - - {fillsTagNumber} - + slotRight: areFillsLoading ? ( + + ) : ( + fillsTagNumber && ( + + {fillsTagNumber} + + ) ), content: ( From 5d73d721e28962deb92d8f211adb33542d63c6e8 Mon Sep 17 00:00:00 2001 From: Tyler Date: Thu, 19 Dec 2024 15:20:28 -0500 Subject: [PATCH 65/65] fix --- src/pages/trade/HorizontalPanel.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/trade/HorizontalPanel.tsx b/src/pages/trade/HorizontalPanel.tsx index 06f312064..53b661be1 100644 --- a/src/pages/trade/HorizontalPanel.tsx +++ b/src/pages/trade/HorizontalPanel.tsx @@ -270,11 +270,12 @@ export const HorizontalPanel = ({ isOpen = true, setIsOpen }: ElementProps) => { }), [ stringGetter, - currentMarketId, - showCurrentMarket, - isTablet, + areFillsLoading, fillsTagNumber, hasUnseenFillUpdates, + showCurrentMarket, + currentMarketId, + isTablet, ] );