diff --git a/.eslintrc.js b/.eslintrc.js
index f7adee3109..daa368f94b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -21,7 +21,14 @@ module.exports = {
rules: {
'no-console': 'off',
'@typescript-eslint/no-explicit-any': 'off',
- '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
+ // `ignoreRestSiblings` allows the idiomatic way to drop a key —
+ // `const { poolType, ...rest } = obj` — which is not dead code; the named sibling is
+ // how the rest is defined. `varsIgnorePattern` keeps a deliberately-unread binding
+ // legible as deliberate.
+ '@typescript-eslint/no-unused-vars': [
+ 'warn',
+ { argsIgnorePattern: '^_', varsIgnorePattern: '^_', ignoreRestSiblings: true },
+ ],
semi: [2, 'always'],
'prettier/prettier': 'error',
'@typescript-eslint/no-var-requires': 'off',
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 1ffec34602..b645ff8cec 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -80,6 +80,21 @@ jobs:
# Copy template configurations
cp -rf src/templates/* conf/
+ # The committed spec is what consumers generate their clients from, and the tests
+ # that check it read the committed copy — so a route change with no regeneration
+ # leaves them passing against a stale document. Only regenerating and comparing
+ # catches that. The generator writes the template port and placeholder wallets, so
+ # this produces the same bytes here as on any developer's machine.
+ - name: Check openapi.json is regenerated
+ shell: bash
+ run: |
+ pnpm generate:openapi
+ if ! git diff --quiet -- openapi.json; then
+ echo "::error::openapi.json does not match the routes. Run 'pnpm generate:openapi' and commit the result."
+ git --no-pager diff -- openapi.json
+ exit 1
+ fi
+
- name: Run unit test coverage
if: github.event_name == 'pull_request'
shell: bash
diff --git a/.prettierignore b/.prettierignore
index ef25ecea08..bb55cce3c5 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -3,4 +3,5 @@ certs
*.yml
coverage
dist
-vendor
\ No newline at end of file
+vendor
+openapi.json
diff --git a/CLAUDE.md b/CLAUDE.md
index 8f2a74ea2f..8882452434 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -251,19 +251,6 @@ Gateway implements RPC provider abstraction for optimized blockchain connectivit
- Regional optimization (slc, ewr, lon, fra, ams, sg, tyo)
- Connection warming for reduced latency
-### Testing RPC Providers
-Live integration tests in `scripts/`:
-- `test-infura-live.js`: Test Infura integration with real API key
-- `test-helius-live.js`: Test Helius integration with real API key
-- `test-provider-switching.js`: Test provider switching functionality
-
-Run tests:
-```bash
-# Requires configured API keys in conf/rpc/*.yml
-node scripts/test-infura-live.js
-node scripts/test-helius-live.js
-```
-
### Adding New RPC Provider
1. Create config template: `src/templates/rpc/{provider}.yml`
2. Create JSON schema: `src/templates/namespace/{provider}-schema.json`
@@ -271,8 +258,7 @@ node scripts/test-helius-live.js
4. Implement service class: `src/chains/{chain}/{provider}-service.ts`
5. Update chain connector to support provider selection
6. Add `rpcProvider` enum to network schema
-7. Create live integration test script
-8. Document configuration and usage
+7. Document configuration and usage
## Hummingbot Gateway Endpoint Standardization
- This repo standardized DEX and chain endpoints that are used by Hummingbot strategies. See this branch for the matching code, especially the Gateway connector classes https://github.com/hummingbot/hummingbot/tree/development
diff --git a/README.md b/README.md
index 54fc4cef19..8b9bf990b8 100644
--- a/README.md
+++ b/README.md
@@ -112,29 +112,37 @@ Gateway uses [Swagger](https://swagger.io/) for API documentation. When running
- `POST /chains/{chain}/approve` - Approve token spending
- `POST /chains/{chain}/wrap` - Wrap/unwrap native tokens
-#### Connector Routes (`/connectors/{dex}/{type}/*`)
-
-**Router Operations** (e.g., `/connectors/jupiter/router/*`):
-- `POST /quote` - Get swap quote from aggregator
-- `POST /swap` - Execute swap through aggregator
-
-**AMM Operations** (e.g., `/connectors/raydium/amm/*`):
-- `POST /poolInfo` - Get pool details
-- `POST /positionInfo` - Get liquidity position info
-- `POST /quoteSwap` - Get swap quote
-- `POST /executeSwap` - Execute swap
-- `POST /quoteLiquidity` - Quote add/remove liquidity
-- `POST /addLiquidity` - Add liquidity to pool
-- `POST /removeLiquidity` - Remove liquidity from pool
-
-**CLMM Operations** (e.g., `/connectors/uniswap/clmm/*`):
-- `POST /poolInfo` - Get concentrated liquidity pool info
-- `POST /openPosition` - Open new position
-- `POST /closePosition` - Close existing position
-- `POST /addLiquidity` - Add liquidity to position
-- `POST /removeLiquidity` - Remove liquidity from position
-- `POST /collectFees` - Collect earned fees
-- `POST /positionsOwned` - List owned positions
+#### Trading Routes (`/trading/{type}/*`)
+
+The trading type is a path segment and the connector is a `connector` parameter, so
+one set of routes covers every DEX.
+
+**Router** (`/trading/router/*`) — aggregators that route across pools (Jupiter, 0x, dflow, okx, titan, Uniswap, PancakeSwap):
+- `GET /trading/router/quote-swap` - Quote a swap (returns a `quoteId`)
+- `POST /trading/router/execute-quote` - Execute a previously fetched quote by id
+- `POST /trading/router/execute-swap` - Quote and execute in one call
+
+**AMM** (`/trading/amm/*`) — constant-product pools (Uniswap V2, PancakeSwap V2, Raydium CPMM, Meteora DAMM v2):
+- `GET /trading/amm/quote-swap` / `POST /trading/amm/execute-swap` - Swap against a single pool
+- `GET /trading/amm/pool-info` - Pool reserves, price, fee
+- `GET /trading/amm/position-info` - Wallet's liquidity in a pool
+- `GET /trading/amm/positions-owned` - All of a wallet's positions
+- `GET /trading/amm/quote-liquidity` - Two-sided deposit quote
+- `POST /trading/amm/open` / `close` - Open or close a position (fungible-LP AMMs deposit/withdraw in full)
+- `POST /trading/amm/add` / `remove` - Change a position's liquidity
+- `POST /trading/amm/create-pool`
+
+**CLMM** (`/trading/clmm/*`) — concentrated liquidity (Uniswap V3, PancakeSwap V3, Raydium, Meteora DLMM, Orca):
+- `GET /trading/clmm/quote-swap` / `POST /trading/clmm/execute-swap` - Swap against a single pool
+- `GET /trading/clmm/pool-info` - Pool info (optionally with bin/tick liquidity)
+- `GET /trading/clmm/position-info` - Position details
+- `GET /trading/clmm/positions-owned` - All of a wallet's positions
+- `GET /trading/clmm/quote-liquidity` - Deposit split for a candidate range
+- `GET /trading/clmm/fetch-pools` - Pool discovery from the DEX's own listing API
+- `POST /trading/clmm/open` / `close` - Open or close a position
+- `POST /trading/clmm/add` / `remove` - Change a position's liquidity
+- `POST /trading/clmm/collect-fees` - Collect earned fees
+- `POST /trading/clmm/create-pool`
#### Wallet Routes (`/wallet/*`)
- `GET /wallet` - List all wallets
@@ -405,43 +413,25 @@ docker compose up -d --build
- `DELETE /wallet/remove` - Remove wallet
- `POST /wallet/sign` - Sign message
-### Chain Operations
+### Chain Operations (`/chains/{chain}/*`)
-#### Ethereum/EVM (`/chains/ethereum`)
-- `GET /status` - Chain connection status
-- `GET /tokens` - Get token information
-- `GET /balances` - Get wallet balances
-- `GET /allowances` - Check token allowances
-- `POST /approve` - Approve token spending
-- `GET /poll` - Poll transaction status
+One parameterized set of routes serves every chain, so a new chain needs no new paths:
+- `GET /chains/{chain}/status` - Chain connection status and block height
+- `GET /chains/{chain}/estimate-gas` - Current transaction fee estimate
+- `POST /chains/{chain}/balances` - Wallet token balances
+- `POST /chains/{chain}/poll` - Poll a transaction by signature/hash
+- `POST /chains/{chain}/wrap` / `unwrap` - Wrap or unwrap the native token
-#### Solana (`/chains/solana`)
-- `GET /status` - Chain connection status
-- `GET /tokens` - Get token information
-- `GET /balances` - Get wallet balances
-- `GET /poll` - Poll transaction status
+EVM-only operations keep chain-specific paths, since they have no meaning elsewhere:
+- `POST /chains/ethereum/allowances` - Check token allowances
+- `POST /chains/ethereum/approve` - Approve token spending
### DEX Trading Endpoints
-#### Router Operations (DEX Aggregators)
-- `GET /connectors/{dex}/router/quote-swap` - Get swap quote
-- `POST /connectors/{dex}/router/execute-swap` - Execute swap without quote
-- `POST /connectors/{dex}/router/execute-quote` - Execute pre-fetched quote
-- `GET /connectors/0x/router/get-price` - Get price estimate (0x only)
-
-#### AMM Operations (Uniswap V2, PancakeSwap V2, Raydium)
-- `GET /connectors/{dex}/amm/pool-info` - Pool information
-- `GET /connectors/{dex}/amm/position-info` - LP position details
-- `POST /connectors/{dex}/amm/add-liquidity` - Add liquidity
-- `POST /connectors/{dex}/amm/remove-liquidity` - Remove liquidity
-
-#### CLMM Operations (Uniswap V3, PancakeSwap V3, Raydium, Meteora)
-- `GET /connectors/{dex}/clmm/pool-info` - Pool information
-- `GET /connectors/{dex}/clmm/positions-owned` - List positions
-- `POST /connectors/{dex}/clmm/open-position` - Open position
-- `POST /connectors/{dex}/clmm/add-liquidity` - Add to position
-- `POST /connectors/{dex}/clmm/remove-liquidity` - Remove from position
-- `POST /connectors/{dex}/clmm/collect-fees` - Collect fees
+See [Trading Routes](#trading-routes-tradingtype) above. Every trading route takes
+`chainNetwork` (e.g. `solana-mainnet-beta`) and `connector` (e.g. `jupiter`), and the
+full request/response schemas are in the OpenAPI document at `/docs` (or `openapi.json`,
+regenerated with `pnpm generate:openapi`).
## Contribution
@@ -626,64 +616,22 @@ The test directory is organized as follows:
```
/test
- /chains/ # Chain endpoint tests
- chain.test.js # Chain routes test
- ethereum.test.js # Ethereum chain tests
- solana.test.js # Solana chain tests
- /connectors/ # Connector endpoint tests by protocol
- /jupiter/ # Jupiter connector tests
- /uniswap/ # Uniswap connector tests
- /raydium/ # Raydium connector tests
- /meteora/ # Meteora connector tests
- /pancakeswap/ # PancakeSwap (EVM) connector tests
- /pancakeswap-sol/ # PancakeSwap Solana connector tests
- /mocks/ # Mock response data
- /chains/ # Chain mock responses
- chains.json # Chain routes mock response
- /ethereum/ # Ethereum mock responses
- /solana/ # Solana mock responses
- /connectors/ # Connector mock responses
- /services/ # Service tests
- /data/ # Test data files
- /wallet/ # Wallet tests
- /config/ # Configuration tests
- /jest-setup.js # Test environment configuration
-
-/scripts # Live testing and utility scripts
- test-helius-live.js # Helius RPC provider integration tests
- test-infura-live.js # Infura RPC provider integration tests
- test-provider-switching.js # RPC provider switching tests
+ /chains/ # Chain route tests (ethereum, solana)
+ /connectors/ # Connector tests, one directory per connector
+ /trading/ # The unified /trading/* route tests
+ /mocks/ # Shared mock modules (TypeScript)
+ /helpers/ /utils/ # Test helpers and fastifyWithTypeProvider
+ /services/ /wallet/ /config/ /pools/ /tokens/ /rpc/
+ jest-setup.js # Test environment configuration
+
+/scripts # Utility scripts
+ generate-openapi.ts # Write openapi.json from the live route table
+ create-wallet.ts # Wallet creation helper
+ add-bsc-tokens.ts # Token list maintenance
+ add-pancakeswap-pools.ts # Pool list maintenance
+ migrate-pool-templates.ts # Pool template migration
```
-#### RPC Provider Testing
-
-Gateway includes comprehensive testing for RPC provider integrations:
-
-**Live Integration Tests** (`scripts/test-*-live.js`):
-- Test real API connectivity with configured keys
-- Verify WebSocket connections and features
-- Measure performance improvements vs standard RPC
-- Validate network-specific endpoint mappings
-
-**Running RPC Provider Tests**:
-```bash
-# Test Infura integration (requires API key in conf/rpc/infura.yml)
-node scripts/test-infura-live.js
-
-# Test Helius integration (requires API key in conf/rpc/helius.yml)
-node scripts/test-helius-live.js
-
-# Test provider switching functionality
-node scripts/test-provider-switching.js
-```
-
-**Test Coverage Areas**:
-- Provider initialization and configuration loading
-- Automatic fallback to standard RPC on failures
-- Network-specific endpoint resolution
-- WebSocket connection establishment
-- Performance benchmarking and health checks
-
For more details on the test setup and structure, see [Test README](./test/README.md).
## Development Guide
@@ -1010,12 +958,18 @@ testProviderIntegration();
3. **Implement trading methods** based on supported operations
-4. **Create route files** following the pattern:
- - Router routes in `router-routes/` (for DEX aggregators)
- - AMM routes in `amm-routes/` (for V2-style pools)
- - CLMM routes in `clmm-routes/` (for concentrated liquidity)
+4. **Export plain operation functions** — not routes — following the pattern:
+ - Router operations in `router-routes/` (for DEX aggregators): `quoteSwap`, `executeSwap`, `executeQuote`
+ - AMM operations in `amm-routes/` (for V2-style pools)
+ - CLMM operations in `clmm-routes/` (for concentrated liquidity)
+
+ Each takes plain arguments and returns the shared response shape. Connectors no
+ longer register HTTP routes of their own; the unified `/trading/*` routes are the
+ only surface.
-5. **Add configuration and register** in `src/connectors/connector.routes.ts`
+5. **Add one entry per trading type** to `src/trading/connector-registry.ts`, which is
+ what wires the functions into the unified routes and into the `connector` enums the
+ schemas (and the OpenAPI document) advertise.
### Testing Requirements
diff --git a/docs/connectors/meteora-damm-v2.md b/docs/connectors/meteora-damm-v2.md
index fe9f3801d1..9fa16bc025 100644
--- a/docs/connectors/meteora-damm-v2.md
+++ b/docs/connectors/meteora-damm-v2.md
@@ -4,20 +4,22 @@ DAMM v2 is Meteora's constant-product AMM, implemented by the on-chain **cp-amm*
(`cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG`) and driven by the
[`@meteora-ag/cp-amm-sdk`](https://docs.meteora.ag/developer-guides/damm-v2/typescript-sdk/getting-started).
-Gateway exposes it under the standard AMM interface at `/connectors/meteora/amm/*`, mirroring
-the Raydium AMM connector:
+Gateway exposes it through the unified AMM interface at `/trading/amm/*` with
+`connector=meteora`, the same routes that serve every other AMM connector:
| Endpoint | Method | Notes |
|---|---|---|
-| `/connectors/meteora/amm/pool-info` | GET | Pool reserves, price, base (cliff) fee % |
-| `/connectors/meteora/amm/position-info` | GET | Wallet's aggregate liquidity in a pool + per-position `positions[]` breakdown |
-| `/connectors/meteora/amm/positions-owned` | GET | All of the wallet's DAMM v2 positions across pools |
-| `/connectors/meteora/amm/quote-swap` | GET | Exact-in (SELL) / exact-out (BUY) quote |
-| `/connectors/meteora/amm/execute-swap` | POST | Swap |
-| `/connectors/meteora/amm/quote-liquidity` | GET | Two-sided deposit quote |
-| `/connectors/meteora/amm/add-liquidity` | POST | Add to a specific position (`positionAddress`) or open a new one |
-| `/connectors/meteora/amm/remove-liquidity` | POST | Remove a % from a specific position (`positionAddress` **required**) |
-| `/connectors/meteora/amm/create-pool` | POST | Create + seed a new pool |
+| `/trading/amm/pool-info` | GET | Pool reserves, price, base (cliff) fee % |
+| `/trading/amm/position-info` | GET | Wallet's aggregate liquidity in a pool + per-position `positions[]` breakdown |
+| `/trading/amm/positions-owned` | GET | All of the wallet's DAMM v2 positions across pools |
+| `/trading/amm/quote-swap` | GET | Exact-in (SELL) / exact-out (BUY) quote |
+| `/trading/amm/execute-swap` | POST | Swap |
+| `/trading/amm/quote-liquidity` | GET | Two-sided deposit quote |
+| `/trading/amm/open` | POST | Open a new position (NFT) and seed it with liquidity |
+| `/trading/amm/add` | POST | Add to a specific position (`positionAddress`) or open a new one |
+| `/trading/amm/remove` | POST | Remove a % from a specific position (`positionAddress` **required**) |
+| `/trading/amm/close` | POST | Withdraw everything and close the position NFT, refunding its rent (`positionAddress` **required**) |
+| `/trading/amm/create-pool` | POST | Create + seed a new pool |
The implementation deliberately keeps to "the basics" so it fits the shared AMM schema. This
document records where DAMM v2 differs from a classic fungible-LP AMM (e.g. Raydium AMM/CPMM),
@@ -91,7 +93,7 @@ resolves the seed price in this priority order:
1. **`initialPrice`** (quote per base) if provided — `quoteTokenAmount = baseTokenAmount × initialPrice`.
2. **`quoteTokenAmount`** if provided — the `baseTokenAmount : quoteTokenAmount` ratio sets the price.
3. **Otherwise, the current market price is fetched** from the unified swap router
- (`/trading/swap/quote`, i.e. the network's configured `swapProvider` — Jupiter on Solana, which
+ (`/trading/router/quote-swap`, i.e. the network's configured `swapProvider` — Jupiter on Solana, which
aggregates existing venues) via a SELL quote of a small probe (1% of `baseTokenAmount`), and the
pool is seeded there. The probe is kept small so the quote approximates the marginal market
price; quoting the full seed amount would bake its own price impact into the seed price and
diff --git a/docs/retry-architecture.md b/docs/retry-architecture.md
new file mode 100644
index 0000000000..e2b814af05
--- /dev/null
+++ b/docs/retry-architecture.md
@@ -0,0 +1,240 @@
+# LP Close Retry Architecture
+
+**Origin:** [gateway#678](https://github.com/hummingbot/gateway/issues/678) — an Orca LP close failed with Whirlpool error `6018` (`TokenMinSubceeded`, misreported as `MATH_OVERFLOW`), the LP executor went terminally `FAILED` with the position still open on-chain, and subsequent stop requests returned 404. Fixing it properly required deciding **where retries live** across Gateway, the Hummingbot connector, the LP executor, the controller, and hummingbot-api — and auditing every layer against that model.
+
+Auditing those layers turned up defects on the paths the LP flow depends on but that #678 never named: the transaction-status contract the poller reads, and the CLMM pool-info contract the UI and agents read. Both are documented here because they share the same root cause as #678 — a caller could not tell a definitive answer from a transient one, or could not ask for what it needed at all.
+
+This document describes the issues found and the architecture that now stands, spanning five repositories: [gateway#679](https://github.com/hummingbot/gateway/pull/679), [hummingbot#8424](https://github.com/hummingbot/hummingbot/pull/8424), [hummingbot-api#217](https://github.com/hummingbot/hummingbot-api/pull/217), [hummingbot-api-client#25](https://github.com/hummingbot/hummingbot-api-client/pull/25), [condor#204](https://github.com/hummingbot/condor/pull/204).
+
+---
+
+## 1. The principle
+
+> **Gateway is a stateless transaction oracle.** One HTTP request = one attempt at one on-chain action, built from fresh on-chain state, answered with either a confirmed result or a **typed error**. Hummingbot holds the position and order state, so Hummingbot owns retries — at distinct altitudes, each answering a different question.
+
+| Layer | Question it answers | What it owns |
+|---|---|---|
+| **Gateway** | "Did *this one attempt* land?" | Reads and transport only: RPC 429s, confirmation polling until blockhash expiry, typed error classification, pre-broadcast simulation rejection. Never re-submits a write. |
+| **Connector** (`gateway_base.py`, `gateway.py`) | "Should I ask Gateway for *another attempt*?" | `_execute_with_retry`: transport timeouts only, the same for every operation. What an operation error means is the caller's decision. |
+| **LP executor** (`lp_executor.py`) | "What does this failure mean for *the position lifecycle*?" | **The close retry loop** — state-machine re-entry with a bounded budget and exponential backoff, a fresh position read before every re-submit, and the terminal close type. It passes `max_retries=0` so the connector makes exactly one request per re-entry. |
+| **Controller** (`lp_rebalancer.py`) | "What does this failure mean for *the strategy*?" | Re-creates a fresh executor with freshly computed bounds; halts instead of stacking exposure over an unresolved position. |
+| **hummingbot-api / condor** | "What survives the process, and who is told?" | Durable orphan records, listing and resolution endpoints, agent-facing warnings. |
+
+```mermaid
+flowchart TB
+ subgraph HB["Hummingbot — stateful, owns retries"]
+ C["Controller: lp_rebalancer
strategy: re-create after clean FAILED,
halt over unresolved position"]
+ E["LP executor: lp_executor
lifecycle: CLOSING re-entry — the ONE close retry loop,
max_retries + 1 attempts, exponential backoff (2ⁿ s, cap 30 s),
fresh position read before every re-submit"]
+ K["Connector: gateway_base / gateway
operation: _execute_with_retry — transport timeouts only;
close passes max_retries=0: one request per re-entry"]
+ end
+ subgraph GW["Gateway — stateless, one attempt per request"]
+ R["Route: build tx from FRESH on-chain state
quote → simulate → sign → broadcast"]
+ S["Chain layer: typed errors, 429 interceptor,
confirm-poll to blockhash expiry,
pre-broadcast simulation guard"]
+ end
+ A["hummingbot-api / condor
durable orphan records, stop semantics, agent visibility"]
+ C --> E
+ E --> K
+ K -->|"each retry = fresh rebuild"| R
+ R --> S
+ S -->|"CONFIRMED · typed error [code: X]"| K
+ K --> E
+ E -->|terminal close_type| C
+ E -.->|persisted final state| A
+```
+
+The property this preserves: **a connector-level retry gets fresh state for free**, because every re-POST re-runs the route's fetch → quote → build → simulate pipeline. A retry loop inside a Gateway route would duplicate that one layer down, per connector, invisible to the strategy, and stacking under the connector's own loop.
+
+---
+
+## 2. Issues found
+
+The #678 investigation and the adversarial review of the fix surfaced the following defects. Each is fixed in this PR family unless marked as an accepted residual (§4).
+
+### Gateway
+
+1. **Misattributed on-chain errors.** Orca `6018` was missing from the error table (reported as `MATH_OVERFLOW`), and the parser attributed custom errors to the *first* program in the log — simulation logs open with a ComputeBudget prelude, so the failing DEX program's table was never consulted. Errors are now attributed to the program on the `failed: custom program error` line, and `6018` maps to `SLIPPAGE_EXCEEDED`.
+2. **Doomed transactions were broadcast anyway.** The compute-estimation simulation's `err` was ignored (only `unitsConsumed` was read), so a transaction guaranteed to fail was signed, broadcast, and paid fees. Both send paths now reject a failed simulation with a typed 400 **before broadcast** — a failed attempt costs nothing.
+3. **Transient read errors served as definitive closure.** `Orca.getPositionInfo` swallowed every error into `null`, which the route surfaced as the position-specific 404 — so an RPC blip inside Gateway read as "position closed". It now returns `null` only for a definitive account-does-not-exist result and rethrows everything else.
+4. **A dropped transaction was indistinguishable from a pending one.** `getTransaction` (commitment `confirmed`) returns null both for a transaction awaiting confirmation and for one the cluster has never seen, and `/poll` reported both as `txStatus 0` (pending) — forever. The poll now consults the signature-status cache (with history search) and reports an unknown signature as **`NOT_FOUND` (-2)**, which is terminal once the transaction's blockhash has expired (~90 s).
+5. **The two poll routes spoke different dialects.** Ethereum's poll used raw numbers including `2` ("likely to be processed") and `3` ("likely stuck") that no consumer understood, reported not-found as `-1` (failed) after blocking the request for three in-route 1-second retries, and — via `typeof receipt.status === 'number' ? 1 : -1` — reported **reverted** transactions (receipt status `0`, which is a number) as CONFIRMED, so a reverted swap polled as filled. Both routes now share one `TransactionStatusCode` contract: `NOT_FOUND (-2) / FAILED (-1) / PENDING (0) / CONFIRMED (1)`.
+6. **Post-SDK-migration slippage exposure.** The migrated Orca close route quotes withdrawal minimums at the configured `slippagePct` (~1%) rather than the legacy 50% buffer — exactly the condition under which the #678 race is reachable. The guards above are load-bearing, not defense-in-depth.
+
+### Hummingbot connector
+
+7. **The connector silently decided what operation errors meant.** `SLIPPAGE_EXCEEDED`/`SIMULATION_FAILED` were classified inside `_execute_with_retry`, one size for all operations — and any attempt to make that operation-aware (an opt-in error set, a per-operation inner budget) produced two nested retry loops with multiplying budgets. The connector now retries **transport timeouts only**, identically for every operation; what an operation error means is the caller's decision, and for close the caller is the executor's single loop (issue 11).
+8. **The landed-but-failed shape had no error code.** A broadcast transaction that failed on-chain raised with no `[code:]` marker at all, so callers could not classify the flagship #678 failure shape. It now raises typed `TX_NOT_CONFIRMED`.
+9. **`get_position_info` swallowed every exception into `None`**, and the executor read `None` as "already closed" → `COMPLETE` — a transient RPC error during close could **abandon a live position while reporting success**. The contract is now: `None` only for a position-specific 404; everything else re-raises. Three coupled requirements: (a) the match is position-specific, because the HTTP client stamps "(Not Found)" on *every* 404 — a missing route after a redeploy read as "position gone"; (b) existence decisions use an **uncached** read (`get_position_info_fresh`) — the 5 s TTL cache stores `None` like any value, so one cached 404 masqueraded as several independent confirmations; (c) external-close detection requires the position to have been **seen on-chain at least once** plus 3 consecutive fresh misses.
+10. **Pending-transaction polling was unbounded.** `update_order_status` polled any in-flight order at 1 s forever; combined with issue 4, a dropped transaction never resolved — the order never failed and burned an RPC call per second until restart. The connector now treats `NOT_FOUND` as transient while the order is younger than `TX_NOT_FOUND_DEADLINE` (120 s, past blockhash validity) and afterwards feeds each miss to the order tracker's existing lost-order machinery, which fails the order after repeated consecutive misses. `PENDING` remains unbounded by design: the chain has seen the transaction, so it can still confirm.
+
+### LP executor
+
+11. **Close failure was terminal on the first error.** `_handle_close_failure` jumped straight to `FAILED` with the position still open. It now counts the attempt, arms exponential backoff (2ⁿ s, capped 30 s — so a Gateway restart spans a few retries instead of burning the whole budget in seconds), and stays `CLOSING`; the family hook `evaluate_max_retries` decides termination after `max_retries + 1` attempts. This re-entry is the **only** close retry loop: the executor passes `max_retries=0` so the connector makes one request per attempt, and budgets cannot multiply.
+12. **The wrong terminal close type.** `FAILED` in the executor family means "abnormal end with *no residual exposure*" — everything downstream (hold store, PnL, dashboards) assumes it. Terminating an exhausted close as `FAILED` forced a parallel side-channel at every layer. An exhausted close with the position still on-chain now terminates as an **involuntary `POSITION_HOLD`** with `hold_reason: "close_retries_exhausted"` and a zero-amount marker order carrying the position address — riding the existing hold machinery (DB-recovered on the API path) instead of a bespoke flag. `FAILED` is reserved for exhaustion with nothing left on-chain (e.g. an open rejected at simulation).
+
+### Controller, hummingbot-api, condor
+
+13. **The controller stacked exposure over a live position.** After a terminal executor still holding a position, `lp_rebalancer` created a fresh executor — a fresh `lp_executor` cannot adopt an existing position (it always mints a new one), so this doubled the funded exposure. It now halts and logs until the orphan is resolved.
+14. **Stopping a terminal executor returned 404.** The API's completion handler pops the executor from memory within one tick, so every stop against a terminal executor hit the "unknown id" branch — the #678 dead-end. Stop is now DB-aware: any DB-known, not-in-memory executor returns `already_terminated` with its final `close_type`, `position_address`, and `hold_reason`; 404 is reserved for ids the database has never seen.
+15. **Failures were invisible to agents.** The condor tick prompt listed only `RUNNING` executors, so a terminal executor with a live position *vanished from view*. The provider now surfaces orphaned executors with a warning, and `manage_executors` gained `orphaned` and `resolve_orphan` actions.
+16. **Orphans had no durable record or resolution path.** The persisted final state now carries the orphan shape; `GET /executors/positions/orphaned` lists candidates (involuntary holds, legacy `FAILED`-with-position, and `SYSTEM_CLEANUP` LP executors from an API restart — the latter flagged `needs_onchain_reconciliation` since no final state was persisted); `POST /executors/{id}/resolve-orphan` marks a recovered position so it stops surfacing.
+
+### CLMM pool-info
+
+The same audit covered the read path that agents and the dashboard use to see a pool before opening a position.
+
+17. **The bin distribution was unreachable through the unified route.** `GET /trading/clmm/pool-info` — the route hummingbot-api and condor read through — had no `binCount` in its querystring schema and called every connector as `(fastify, network, poolAddress)`, dropping the parameter orca, raydium and uniswap already implemented. Meteora returns its bins unconditionally, so the gap looked like "only Meteora has bins" rather than "nobody can ask". The route now accepts `binCount` and forwards it, and the parameter is threaded through hummingbot-api, the API client (1.5.8) and condor.
+18. **PancakeSwap had no bin support at all.** Added, reusing the V3 tick walk. The two SDKs disagree on numeric type — `@uniswap/v3-sdk` is JSBI-based, `@pancakeswap/v3-sdk` uses native `bigint` — so the walk moved to a shared `clmm-v3-utils` helper that works in `bigint`, with each connector adapting its own SDK rather than one importing the other's math.
+19. **PancakeSwap reported virtual liquidity as token amounts.** Both `baseTokenAmount` and `quoteTokenAmount` came from `pool.liquidity` — V3's active liquidity in sqrt-price space, not a token quantity — scaled by each token's decimals, so the same meaningless figure was reported for both sides. Now ERC20 `balanceOf` on the pool contract, the fix Uniswap already carried.
+20. **Raydium bypassed Gateway entirely.** hummingbot-api's pool-info special-cased Raydium: it skipped Gateway, called `api-v3.raydium.io` directly, and reshaped that response to imitate Gateway's. The transform hardcoded `active_bin_id` to `None`, `bin_step` to `1` and `bins` to `[]`, so Raydium silently returned degraded data and could not answer `binCount` at all. It now takes the same path as every other CLMM connector.
+21. **Two default RPC endpoints were dead.** `eth.llamarpc.com` and `binance.llamarpc.com` answer nothing; Gateway logged "Unable to fetch block number" at startup and every read on those chains failed — which is how a PancakeSwap pool that plainly exists reported "Pool not found". Defaults are now `eth-mainnet.g.alchemy.com/public` and `bsc-dataseed.bnbchain.org`.
+
+---
+
+## 3. The architecture
+
+### 3.1 Why close retries and open does not
+
+| Operation | If the outcome is uncertain and you blindly re-submit… | Blind-retry safe? |
+|---|---|---|
+| Swap | Second swap also executes → double spend | ❌ |
+| Open position | Second position minted → duplicate exposure | ❌ |
+| **Close position** | Success consumes the position account; a second close fails cleanly with "position not found" | ✅ idempotent |
+
+The same price move that makes a close fail (stale withdrawal minimums) also makes an open fail (stale deposit maximums), but the recovery is asymmetric:
+
+- **Close**: the intent — "remove whatever is in this position" — stays valid at any price. Retry with a fresh quote, at the connector (fast path) and the executor (paced re-entry).
+- **Open**: the intent — a range and a base/quote split computed at the old price — is stale. The executor fails cleanly with nothing on-chain (`FAILED`), and the **controller** re-decides: the next cycle recomputes bounds around the current price and creates a fresh executor. (One guard: if the add actually landed and only the bookkeeping after it threw, the executor flips to `CLOSING` to recover the funds instead of stranding them.)
+
+### 3.2 The close lifecycle
+
+```mermaid
+sequenceDiagram
+ participant EX as LP executor
+ participant CN as Connector
+ participant GW as Gateway
+ participant SOL as Chain
+
+ loop each CLOSING re-entry (≤ max_retries + 1, backoff 2ⁿ s cap 30 s)
+ EX->>CN: get_position_info_fresh (uncached)
+ alt position definitively absent (seen on-chain before + 3 fresh misses)
+ EX->>EX: already closed → COMPLETE
+ else position live or read transiently failed
+ EX->>CN: close position
+ CN->>GW: POST close-position (one request — max_retries=0)
+ GW->>SOL: fetch fresh state → quote → build → simulate
+ alt simulation fails
+ GW-->>CN: typed 400, pre-broadcast — no fee spent
+ else
+ GW->>SOL: broadcast + confirm
+ GW-->>CN: CONFIRMED or typed error
+ end
+ CN-->>EX: result or typed exception
+ end
+ end
+ Note over EX: budget exhausted, position still live →
involuntary POSITION_HOLD (hold_reason: close_retries_exhausted,
zero-amount marker order carrying position_address)
+```
+
+### 3.3 Terminal semantics
+
+```mermaid
+stateDiagram-v2
+ [*] --> OPENING
+ OPENING --> IN_RANGE: position minted
+ OPENING --> FAILED: open failed, nothing on-chain
(controller re-decides with fresh bounds)
+ OPENING --> CLOSING: add landed but bookkeeping threw
(recover the funds)
+ IN_RANGE --> CLOSING: limit price hit / stop requested
+ OUT_OF_RANGE --> CLOSING: limit price hit / stop requested
+ IN_RANGE --> OUT_OF_RANGE
+ OUT_OF_RANGE --> IN_RANGE
+ CLOSING --> CLOSING: close attempt failed,
budget remains — backoff, re-enter
+ CLOSING --> COMPLETE: closed (or confirmed already closed)
+ CLOSING --> POSITION_HOLD: budget exhausted, position live —
hold_reason set, marker order carries address
+ POSITION_HOLD --> [*]
+ COMPLETE --> [*]
+ FAILED --> [*]
+```
+
+- **`FAILED`** = abnormal end with **nothing left on-chain**. The controller may create a replacement.
+- **`POSITION_HOLD` + `hold_reason`** = residual exposure that could not be closed. Voluntary holds (`keep_position=True`) and involuntary holds are the same close type, distinguished only by the reason. The zero-amount marker order makes the hold visible to the durable hold store without corrupting spot accounting (a still-open position's pool balances are not returned tokens).
+- Consumers key off `hold_reason`, not close type: the rebalancer halts and skips accounting; the API's orphan listing is a view over involuntary holds; condor warns the agent.
+- Exception: a **force-stop** with a live position still terminates `FAILED` — the close may be in flight at the shutdown deadline, so the legacy `FAILED`-with-position orphan class covers it.
+
+### 3.4 Two topologies, one orphan lifecycle
+
+The executor is the only layer present in both deployment topologies, which is why the bounded close re-entry lives there.
+
+```mermaid
+flowchart TB
+ subgraph TA["Topology A — deployed bot"]
+ A0["lp_rebalancer controller"] --> A1["ExecutorOrchestrator"] --> A2["LPExecutor"]
+ end
+ subgraph TB2["Topology B — manage_executors (condor / API)"]
+ B0["condor agent / API user"] --> B1["manage_executors MCP tool"] --> B2["hummingbot-api ExecutorService
(no controller — controller_id is a label)"] --> B3["LPExecutor"]
+ end
+ A2 --> GW["Gateway"]
+ B3 --> GW
+```
+
+When a close exhausts its budget:
+
+```mermaid
+flowchart TD
+ T["Executor terminates POSITION_HOLD
hold_reason: close_retries_exhausted"] --> P["hummingbot-api persists final state
with orphan shape"]
+ T --> H["Controller (topology A) halts:
no new positions over the orphan"]
+ P --> L["GET /executors/positions/orphaned
lists the candidate"]
+ P --> W["condor tick prompt warns the agent"]
+ L --> R["Operator/agent closes the position
via gateway tools (remove liquidity by address —
a fresh lp_executor CANNOT adopt it)"]
+ R --> S["POST /executors/{id}/resolve-orphan
clears the listing and warnings"]
+ S --> X["Restart the controller —
its halt is in-memory; restart is the
acknowledgment that recovery is done"]
+```
+
+Also listed as orphan candidates: legacy `FAILED` executors whose final state carries a position address (force-stop stragglers), and `SYSTEM_CLEANUP` LP executors from an API restart (position address unknown — reconcile against on-chain positions).
+
+### 3.5 Transaction status polling
+
+Both chains' `/poll` routes share one `TransactionStatusCode` contract; the connector's 1 s poller acts on it:
+
+| `txStatus` | Meaning | Connector behavior |
+|---|---|---|
+| `1` CONFIRMED | Landed without error | Fill the order |
+| `0` PENDING | The chain has seen the transaction (Solana: signature status; EVM: in the mempool) | Keep polling — it can still confirm (unbounded by design) |
+| `-1` FAILED | Landed with an error / reverted | Fail the order, trigger `TransactionFailure` |
+| `-2` NOT_FOUND | Unknown to the chain — never received or dropped (Solana: terminal once the blockhash expires; EVM: the mempool is visible via `getTransaction`, so not-found already means dropped) | Transient while the order is younger than 120 s (blockhash validity margin); afterwards each miss counts toward the tracker's lost-order limit → order fails after repeated consecutive misses |
+
+Transient poll errors (RPC failures) report `PENDING`, never `NOT_FOUND` — an unknown outcome is a reason to poll again, not to give up. Note the LP flow's writes do not depend on this poller to progress: the connector's operation calls only return a signature after in-request confirmation. The bound matters for flows that record a hash at submission time, and for the RPC cost of stuck orders.
+
+### 3.6 CLMM pool-info and bins
+
+One route answers for every CLMM connector, and every caller reaches it through the same chain:
+
+```mermaid
+flowchart LR
+ A["condor
manage_gateway_clmm(bin_count=N)"] --> B["hummingbot-api-client 1.5.8
get_pool_info(bin_count=N)"]
+ B --> C["hummingbot-api
GET /gateway/clmm/pool-info?bin_count=N"]
+ C --> D["gateway
GET /trading/clmm/pool-info?binCount=N"]
+ D --> E["connector pool-info
bins computed only when asked"]
+```
+
+`binCount` is a **request for work, not a formatting flag** — the bins are read from chain state, so the default of `0` exists to keep the common call cheap:
+
+| Connector | Bins | Cost of `binCount = N` |
+|---|---|---|
+| Meteora | Always returned; ignores `binCount` | Already paid — the DLMM pool exposes its bins directly |
+| Orca | On request | Roughly flat: one position fetch, then local math |
+| Raydium | On request | Roughly flat: tick-array fetch, then local math |
+| Uniswap | On request | Linear: `N + 1` parallel `pool.ticks()` eth_calls |
+| PancakeSwap | On request | Linear: `N + 1` parallel `pool.ticks()` eth_calls |
+
+Gateway caps `binCount` at 401. Because the EVM cost scales with `N` while the Solana cost does not, callers that render a depth column should treat the window size as a parameter rather than a constant.
+
+The output shape mirrors Meteora's `bins[]` for every connector — `{ binId, price, baseTokenAmount, quoteTokenAmount }` — and is centred on the active tick: bins below the active price hold only quote, bins above hold only base, and the one bin straddling it holds both.
+
+---
+
+## 4. Accepted residual risks
+
+- **The controller halt is process-local.** A bot restart clears `_orphaned_position_address` and the rebalancer can reopen while the orphan is unresolved; conversely, resolving the orphan does not un-halt a running controller (restart is the acknowledgment step). Controllers have no persisted state to rebuild the latch from; the durable guard is the API-layer orphan record, listing, and agent warnings.
+- **Force-stop stragglers.** A force-stop does not cancel an in-flight close; a lingering attempt can land after the executor is persisted with the orphan shape, making the record stale-wrong. `resolve-orphan` (after an on-chain check) is the correction path.
+- **Deployment coupling.** hummingbot-api runs the *installed* hummingbot wheel — the executor- and connector-level fixes reach topology B only after the wheel is rebuilt and reinstalled.
+- **`SYSTEM_CLEANUP` orphans have no position address** (no final state was persisted); they are listed for on-chain reconciliation rather than resolved automatically.
+- **A lost-order verdict can race a very late confirmation.** An order failed via the NOT_FOUND deadline could in principle confirm afterwards if an RPC node was more than two minutes behind the cluster; the deadline plus the consecutive-miss requirement makes this require a broken RPC, and the alternative — waiting forever — is strictly worse.
diff --git a/jest.config.js b/jest.config.js
index 58a19a83e7..81d4d228ef 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -20,12 +20,7 @@ module.exports = {
],
modulePathIgnorePatterns: ['/dist/'],
setupFilesAfterEnv: ['/test/jest-setup.js'],
- testPathIgnorePatterns: [
- '/node_modules/',
- 'test-helpers',
- '/test-scripts/',
- '/test/lifecycle/',
- ],
+ testPathIgnorePatterns: ['/node_modules/', 'test-helpers', '/test-scripts/', '/test/lifecycle/'],
testMatch: ['/test/**/*.test.ts', '/test/**/*.test.js'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
diff --git a/openapi.json b/openapi.json
index dec2716d23..9f76a841b0 100644
--- a/openapi.json
+++ b/openapi.json
@@ -3,7 +3,7 @@
"info": {
"title": "Hummingbot Gateway",
"description": "API endpoints for interacting with DEXs and blockchains",
- "version": "dev-2.11.0"
+ "version": "dev-2.17.0"
},
"components": {
"parameters": {
@@ -15,9769 +15,3788 @@
}
}
},
- "schemas": {}
- },
- "paths": {
- "/config/": {
- "get": {
- "tags": ["/config"],
- "description": "Get configuration settings. Returns all configurations if no parameters are specified. Use namespace to get a specific config (e.g., server, ethereum-mainnet, solana-mainnet-beta, uniswap).",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "server": {
- "value": "server"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "uniswap": {
- "value": "uniswap"
- }
- },
- "in": "query",
- "name": "namespace",
- "required": false,
- "description": "Optional configuration namespace (e.g., \"server\", \"ethereum-mainnet\", \"solana-mainnet-beta\", \"uniswap\")"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": true
- }
- }
- }
- }
- }
- }
- },
- "/config/update": {
- "post": {
- "tags": ["/config"],
- "description": "Update a specific configuration value",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "namespace": {
- "description": "Configuration namespace (e.g., \"server\", \"ethereum-mainnet\", \"solana-mainnet-beta\", \"uniswap\")",
- "type": "string",
- "example": "server"
- },
- "path": {
- "description": "Configuration path within the namespace (e.g., \"nodeURL\", \"manualGasPrice\")",
- "type": "string",
- "example": "nodeURL"
- },
- "value": {
- "description": "Configuration value",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "number"
- },
- {
- "type": "boolean"
- },
- {
- "type": "object",
- "properties": {}
- },
- {
- "type": "array",
- "items": {}
- }
- ]
- }
- },
- "required": ["namespace", "path", "value"]
- },
- "examples": {
- "example1": {
- "value": {
- "namespace": "solana-mainnet-beta",
- "path": "maxFee",
- "value": 0.01
- }
- },
- "example2": {
- "value": {
- "namespace": "ethereum-mainnet",
- "path": "nodeURL",
- "value": "https://eth-mainnet.g.alchemy.com/v2/your-api-key"
- }
- },
- "example3": {
- "value": {
- "namespace": "ethereum-mainnet",
- "path": "gasLimitTransaction",
- "value": 3000000
- }
- },
- "example4": {
- "value": {
- "namespace": "solana-devnet",
- "path": "retryCount",
- "value": 5
- }
- },
- "example5": {
- "value": {
- "namespace": "server",
- "path": "port",
- "value": 15888
- }
- }
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "description": "Status message",
- "type": "string"
- }
- },
- "required": ["message"]
- }
- }
- }
- }
- }
- }
- },
- "/config/chains": {
- "get": {
- "tags": ["/config"],
- "description": "Returns a list of available blockchain networks supported by Gateway.",
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chains": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "chain": {
- "type": "string"
- },
- "networks": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- },
- "required": ["chain", "networks"]
- }
- }
- },
- "required": ["chains"]
- }
- }
- }
- }
- }
- }
- },
- "/config/connectors": {
- "get": {
- "tags": ["/config"],
- "description": "Returns a list of available DEX connectors and their supported blockchain networks.",
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connectors": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
- },
- "trading_types": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "chain": {
- "type": "string"
- },
- "networks": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- },
- "required": ["name", "trading_types", "chain", "networks"]
- }
- }
- },
- "required": ["connectors"]
- }
- }
- }
- }
- }
- }
- },
- "/config/namespaces": {
- "get": {
- "tags": ["/config"],
- "description": "Returns a list of all configuration namespaces available in Gateway.",
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "namespaces": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- },
- "required": ["namespaces"]
- }
- }
- }
- }
- }
- }
- },
- "/wallet/": {
- "get": {
- "tags": ["/wallet"],
- "description": "Get all wallets across different chains",
- "parameters": [
- {
- "schema": {
- "default": true,
- "type": "boolean"
- },
- "in": "query",
- "name": "showHardware",
- "required": false
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain name",
- "type": "string",
- "example": "solana"
- },
- "walletAddresses": {
- "description": "List of regular wallet addresses with private keys",
- "type": "array",
- "items": {
- "description": "Wallet address (Ethereum format: 0x... or Solana format: base58)",
- "type": "string"
- }
- },
- "hardwareWalletAddresses": {
- "description": "List of hardware wallet addresses (Ledger)",
- "type": "array",
- "items": {
- "description": "Wallet address (Ethereum format: 0x... or Solana format: base58)",
- "type": "string"
- }
- }
- },
- "required": ["chain", "walletAddresses"]
- }
- }
- }
- }
- }
- }
- }
- },
- "/wallet/add": {
- "post": {
- "tags": ["/wallet"],
- "description": "Add a new wallet using a private key",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain to add wallet to",
- "enum": ["ethereum", "solana"],
- "type": "string",
- "example": "solana"
- },
- "privateKey": {
- "description": "Private key for the wallet",
- "type": "string",
- "example": "\u003Cyour-private-key\u003E"
- },
- "setDefault": {
- "description": "Set this wallet as the default for the chain",
- "default": false,
- "type": "boolean"
- }
- },
- "required": ["chain", "privateKey"]
- },
- "example": {
- "chain": "solana",
- "privateKey": "\u003Cyour-private-key\u003E",
- "setDefault": true
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "description": "The wallet address that was added",
- "type": "string"
- }
- },
- "required": ["address"]
- }
- }
- }
- }
- }
- }
- },
- "/wallet/add-hardware": {
- "post": {
- "tags": ["/wallet"],
- "description": "Add a hardware wallet",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain for hardware wallet",
- "enum": ["ethereum", "solana"],
- "default": "solana",
- "type": "string",
- "example": "solana"
- },
- "address": {
- "description": "Hardware wallet address to add (must exist on connected Ledger device)",
- "type": "string"
- },
- "setDefault": {
- "description": "Set this wallet as the default for the chain",
- "default": false,
- "type": "boolean"
- }
- },
- "required": ["chain", "address"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "description": "The hardware wallet address that was added",
- "type": "string"
- },
- "publicKey": {
- "description": "Public key of the hardware wallet",
- "type": "string"
- },
- "derivationPath": {
- "description": "BIP32/BIP44 derivation path used",
- "type": "string"
- },
- "message": {
- "description": "Success message",
- "type": "string"
- }
- },
- "required": ["address", "publicKey", "derivationPath", "message"]
- }
- }
- }
- }
- }
- }
- },
- "/wallet/remove": {
- "delete": {
- "tags": ["/wallet"],
- "description": "Remove a wallet by its address (automatically detects wallet type)",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain to remove wallet from",
- "enum": ["ethereum", "solana"],
- "type": "string",
- "example": "solana"
- },
- "address": {
- "description": "Wallet address to remove",
- "type": "string"
- }
- },
- "required": ["chain", "address"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "description": "Success message indicating wallet type removed",
- "type": "string"
- }
- },
- "required": ["message"]
- }
- }
- }
- }
- }
- }
- },
- "/wallet/setDefault": {
- "post": {
- "tags": ["/wallet"],
- "description": "Set a wallet as default for a specific chain",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain to set default wallet for",
- "enum": ["ethereum", "solana"],
- "type": "string",
- "example": "solana"
- },
- "address": {
- "description": "Wallet address to set as default",
- "type": "string"
- }
- },
- "required": ["chain", "address"]
- },
- "examples": {
- "example1": {
- "value": {
- "chain": "ethereum",
- "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2BDf8"
- }
- },
- "example2": {
- "value": {
- "chain": "solana",
- "address": "7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi"
- }
- }
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "description": "Success message",
- "type": "string"
- },
- "chain": {
- "description": "Chain name",
- "type": "string"
- },
- "address": {
- "description": "Default wallet address",
- "type": "string"
- }
- },
- "required": ["message", "chain", "address"]
- }
- }
- }
- }
- }
- }
- },
- "/tokens/{symbolOrAddress}": {
- "get": {
- "tags": ["/tokens"],
- "description": "Get a specific token by symbol or address",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "ethereum": {
- "value": "ethereum"
- },
- "solana": {
- "value": "solana"
- }
- },
- "in": "query",
- "name": "chain",
- "required": true,
- "description": "Blockchain network (e.g., ethereum, solana)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "mainnet": {
- "value": "mainnet"
- },
- "mainnet-beta": {
- "value": "mainnet-beta"
- },
- "devnet": {
- "value": "devnet"
- }
- },
- "in": "query",
- "name": "network",
- "required": true,
- "description": "Network name (e.g., mainnet, mainnet-beta)"
- },
- {
- "schema": {
- "type": "string"
- },
- "in": "path",
- "name": "symbolOrAddress",
- "required": true,
- "description": "Token symbol or address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "token": {
- "type": "object",
- "properties": {
- "chainId": {
- "description": "The chain ID",
- "type": "number",
- "example": 1
- },
- "name": {
- "description": "The full name of the token",
- "type": "string",
- "example": "USD Coin"
- },
- "symbol": {
- "description": "The token symbol",
- "type": "string",
- "example": "USDC"
- },
- "address": {
- "description": "The token contract address",
- "type": "string",
- "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- },
- "decimals": {
- "description": "The number of decimals the token uses",
- "minimum": 0,
- "maximum": 255,
- "type": "number",
- "example": 6
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- }
- },
- "required": ["name", "symbol", "address", "decimals"]
- },
- "chain": {
- "type": "string"
- },
- "network": {
- "type": "string"
- }
- },
- "required": ["token", "chain", "network"]
- }
- }
- }
- }
- }
- }
- },
- "/tokens/find/{address}": {
- "get": {
- "tags": ["/tokens"],
- "description": "Get token information with market data from GeckoTerminal by address",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "ethereum-base": {
- "value": "ethereum-base"
- },
- "ethereum-polygon": {
- "value": "ethereum-polygon"
- }
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "So11111111111111111111111111111111111111112": {
- "value": "So11111111111111111111111111111111111111112"
- },
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
- "value": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- }
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Token contract address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chainId": {
- "description": "The chain ID",
- "type": "number",
- "example": 1
- },
- "name": {
- "description": "The full name of the token",
- "type": "string",
- "example": "USD Coin"
- },
- "symbol": {
- "description": "The token symbol",
- "type": "string",
- "example": "USDC"
- },
- "address": {
- "description": "The token contract address",
- "type": "string",
- "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- },
- "decimals": {
- "description": "The number of decimals the token uses",
- "minimum": 0,
- "maximum": 255,
- "type": "number",
- "example": 6
- },
- "geckoData": {
- "type": "object",
- "allOf": [
- {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- },
- {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- }
- ]
- }
- },
- "required": ["name", "symbol", "address", "decimals"]
- }
- }
- }
- }
- }
- }
- },
- "/tokens/": {
- "get": {
- "tags": ["/tokens"],
- "description": "List tokens from token lists with optional filtering",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "ethereum": {
- "value": "ethereum"
- },
- "solana": {
- "value": "solana"
- }
- },
- "in": "query",
- "name": "chain",
- "required": false,
- "description": "Blockchain network (e.g., ethereum, solana)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "mainnet": {
- "value": "mainnet"
- },
- "mainnet-beta": {
- "value": "mainnet-beta"
- },
- "devnet": {
- "value": "devnet"
- }
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Network name (e.g., mainnet, mainnet-beta)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "USDC": {
- "value": "USDC"
- },
- "USD": {
- "value": "USD"
- }
- },
- "in": "query",
- "name": "search",
- "required": false,
- "description": "Search term for filtering tokens by symbol or name"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "tokens": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "chainId": {
- "description": "The chain ID",
- "type": "number",
- "example": 1
- },
- "name": {
- "description": "The full name of the token",
- "type": "string",
- "example": "USD Coin"
- },
- "symbol": {
- "description": "The token symbol",
- "type": "string",
- "example": "USDC"
- },
- "address": {
- "description": "The token contract address",
- "type": "string",
- "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- },
- "decimals": {
- "description": "The number of decimals the token uses",
- "minimum": 0,
- "maximum": 255,
- "type": "number",
- "example": 6
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- }
- },
- "required": ["name", "symbol", "address", "decimals"]
- }
- }
- },
- "required": ["tokens"]
- }
- }
- }
- }
- }
- },
- "post": {
- "tags": ["/tokens"],
- "description": "Add a new token to a token list",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "description": "Blockchain network (e.g., ethereum, solana)",
- "type": "string",
- "example": "ethereum"
- },
- "network": {
- "description": "Network name (e.g., mainnet, mainnet-beta)",
- "type": "string",
- "example": "mainnet"
- },
- "token": {
- "type": "object",
- "properties": {
- "chainId": {
- "description": "The chain ID",
- "type": "number",
- "example": 1
- },
- "name": {
- "description": "The full name of the token",
- "type": "string",
- "example": "USD Coin"
- },
- "symbol": {
- "description": "The token symbol",
- "type": "string",
- "example": "USDC"
- },
- "address": {
- "description": "The token contract address",
- "type": "string",
- "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- },
- "decimals": {
- "description": "The number of decimals the token uses",
- "minimum": 0,
- "maximum": 255,
- "type": "number",
- "example": 6
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- }
- },
- "required": ["name", "symbol", "address", "decimals"]
- }
- },
- "required": ["chain", "network", "token"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "description": "Success message",
- "type": "string"
- },
- "requiresRestart": {
- "description": "Whether gateway restart is required",
- "default": true,
- "type": "boolean"
- }
- },
- "required": ["message", "requiresRestart"]
- }
- }
- }
- }
- }
- }
- },
- "/tokens/save/{address}": {
- "post": {
- "tags": ["/tokens"],
- "description": "Find token from GeckoTerminal and save it to the token list",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "ethereum-base": {
- "value": "ethereum-base"
- },
- "ethereum-polygon": {
- "value": "ethereum-polygon"
- }
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "So11111111111111111111111111111111111111112": {
- "value": "So11111111111111111111111111111111111111112"
- },
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
- "value": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- }
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Token contract address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- },
- "token": {
- "type": "object",
- "properties": {
- "chainId": {
- "description": "The chain ID",
- "type": "number",
- "example": 1
- },
- "name": {
- "description": "The full name of the token",
- "type": "string",
- "example": "USD Coin"
- },
- "symbol": {
- "description": "The token symbol",
- "type": "string",
- "example": "USDC"
- },
- "address": {
- "description": "The token contract address",
- "type": "string",
- "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- },
- "decimals": {
- "description": "The number of decimals the token uses",
- "minimum": 0,
- "maximum": 255,
- "type": "number",
- "example": 6
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "coingeckoCoinId": {
- "description": "CoinGecko coin ID if available",
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ]
- },
- "imageUrl": {
- "description": "Token image URL",
- "type": "string"
- },
- "priceUsd": {
- "description": "Current price in USD",
- "type": "string"
- },
- "volumeUsd24h": {
- "description": "24h trading volume in USD",
- "type": "string"
- },
- "marketCapUsd": {
- "description": "Market capitalization in USD",
- "type": "string"
- },
- "fdvUsd": {
- "description": "Fully diluted valuation in USD",
- "type": "string"
- },
- "totalSupply": {
- "description": "Normalized total supply (human-readable)",
- "type": "string"
- },
- "topPools": {
- "description": "Array of top pool addresses",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "coingeckoCoinId",
- "imageUrl",
- "priceUsd",
- "volumeUsd24h",
- "marketCapUsd",
- "fdvUsd",
- "totalSupply",
- "topPools",
- "timestamp"
- ]
- }
- },
- "required": ["name", "symbol", "address", "decimals"]
- }
- },
- "required": ["message", "token"]
- }
- }
- }
- }
- }
- }
- },
- "/tokens/{address}": {
- "delete": {
- "tags": ["/tokens"],
- "description": "Remove a token from a token list by address",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "ethereum": {
- "value": "ethereum"
- },
- "solana": {
- "value": "solana"
- }
- },
- "in": "query",
- "name": "chain",
- "required": true,
- "description": "Blockchain network (e.g., ethereum, solana)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "mainnet": {
- "value": "mainnet"
- },
- "mainnet-beta": {
- "value": "mainnet-beta"
- },
- "devnet": {
- "value": "devnet"
- }
- },
- "in": "query",
- "name": "network",
- "required": true,
- "description": "Network name (e.g., mainnet, mainnet-beta)"
- },
- {
- "schema": {
- "type": "string"
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Token address to remove"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "description": "Success message",
- "type": "string"
- },
- "requiresRestart": {
- "description": "Whether gateway restart is required",
- "default": true,
- "type": "boolean"
- }
- },
- "required": ["message", "requiresRestart"]
- }
- }
- }
- }
- }
- }
- },
- "/pools/{tradingPair}": {
- "get": {
- "tags": ["/pools"],
- "description": "Get a specific pool by trading pair",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "raydium": {
- "value": "raydium"
- },
- "meteora": {
- "value": "meteora"
- },
- "uniswap": {
- "value": "uniswap"
- },
- "orca": {
- "value": "orca"
- }
- },
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "Connector (raydium, meteora, uniswap, orca)"
- },
- {
- "schema": {
- "default": "mainnet-beta",
- "type": "string"
- },
- "examples": {
- "mainnet-beta": {
- "value": "mainnet-beta"
- },
- "mainnet": {
- "value": "mainnet"
- }
- },
- "in": "query",
- "name": "network",
- "required": true,
- "description": "Network name (mainnet, mainnet-beta, etc)"
- },
- {
- "schema": {
- "enum": ["amm", "clmm"],
- "type": "string"
- },
- "examples": {
- "amm": {
- "value": "amm"
- },
- "clmm": {
- "value": "clmm"
- }
- },
- "in": "query",
- "name": "type",
- "required": true,
- "description": "Pool type"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "SOL-USDC": {
- "value": "SOL-USDC"
- },
- "ETH-USDC": {
- "value": "ETH-USDC"
- }
- },
- "in": "path",
- "name": "tradingPair",
- "required": true,
- "description": "Trading pair (e.g., SOL-USDC, ETH-USDC)"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "type": "string"
- },
- "baseSymbol": {
- "type": "string"
- },
- "quoteSymbol": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "address": {
- "type": "string"
- }
- },
- "required": [
- "type",
- "network",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "address"
- ]
- }
- }
- }
- },
- "404": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- }
- }
- },
- "/pools/find/{address}": {
- "get": {
- "tags": ["/pools"],
- "description": "Get detailed pool information by address from GeckoTerminal",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "ethereum-base": {
- "value": "ethereum-base"
- },
- "ethereum-polygon": {
- "value": "ethereum-polygon"
- }
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2": {
- "value": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
- },
- "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640": {
- "value": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
- }
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Pool contract address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "type": "string"
- },
- "baseSymbol": {
- "type": "string"
- },
- "quoteSymbol": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "address": {
- "type": "string"
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "volumeUsd24h": {
- "description": "24-hour trading volume in USD",
- "type": "string"
- },
- "liquidityUsd": {
- "description": "Total liquidity in USD",
- "type": "string"
- },
- "priceNative": {
- "description": "Base token price in quote token",
- "type": "string"
- },
- "priceUsd": {
- "description": "Base token price in USD",
- "type": "string"
- },
- "buys24h": {
- "description": "Number of buy transactions in 24h",
- "type": "number"
- },
- "sells24h": {
- "description": "Number of sell transactions in 24h",
- "type": "number"
- },
- "apr": {
- "description": "Annual percentage rate",
- "type": "number"
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "volumeUsd24h",
- "liquidityUsd",
- "priceNative",
- "priceUsd",
- "buys24h",
- "sells24h",
- "timestamp"
- ]
- }
- },
- "required": [
- "type",
- "network",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "address"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/pools/find": {
- "get": {
- "tags": ["/pools"],
- "description": "Find pools for a token pair from GeckoTerminal",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "ethereum-base": {
- "value": "ethereum-base"
- },
- "ethereum-polygon": {
- "value": "ethereum-polygon"
- }
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "raydium": {
- "value": "raydium"
- },
- "meteora": {
- "value": "meteora"
- },
- "uniswap": {
- "value": "uniswap"
- },
- "pancakeswap": {
- "value": "pancakeswap"
- },
- "pancakeswap-sol": {
- "value": "pancakeswap-sol"
- },
- "orca": {
- "value": "orca"
- }
- },
- "in": "query",
- "name": "connector",
- "required": false,
- "description": "Filter by connector name (e.g., raydium, meteora, uniswap, pancakeswap, pancakeswap-sol)"
- },
- {
- "schema": {
- "enum": ["clmm", "amm"],
- "default": "clmm",
- "type": "string"
- },
- "examples": {
- "clmm": {
- "value": "clmm"
- },
- "amm": {
- "value": "amm"
- }
- },
- "in": "query",
- "name": "type",
- "required": false,
- "description": "Filter by pool type: clmm (v3-style concentrated liquidity) or amm (v2-style)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "SOL": {
- "value": "SOL"
- },
- "So11111111111111111111111111111111111111112": {
- "value": "So11111111111111111111111111111111111111112"
- },
- "USDC": {
- "value": "USDC"
- }
- },
- "in": "query",
- "name": "tokenA",
- "required": false,
- "description": "First token symbol or contract address (optional - for filtering by token pair)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "USDC": {
- "value": "USDC"
- },
- "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": {
- "value": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
- },
- "SOL": {
- "value": "SOL"
- }
- },
- "in": "query",
- "name": "tokenB",
- "required": false,
- "description": "Second token symbol or contract address (optional - for filtering by token pair)"
- },
- {
- "schema": {
- "minimum": 1,
- "maximum": 10,
- "default": 10,
- "type": "number"
- },
- "in": "query",
- "name": "pages",
- "required": false,
- "description": "Number of pages to fetch from GeckoTerminal (1-10, default: 10)"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "type": "string"
- },
- "baseSymbol": {
- "type": "string"
- },
- "quoteSymbol": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "address": {
- "type": "string"
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "volumeUsd24h": {
- "description": "24-hour trading volume in USD",
- "type": "string"
- },
- "liquidityUsd": {
- "description": "Total liquidity in USD",
- "type": "string"
- },
- "priceNative": {
- "description": "Base token price in quote token",
- "type": "string"
- },
- "priceUsd": {
- "description": "Base token price in USD",
- "type": "string"
- },
- "buys24h": {
- "description": "Number of buy transactions in 24h",
- "type": "number"
- },
- "sells24h": {
- "description": "Number of sell transactions in 24h",
- "type": "number"
- },
- "apr": {
- "description": "Annual percentage rate",
- "type": "number"
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "volumeUsd24h",
- "liquidityUsd",
- "priceNative",
- "priceUsd",
- "buys24h",
- "sells24h",
- "timestamp"
- ]
- }
- },
- "required": [
- "type",
- "network",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "address"
- ]
- }
- }
- }
- }
- }
- }
- }
- },
- "/pools/": {
- "get": {
- "tags": ["/pools"],
- "description": "List all pools for a connector, optionally filtered by network, type, or search term",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "raydium": {
- "value": "raydium"
- },
- "meteora": {
- "value": "meteora"
- },
- "uniswap": {
- "value": "uniswap"
- },
- "orca": {
- "value": "orca"
- }
- },
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "Connector (raydium, meteora, uniswap, orca)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "mainnet": {
- "value": "mainnet"
- },
- "mainnet-beta": {
- "value": "mainnet-beta"
- },
- "base": {
- "value": "base"
- }
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Optional: filter by network (mainnet, mainnet-beta, etc)"
- },
- {
- "schema": {
- "enum": ["clmm", "amm"],
- "type": "string"
- },
- "examples": {
- "clmm": {
- "value": "clmm"
- },
- "amm": {
- "value": "amm"
- }
- },
- "in": "query",
- "name": "type",
- "required": false,
- "description": "Optional: filter by pool type"
- },
- {
- "schema": {
- "type": "string"
- },
- "in": "query",
- "name": "search",
- "required": false,
- "description": "Optional: search by token symbol or address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "type": "string"
- },
- "baseSymbol": {
- "type": "string"
- },
- "quoteSymbol": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "address": {
- "type": "string"
- }
- },
- "required": [
- "type",
- "network",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "address"
- ]
- }
- }
- }
- }
- }
- }
- },
- "post": {
- "tags": ["/pools"],
- "description": "Add a new pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector (raydium, meteora, uniswap, orca)",
- "type": "string",
- "example": "raydium"
- },
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "description": "Network name (mainnet, mainnet-beta, etc)",
- "default": "mainnet-beta",
- "type": "string",
- "example": "mainnet-beta"
- },
- "address": {
- "description": "Pool contract address",
- "type": "string"
- },
- "baseSymbol": {
- "description": "Base token symbol",
- "type": "string",
- "example": "SOL"
- },
- "quoteSymbol": {
- "description": "Quote token symbol",
- "type": "string",
- "example": "USDC"
- },
- "baseTokenAddress": {
- "description": "Base token contract address",
- "type": "string",
- "example": "So11111111111111111111111111111111111111112"
- },
- "quoteTokenAddress": {
- "description": "Quote token contract address",
- "type": "string",
- "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
- },
- "feePct": {
- "description": "Pool fee percentage (optional - fetched from pool-info if not provided)",
- "minimum": 0,
- "maximum": 100,
- "type": "number",
- "example": 0.25
- }
- },
- "required": [
- "connector",
- "type",
- "network",
- "address",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress"
- ]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- },
- "required": ["message"]
- }
- }
- }
- },
- "400": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- }
- }
- },
- "/pools/save/{address}": {
- "post": {
- "tags": ["/pools"],
- "description": "Find pool from GeckoTerminal and save it to the pool list",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "solana-mainnet-beta": {
- "value": "solana-mainnet-beta"
- },
- "ethereum-mainnet": {
- "value": "ethereum-mainnet"
- },
- "ethereum-base": {
- "value": "ethereum-base"
- },
- "ethereum-polygon": {
- "value": "ethereum-polygon"
- }
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2": {
- "value": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
- },
- "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640": {
- "value": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
- }
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Pool contract address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- },
- "pool": {
- "type": "object",
- "properties": {
- "type": {
- "description": "Pool type",
- "enum": ["clmm", "amm"],
- "type": "string",
- "example": "clmm"
- },
- "network": {
- "type": "string"
- },
- "baseSymbol": {
- "type": "string"
- },
- "quoteSymbol": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "address": {
- "type": "string"
- },
- "geckoData": {
- "type": "object",
- "properties": {
- "volumeUsd24h": {
- "description": "24-hour trading volume in USD",
- "type": "string"
- },
- "liquidityUsd": {
- "description": "Total liquidity in USD",
- "type": "string"
- },
- "priceNative": {
- "description": "Base token price in quote token",
- "type": "string"
- },
- "priceUsd": {
- "description": "Base token price in USD",
- "type": "string"
- },
- "buys24h": {
- "description": "Number of buy transactions in 24h",
- "type": "number"
- },
- "sells24h": {
- "description": "Number of sell transactions in 24h",
- "type": "number"
- },
- "apr": {
- "description": "Annual percentage rate",
- "type": "number"
- },
- "timestamp": {
- "description": "Unix timestamp (ms) when data was fetched",
- "type": "number"
- }
- },
- "required": [
- "volumeUsd24h",
- "liquidityUsd",
- "priceNative",
- "priceUsd",
- "buys24h",
- "sells24h",
- "timestamp"
- ]
- }
- },
- "required": [
- "type",
- "network",
- "baseSymbol",
- "quoteSymbol",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "address"
- ]
- }
- },
- "required": ["message", "pool"]
- }
- }
- }
- }
- }
- }
- },
- "/pools/{address}": {
- "delete": {
- "tags": ["/pools"],
- "description": "Remove a pool by address",
- "parameters": [
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "raydium": {
- "value": "raydium"
- },
- "meteora": {
- "value": "meteora"
- },
- "uniswap": {
- "value": "uniswap"
- },
- "orca": {
- "value": "orca"
- }
- },
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "Connector (raydium, meteora, uniswap, orca)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "mainnet": {
- "value": "mainnet"
- },
- "mainnet-beta": {
- "value": "mainnet-beta"
- }
- },
- "in": "query",
- "name": "network",
- "required": true,
- "description": "Network name (mainnet, mainnet-beta, etc)"
- },
- {
- "schema": {
- "type": "string"
- },
- "examples": {
- "amm": {
- "value": "amm"
- },
- "clmm": {
- "value": "clmm"
- }
- },
- "in": "query",
- "name": "type",
- "required": true,
- "description": "Pool type"
- },
- {
- "schema": {
- "type": "string"
- },
- "in": "path",
- "name": "address",
- "required": true,
- "description": "Pool contract address to remove"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- },
- "required": ["message"]
- }
- }
- }
- },
- "404": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- }
- }
- },
- "/trading/swap/quote": {
- "get": {
- "tags": ["/trading/swap"],
- "description": "Get a swap quote for any supported chain",
- "parameters": [
- {
- "schema": {
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet, ethereum-polygon)"
- },
- {
- "schema": {
- "default": "jupiter/router",
- "type": "string"
- },
- "in": "query",
- "name": "connector",
- "required": false,
- "description": "Connector to use in format: connector/type (e.g., jupiter/router, raydium/amm, uniswap/clmm). If not provided, uses network's configured swapProvider"
- },
- {
- "schema": {
- "default": "SOL",
- "type": "string"
- },
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Symbol or address of the base token"
- },
- {
- "schema": {
- "default": "USDC",
- "type": "string"
- },
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "Symbol or address of the quote token"
- },
- {
- "schema": {
- "default": 1,
- "type": "number"
- },
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
- },
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Side of the swap"
- },
- {
- "schema": {
- "default": 1,
- "type": "number"
- },
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Slippage tolerance percentage (optional)"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token being swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token being swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Amount of tokenIn to be swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Expected amount of tokenOut to receive",
- "type": "number"
- },
- "price": {
- "description": "Exchange rate between tokenIn and tokenOut",
- "type": "number"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage (0-100)",
- "type": "number"
- },
- "minAmountOut": {
- "description": "Minimum amount of tokenOut that will be accepted",
- "type": "number"
- },
- "maxAmountIn": {
- "description": "Maximum amount of tokenIn that will be spent",
- "type": "number"
- },
- "poolAddress": {
- "description": "Pool address for AMM/CLMM swaps",
- "type": "string"
- },
- "routePath": {
- "description": "Route path for router-based swaps",
- "type": "string"
- },
- "slippagePct": {
- "description": "Slippage tolerance percentage",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "priceImpactPct",
- "minAmountOut",
- "maxAmountIn"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/trading/swap/execute": {
- "post": {
- "tags": ["/trading/swap"],
- "description": "Execute a swap on any supported chain",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address to execute swap from",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet, ethereum-polygon)",
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "connector": {
- "description": "Connector to use in format: connector/type (e.g., jupiter/router, raydium/amm, uniswap/clmm). If not provided, uses network's configured swapProvider",
- "default": "jupiter/router",
- "type": "string"
- },
- "baseToken": {
- "description": "Symbol or address of the base token",
- "default": "SOL",
- "type": "string"
- },
- "quoteToken": {
- "description": "Symbol or address of the quote token",
- "default": "USDC",
- "type": "string"
- },
- "amount": {
- "description": "Amount to swap",
- "default": 1,
- "type": "number"
- },
- "side": {
- "description": "Side of the swap",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "slippagePct": {
- "description": "Slippage tolerance percentage (optional)",
- "default": 1,
- "type": "number"
- }
- },
- "required": ["walletAddress", "chainNetwork", "baseToken", "quoteToken", "amount", "side"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/pool-info": {
- "get": {
- "tags": ["/trading/clmm"],
- "description": "Get CLMM pool information from any supported connector",
- "parameters": [
- {
- "schema": {
- "enum": ["raydium", "meteora", "pancakeswap-sol", "uniswap", "pancakeswap", "orca"],
- "default": "meteora",
- "type": "string"
- },
- "example": "meteora",
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "CLMM connector (raydium, meteora, pancakeswap-sol, uniswap, pancakeswap, orca)"
- },
- {
- "schema": {
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "example": "solana-mainnet-beta",
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Pool contract address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/position-info": {
- "get": {
- "tags": ["/trading/clmm"],
- "description": "Get CLMM position information from any supported connector",
- "parameters": [
- {
- "schema": {
- "enum": ["raydium", "meteora", "pancakeswap-sol", "uniswap", "pancakeswap", "orca"],
- "default": "meteora",
- "type": "string"
- },
- "example": "meteora",
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "CLMM connector (raydium, meteora, pancakeswap-sol, uniswap, pancakeswap, orca)"
- },
- {
- "schema": {
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "example": "solana-mainnet-beta",
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "\u003Csample-position-address\u003E",
- "in": "query",
- "name": "positionAddress",
- "required": true,
- "description": "Position address or NFT token ID"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/positions-owned": {
- "get": {
- "tags": ["/trading/clmm"],
- "description": "Get all CLMM positions owned by a wallet from any supported connector",
- "parameters": [
- {
- "schema": {
- "enum": ["raydium", "meteora", "pancakeswap-sol", "uniswap", "pancakeswap", "orca"],
- "default": "meteora",
- "type": "string"
- },
- "example": "meteora",
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "CLMM connector (raydium, meteora, pancakeswap-sol, uniswap, pancakeswap, orca)"
- },
- {
- "schema": {
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "example": "solana-mainnet-beta",
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "in": "query",
- "name": "walletAddress",
- "required": false,
- "description": "Wallet address (optional, uses default wallet if not provided)"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ],
- "title": "PositionInfo"
- }
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/quote-position": {
- "get": {
- "tags": ["/trading/clmm"],
- "description": "Quote amounts for a new CLMM position from any supported connector",
- "parameters": [
- {
- "schema": {
- "enum": ["raydium", "meteora", "pancakeswap-sol", "uniswap", "pancakeswap", "orca"],
- "default": "meteora",
- "type": "string"
- },
- "example": "meteora",
- "in": "query",
- "name": "connector",
- "required": true,
- "description": "CLMM connector (raydium, meteora, pancakeswap-sol, uniswap, pancakeswap, orca)"
- },
- {
- "schema": {
- "default": "solana-mainnet-beta",
- "type": "string"
- },
- "example": "solana-mainnet-beta",
- "in": "query",
- "name": "chainNetwork",
- "required": true,
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 150,
- "in": "query",
- "name": "lowerPrice",
- "required": true,
- "description": "Lower price bound for the position"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 250,
- "in": "query",
- "name": "upperPrice",
- "required": true,
- "description": "Upper price bound for the position"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Pool contract address"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "baseTokenAmount",
- "required": false,
- "description": "Amount of base token to deposit"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": false,
- "description": "Amount of quote token to deposit"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 1,
- "type": "number"
- },
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/open": {
- "post": {
- "tags": ["/trading/clmm"],
- "description": "Open a new CLMM position across supported connectors",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector name (uniswap, pancakeswap, raydium, meteora, pancakeswap-sol, orca)",
- "default": "meteora",
- "type": "string",
- "example": "meteora"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
- "default": "solana-mainnet-beta",
- "type": "string",
- "example": "solana-mainnet-beta"
- },
- "walletAddress": {
- "description": "Wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "lowerPrice": {
- "description": "Lower price bound for the position",
- "type": "number",
- "example": 150
- },
- "upperPrice": {
- "description": "Upper price bound for the position",
- "type": "number",
- "example": 250
- },
- "poolAddress": {
- "description": "Pool address",
- "type": "string",
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": ["connector", "chainNetwork", "walletAddress", "lowerPrice", "upperPrice", "poolAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/add": {
- "post": {
- "tags": ["/trading/clmm"],
- "description": "Add liquidity to an existing CLMM position across supported connectors",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector name (uniswap, pancakeswap, raydium, meteora, pancakeswap-sol, orca)",
- "default": "meteora",
- "type": "string",
- "example": "meteora"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
- "default": "solana-mainnet-beta",
- "type": "string",
- "example": "solana-mainnet-beta"
- },
- "walletAddress": {
- "description": "Wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": [
- "connector",
- "chainNetwork",
- "walletAddress",
- "positionAddress",
- "baseTokenAmount",
- "quoteTokenAmount"
- ]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/remove": {
- "post": {
- "tags": ["/trading/clmm"],
- "description": "Remove liquidity from a CLMM position across supported connectors",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector name (uniswap, pancakeswap, raydium, meteora, pancakeswap-sol, orca)",
- "default": "meteora",
- "type": "string",
- "example": "meteora"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
- "default": "solana-mainnet-beta",
- "type": "string",
- "example": "solana-mainnet-beta"
- },
- "walletAddress": {
- "description": "Wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "default": 100,
- "type": "number",
- "example": 100
- }
- },
- "required": ["connector", "chainNetwork", "walletAddress", "positionAddress", "percentageToRemove"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/collect-fees": {
- "post": {
- "tags": ["/trading/clmm"],
- "description": "Collect fees from a CLMM position across supported connectors",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector name (uniswap, pancakeswap, raydium, meteora, pancakeswap-sol, orca)",
- "default": "meteora",
- "type": "string",
- "example": "meteora"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
- "default": "solana-mainnet-beta",
- "type": "string",
- "example": "solana-mainnet-beta"
- },
- "walletAddress": {
- "description": "Wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["connector", "chainNetwork", "walletAddress", "positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/trading/clmm/close": {
- "post": {
- "tags": ["/trading/clmm"],
- "description": "Close a CLMM position across supported connectors",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "connector": {
- "description": "Connector name (uniswap, pancakeswap, raydium, meteora, pancakeswap-sol, orca)",
- "default": "meteora",
- "type": "string",
- "example": "meteora"
- },
- "chainNetwork": {
- "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
- "default": "solana-mainnet-beta",
- "type": "string",
- "example": "solana-mainnet-beta"
- },
- "walletAddress": {
- "description": "Wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["connector", "chainNetwork", "walletAddress", "positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/status": {
- "get": {
- "tags": ["/chain/solana"],
- "description": "Get Solana network status",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The Solana network to use"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "type": "string"
- },
- "network": {
- "type": "string"
- },
- "rpcUrl": {
- "type": "string"
- },
- "rpcProvider": {
- "type": "string"
- },
- "currentBlockNumber": {
- "type": "number"
- },
- "nativeCurrency": {
- "type": "string"
- },
- "swapProvider": {
- "type": "string"
- }
- },
- "required": [
- "chain",
- "network",
- "rpcUrl",
- "rpcProvider",
- "currentBlockNumber",
- "nativeCurrency",
- "swapProvider"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/estimate-gas": {
- "get": {
- "tags": ["/chain/solana"],
- "description": "Estimate gas prices for Solana transactions",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The Solana network to use"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "feePerComputeUnit": {
- "type": "number"
- },
- "denomination": {
- "type": "string"
- },
- "computeUnits": {
- "type": "number"
- },
- "feeAsset": {
- "type": "string"
- },
- "fee": {
- "type": "number"
- },
- "timestamp": {
- "type": "number"
- },
- "gasType": {
- "type": "string"
- },
- "maxFeePerGas": {
- "type": "number"
- },
- "maxPriorityFeePerGas": {
- "type": "number"
- }
- },
- "required": ["feePerComputeUnit", "denomination", "computeUnits", "feeAsset", "fee", "timestamp"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/balances": {
- "post": {
- "tags": ["/chain/solana"],
- "description": "Get token balances for a Solana address. Only returns tokens in the network's token list. If no tokens specified or empty array provided, returns non-zero balances for tokens from the token list that are found in the wallet (includes SOL even if zero). If specific tokens are requested, returns those exact tokens with their balances, including zeros.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "address": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "tokens": {
- "description": "A list of token symbols (SOL, USDC, BONK) from the network's token list. Only tokens in the token list will be returned. An empty array is treated the same as if the parameter was not provided, returning only non-zero balances (with the exception of SOL).",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": ["SOL", "USDC", "BONK"]
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Token balances for the specified address (only tokens in token list)",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "balances": {
- "type": "object",
- "additionalProperties": {
- "type": "number"
- }
- }
- },
- "required": ["balances"],
- "description": "Token balances for the specified address (only tokens in token list)"
- },
- "example": {
- "balances": {
- "SOL": 1.5,
- "USDC": 100,
- "BONK": 50000
- }
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/poll": {
- "post": {
- "tags": ["/chain/solana"],
- "description": "Poll for the status of a Solana transaction",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "signature": {
- "description": "Transaction signature to poll",
- "type": "string",
- "example": "55ukR6VCt1sQFMC8Nyeo51R1SMaTzUC7jikmkEJ2jjkQNdqBxXHraH7vaoaNmf8rX4Y55EXAj8XXoyzvvsrQqWZa"
- },
- "tokens": {
- "description": "Tokens to track balance changes for",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": ["SOL", "USDC", "BONK"]
- },
- "walletAddress": {
- "description": "Wallet address to track balance changes for",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- }
- },
- "required": ["signature"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "currentBlock": {
- "type": "number"
- },
- "signature": {
- "type": "string"
- },
- "txBlock": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ]
- },
- "txStatus": {
- "type": "number"
- },
- "fee": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ]
- },
- "tokenBalanceChanges": {
- "description": "Dictionary of token balance changes keyed by token input value (symbol or address)",
- "type": "object",
- "additionalProperties": {
- "type": "number"
- }
- },
- "txData": {
- "anyOf": [
- {
- "type": "object",
- "additionalProperties": {}
- },
- {
- "type": "null"
- }
- ]
- },
- "error": {
- "type": "string"
- }
- },
- "required": ["currentBlock", "signature", "txBlock", "txStatus", "fee", "txData"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/wrap": {
- "post": {
- "tags": ["/chain/solana"],
- "description": "Wrap SOL to WSOL (Wrapped SOL)",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "address": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "amount": {
- "description": "The amount of SOL to wrap (in SOL, not lamports)",
- "type": "string",
- "example": "1.0"
- }
- },
- "required": ["amount"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "string"
- },
- "amount": {
- "type": "string"
- },
- "wrappedAddress": {
- "type": "string"
- },
- "nativeToken": {
- "type": "string"
- },
- "wrappedToken": {
- "type": "string"
- }
- },
- "required": ["fee", "amount", "wrappedAddress", "nativeToken", "wrappedToken"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/solana/unwrap": {
- "post": {
- "tags": ["/chain/solana"],
- "description": "Unwrap WSOL to SOL. Note: This closes the entire WSOL account, returning all WSOL as SOL.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "address": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "amount": {
- "description": "The amount of WSOL to unwrap (in SOL, not lamports). If not provided, unwraps all WSOL.",
- "type": "string",
- "example": "1.0"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "string"
- },
- "amount": {
- "type": "string"
- },
- "wrappedAddress": {
- "type": "string"
- },
- "nativeToken": {
- "type": "string"
- },
- "wrappedToken": {
- "type": "string"
- }
- },
- "required": ["fee", "amount", "wrappedAddress", "nativeToken", "wrappedToken"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/status": {
- "get": {
- "tags": ["/chain/ethereum"],
- "description": "Get Ethereum chain status",
- "parameters": [
- {
- "schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon", "sepolia"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The Ethereum network to use"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "chain": {
- "type": "string"
- },
- "network": {
- "type": "string"
- },
- "rpcUrl": {
- "type": "string"
- },
- "rpcProvider": {
- "type": "string"
- },
- "currentBlockNumber": {
- "type": "number"
- },
- "nativeCurrency": {
- "type": "string"
- },
- "swapProvider": {
- "type": "string"
- }
- },
- "required": [
- "chain",
- "network",
- "rpcUrl",
- "rpcProvider",
- "currentBlockNumber",
- "nativeCurrency",
- "swapProvider"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/estimate-gas": {
- "get": {
- "tags": ["/chain/ethereum"],
- "description": "Estimate gas prices for Ethereum transactions",
- "parameters": [
- {
- "schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon", "sepolia"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The Ethereum network to use"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "feePerComputeUnit": {
- "type": "number"
- },
- "denomination": {
- "type": "string"
- },
- "computeUnits": {
- "type": "number"
- },
- "feeAsset": {
- "type": "string"
- },
- "fee": {
- "type": "number"
- },
- "timestamp": {
- "type": "number"
- },
- "gasType": {
- "type": "string"
- },
- "maxFeePerGas": {
- "type": "number"
- },
- "maxPriorityFeePerGas": {
- "type": "number"
- }
- },
- "required": ["feePerComputeUnit", "denomination", "computeUnits", "feeAsset", "fee", "timestamp"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/balances": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Get Ethereum balances. If no tokens specified or empty array provided, returns native token (ETH) and only non-zero balances for tokens from the token list. If specific tokens are requested, returns those exact tokens with their balances, including zeros.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "address": {
- "description": "Ethereum wallet address",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "tokens": {
- "description": "A list of token symbols (ETH, USDC, WETH) or token addresses. Both formats are accepted and will be automatically detected. An empty array is treated the same as if the parameter was not provided, returning only non-zero balances (with the exception of ETH).",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": ["ETH", "USDC", "WETH"]
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "balances": {
- "type": "object",
- "additionalProperties": {
- "type": "number"
- }
- }
- },
- "required": ["balances"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/poll": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Poll Ethereum transaction status",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "signature": {
- "description": "Transaction hash to poll",
- "type": "string",
- "example": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
- }
- },
- "required": ["signature"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "currentBlock": {
- "type": "number"
- },
- "signature": {
- "type": "string"
- },
- "txBlock": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ]
- },
- "txStatus": {
- "type": "number"
- },
- "fee": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "null"
- }
- ]
- },
- "tokenBalanceChanges": {
- "description": "Dictionary of token balance changes keyed by token input value (symbol or address)",
- "type": "object",
- "additionalProperties": {
- "type": "number"
- }
- },
- "txData": {
- "anyOf": [
- {
- "type": "object",
- "additionalProperties": {}
- },
- {
- "type": "null"
- }
- ]
- },
- "error": {
- "type": "string"
- }
- },
- "required": ["currentBlock", "signature", "txBlock", "txStatus", "fee", "txData"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/allowances": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Get token allowances",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "address": {
- "description": "Ethereum wallet address",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "spender": {
- "description": "Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) or contract address",
- "type": "string",
- "example": "uniswap/router"
- },
- "tokens": {
- "description": "Array of token symbols or addresses",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": ["USDC", "WETH"]
- }
- },
- "required": ["spender", "tokens"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "spender": {
- "type": "string"
- },
- "approvals": {
- "type": "object",
- "additionalProperties": {
- "type": "string"
- }
- }
- },
- "required": ["spender", "approvals"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/approve": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Approve token spending",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "address": {
- "description": "Ethereum wallet address",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "spender": {
- "description": "Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) contract address",
- "type": "string",
- "example": "uniswap/router"
- },
- "token": {
- "description": "Token symbol or address",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "The amount to approve. If not provided, defaults to maximum amount (unlimited approval).",
- "default": "",
- "type": "string"
- }
- },
- "required": ["spender", "token"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenAddress": {
- "type": "string"
- },
- "spender": {
- "type": "string"
- },
- "amount": {
- "type": "string"
- },
- "nonce": {
- "type": "number"
- },
- "fee": {
- "type": "string"
- }
- },
- "required": ["tokenAddress", "spender", "amount", "nonce", "fee"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/wrap": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Wrap native token to wrapped token (e.g., ETH to WETH, BNB to WBNB)",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "address": {
- "description": "Ethereum wallet address",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "amount": {
- "description": "The amount of native token to wrap (e.g., ETH, BNB, AVAX)",
- "type": "string",
- "example": "0.01"
- }
- },
- "required": ["amount"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "nonce": {
- "type": "number"
- },
- "fee": {
- "type": "string"
- },
- "amount": {
- "type": "string"
- },
- "wrappedAddress": {
- "type": "string"
- },
- "nativeToken": {
- "type": "string"
- },
- "wrappedToken": {
- "type": "string"
- }
- },
- "required": ["nonce", "fee", "amount", "wrappedAddress", "nativeToken", "wrappedToken"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/chains/ethereum/unwrap": {
- "post": {
- "tags": ["/chain/ethereum"],
- "description": "Unwrap wrapped token to native token (e.g., WETH to ETH, WBNB to BNB)",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The Ethereum network to use",
- "default": "mainnet",
- "enum": [
- "arbitrum",
- "avalanche",
- "base",
- "bsc",
- "celo",
- "mainnet",
- "optimism",
- "polygon",
- "sepolia"
- ],
- "type": "string"
- },
- "address": {
- "description": "Ethereum wallet address",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "amount": {
- "description": "The amount of wrapped token to unwrap (e.g., WETH, WBNB, WAVAX)",
- "type": "string",
- "example": "0.01"
- }
- },
- "required": ["amount"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "nonce": {
- "type": "number"
- },
- "fee": {
- "type": "string"
- },
- "amount": {
- "type": "string"
- },
- "wrappedAddress": {
- "type": "string"
- },
- "nativeToken": {
- "type": "string"
- },
- "wrappedToken": {
- "type": "string"
- }
- },
- "required": ["nonce", "fee", "amount", "wrappedAddress", "nativeToken", "wrappedToken"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/jupiter/router/quote-swap": {
- "get": {
- "tags": ["/connector/jupiter"],
- "description": "Get an executable swap quote from Jupiter",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Solana token symbol or address to determine swap direction"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "The other Solana token symbol or address in the pair"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.1,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount of base token to trade"
- },
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 1,
- "type": "number"
- },
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- },
- {
- "schema": {
- "default": true,
- "type": "boolean"
- },
- "in": "query",
- "name": "restrictIntermediateTokens",
- "required": false,
- "description": "Restrict routing through highly liquid intermediate tokens only for better price and stability"
- },
- {
- "schema": {
- "default": false,
- "type": "boolean"
- },
- "in": "query",
- "name": "onlyDirectRoutes",
- "required": false,
- "description": "Restrict routing to only go through 1 market"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "quoteId": {
- "description": "Unique identifier for this quote",
- "type": "string"
- },
- "tokenIn": {
- "description": "Address of the token being swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token being swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Amount of tokenIn to be swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Expected amount of tokenOut to receive",
- "type": "number"
- },
- "price": {
- "description": "Exchange rate between tokenIn and tokenOut",
- "type": "number"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage (0-100)",
- "type": "number"
- },
- "minAmountOut": {
- "description": "Minimum amount of tokenOut that will be accepted",
- "type": "number"
- },
- "maxAmountIn": {
- "description": "Maximum amount of tokenIn that will be spent",
- "type": "number"
- },
- "quoteResponse": {
- "type": "object",
- "properties": {
- "inputMint": {
- "description": "Solana mint address of input token",
- "type": "string"
- },
- "inAmount": {
- "description": "Input amount in token decimals",
- "type": "string"
- },
- "outputMint": {
- "description": "Solana mint address of output token",
- "type": "string"
- },
- "outAmount": {
- "description": "Expected output amount in token decimals",
- "type": "string"
- },
- "otherAmountThreshold": {
- "description": "Minimum output amount based on slippage",
- "type": "string"
- },
- "swapMode": {
- "description": "Swap mode used (ExactIn or ExactOut)",
- "type": "string"
- },
- "slippageBps": {
- "description": "Slippage in basis points",
- "type": "number"
- },
- "platformFee": {
- "description": "Platform fee information if applicable"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage",
- "type": "string"
- },
- "routePlan": {
- "description": "Detailed routing plan through various markets",
- "type": "array",
- "items": {}
- },
- "contextSlot": {
- "description": "Solana slot used for quote calculation",
- "type": "number"
- },
- "timeTaken": {
- "description": "Time taken to generate quote in milliseconds",
- "type": "number"
- }
- },
- "required": [
- "inputMint",
- "inAmount",
- "outputMint",
- "outAmount",
- "otherAmountThreshold",
- "swapMode",
- "slippageBps",
- "priceImpactPct",
- "routePlan"
- ]
- },
- "approximation": {
- "description": "Indicates if ExactIn approximation was used when ExactOut route was not available",
- "type": "boolean"
- }
- },
- "required": [
- "quoteId",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "priceImpactPct",
- "minAmountOut",
- "maxAmountIn",
- "quoteResponse"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/jupiter/router/execute-quote": {
- "post": {
- "tags": ["/connector/jupiter"],
- "description": "Execute a previously fetched quote from Jupiter",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Solana wallet address that will execute the swap",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "quoteId": {
- "description": "ID of the Jupiter quote to execute",
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "priorityLevel": {
- "description": "Priority level for Solana transaction processing",
- "enum": ["medium", "high", "veryHigh"],
- "default": "veryHigh",
- "type": "string"
- },
- "maxLamports": {
- "description": "Maximum priority fee in lamports for Solana transaction",
- "default": [1000000],
- "type": "number"
- }
- },
- "required": ["quoteId"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/jupiter/router/execute-swap": {
- "post": {
- "tags": ["/connector/jupiter"],
- "description": "Quote and execute a token swap on Jupiter in one step",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Solana wallet address that will execute the swap",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "baseToken": {
- "description": "Solana token symbol or address to determine swap direction",
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "description": "The other Solana token symbol or address in the pair",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 0.1
- },
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number"
- },
- "restrictIntermediateTokens": {
- "description": "Restrict routing through highly liquid intermediate tokens only for better price and stability",
- "default": true,
- "type": "boolean"
- },
- "onlyDirectRoutes": {
- "description": "Restrict routing to only go through 1 market",
- "default": false,
- "type": "boolean"
- },
- "priorityLevel": {
- "description": "Priority level for Solana transaction processing",
- "enum": ["medium", "high", "veryHigh"],
- "default": "veryHigh",
- "type": "string"
- },
- "maxLamports": {
- "description": "Maximum priority fee in lamports for Solana transaction",
- "default": 1000000,
- "type": "number"
- }
- },
- "required": ["baseToken", "quoteToken", "amount", "side"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/fetch-pools": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Fetch info about Meteora pools",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "minimum": 1,
- "default": 10,
- "type": "number"
- },
- "example": 10,
- "in": "query",
- "name": "limit",
- "required": false,
- "description": "Maximum number of pools to return"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "tokenA",
- "required": false,
- "description": "First token symbol or address"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "tokenB",
- "required": false,
- "description": "Second token symbol or address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ],
- "title": "PoolInfo"
- }
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/pool-info": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Get pool information for a Meteora pool",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Meteora DLMM pool address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- },
- "dynamicFeePct": {
- "type": "number"
- },
- "minBinId": {
- "type": "number"
- },
- "maxBinId": {
- "type": "number"
- },
- "bins": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "binId": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- }
- },
- "required": ["binId", "price", "baseTokenAmount", "quoteTokenAmount"],
- "title": "BinLiquidity"
- }
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId",
- "dynamicFeePct",
- "minBinId",
- "maxBinId",
- "bins"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/positions-owned": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Retrieve all positions owned by a user's wallet across all Meteora pools",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "in": "query",
- "name": "walletAddress",
- "required": true,
- "description": "Solana wallet address to check for positions"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/position-info": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Get details for a specific Meteora position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "\u003Csample-position-address\u003E",
- "in": "query",
- "name": "positionAddress",
- "required": true,
- "description": "Position NFT address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/quote-position": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Quote amounts for a new Meteora CLMM position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 150,
- "in": "query",
- "name": "lowerPrice",
- "required": true,
- "description": "Lower price bound for the position"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 250,
- "in": "query",
- "name": "upperPrice",
- "required": true,
- "description": "Upper price bound for the position"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Meteora DLMM pool address"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "baseTokenAmount",
- "required": false,
- "description": "Amount of base token to deposit"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": false,
- "description": "Amount of quote token to deposit"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- },
- {
- "schema": {
- "enum": [0, 1, 2],
- "type": "number"
- },
- "example": 0,
- "in": "query",
- "name": "strategyType",
- "required": false,
- "description": "Strategy type for the position"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/quote-swap": {
- "get": {
- "tags": ["/connector/meteora"],
- "description": "Get swap quote for Meteora CLMM",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "Meteora DLMM pool address (optional - can be looked up from baseToken and quoteToken)"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Token to determine swap direction"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false,
- "description": "The other token in the pair (optional - required if poolAddress not provided)"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
- },
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "example": "SELL",
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/execute-swap": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Execute a token swap on Meteora DLMM",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will execute the swap",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "poolAddress": {
- "description": "Meteora DLMM pool address (optional - can be looked up from baseToken and quoteToken)",
- "type": "string",
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
- },
- "baseToken": {
- "description": "Base token symbol or address",
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "description": "Quote token symbol or address (optional - required if poolAddress not provided)",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 0.01
- },
- "side": {
- "description": "Trade direction",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string",
- "example": "SELL"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["baseToken", "amount", "side"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "fee": {
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/open-position": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Open a new Meteora position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will open the position",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "lowerPrice": {
- "description": "Lower price bound for the position",
- "type": "number",
- "example": 150
- },
- "upperPrice": {
- "description": "Upper price bound for the position",
- "type": "number",
- "example": 250
- },
- "poolAddress": {
- "description": "Meteora DLMM pool address",
- "type": "string",
- "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- },
- "strategyType": {
- "description": "Strategy type for the position",
- "enum": [0, 1, 2],
- "type": "number",
- "example": 0
- }
- },
- "required": ["lowerPrice", "upperPrice", "poolAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/add-liquidity": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Add liquidity to a Meteora position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will add liquidity",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- },
- "strategyType": {
- "description": "Strategy type for the position",
- "enum": [0, 1, 2],
- "type": "number",
- "example": 0
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/remove-liquidity": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Remove liquidity from a Meteora position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will remove liquidity",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "liquidityPct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "default": 100,
- "type": "number",
- "example": 100
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/collect-fees": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Collect fees from a Meteora position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will collect fees",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/meteora/clmm/close-position": {
- "post": {
- "tags": ["/connector/meteora"],
- "description": "Close a Meteora position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will close the position",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/fetch-pools": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Fetch info about Orca pools",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "minimum": 1,
- "default": 10,
- "type": "number"
- },
- "example": 10,
- "in": "query",
- "name": "limit",
- "required": false,
- "description": "Maximum number of pools to return"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "tokenA",
- "required": false,
- "description": "First token symbol or address"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "tokenB",
- "required": false,
- "description": "Second token symbol or address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ]
- }
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/pool-info": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Get pool information for a Orca pool",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Orca CLMM pool address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- },
- "liquidity": {
- "type": "string"
- },
- "sqrtPrice": {
- "type": "string"
- },
- "tvlUsdc": {
- "type": "number"
- },
- "protocolFeeRate": {
- "type": "number"
- },
- "yieldOverTvl": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId",
- "liquidity",
- "sqrtPrice",
- "tvlUsdc",
- "protocolFeeRate",
- "yieldOverTvl"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/positions-owned": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Retrieve a list of positions owned by a user's wallet in a specific Orca pool",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "in": "query",
- "name": "walletAddress",
- "required": false,
- "description": "Solana wallet address to check for positions"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Orca CLMM pool address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/position-info": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Get details for a specific Orca position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "\u003Csample-position-address\u003E",
- "in": "query",
- "name": "positionAddress",
- "required": true,
- "description": "Position address"
- },
- {
- "schema": {
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "in": "query",
- "name": "walletAddress",
- "required": false,
- "description": "Solana wallet address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/quote-position": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Quote amounts for a new Orca CLMM position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 200,
- "in": "query",
- "name": "lowerPrice",
- "required": true,
- "description": "Lower price bound for the position"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 300,
- "in": "query",
- "name": "upperPrice",
- "required": true,
- "description": "Upper price bound for the position"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Orca CLMM pool address"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "baseTokenAmount",
- "required": false,
- "description": "Amount of base token to deposit"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": false,
- "description": "Amount of quote token to deposit"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 1,
- "type": "number"
- },
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/quote-swap": {
- "get": {
- "tags": ["/connector/orca"],
- "description": "Get swap quote for Orca CLMM",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "Orca CLMM pool address (optional - can be looked up from baseToken and quoteToken)"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Token to determine swap direction"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false,
- "description": "The other token in the pair (optional - required if poolAddress not provided)"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
- },
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "example": "SELL",
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 1,
- "type": "number"
- },
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/execute-swap": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Execute a token swap on Orca CLMM",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will execute the swap",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "poolAddress": {
- "description": "Orca CLMM pool address (optional - can be looked up from baseToken and quoteToken)",
- "type": "string",
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE"
- },
- "baseToken": {
- "description": "Base token symbol or address",
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "description": "Quote token symbol or address (optional - required if poolAddress not provided)",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 0.01
- },
- "side": {
- "description": "Trade direction",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string",
- "example": "SELL"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": ["baseToken", "amount", "side"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "fee": {
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/open-position": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Open a new Orca position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will open the position",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "lowerPrice": {
- "description": "Lower price bound for the position",
- "type": "number",
- "example": 200
- },
- "upperPrice": {
- "description": "Upper price bound for the position",
- "type": "number",
- "example": 300
- },
- "poolAddress": {
- "description": "Orca CLMM pool address",
- "type": "string",
- "example": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": ["lowerPrice", "upperPrice", "poolAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/add-liquidity": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Add liquidity to an Orca position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will add liquidity",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/remove-liquidity": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Remove liquidity from an Orca position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will remove liquidity",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "liquidityPct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "default": 100,
- "type": "number",
- "example": 100
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 1,
- "type": "number",
- "example": 1
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/collect-fees": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Collect fees from an Orca position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will collect fees",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/orca/clmm/close-position": {
- "post": {
- "tags": ["/connector/orca"],
- "description": "Close an Orca position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address that will close the position",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/raydium/amm/pool-info": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get AMM pool information from Raydium",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Raydium AMM pool address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/raydium/amm/position-info": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get info about a Raydium AMM position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Raydium AMM pool address"
- },
- {
- "schema": {
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "in": "query",
- "name": "walletAddress",
- "required": false,
- "description": "Solana wallet address"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "walletAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "lpTokenAmount": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "price": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "walletAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "lpTokenAmount",
- "baseTokenAmount",
- "quoteTokenAmount",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/raydium/amm/quote-liquidity": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Quote amounts for a new Raydium AMM liquidity position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ "schemas": {
+ "AmmPoolInfo": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Raydium AMM pool address"
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "baseTokenAmount",
- "required": true,
- "description": "Amount of base token to add"
+ "baseTokenAddress": {
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": true,
- "description": "Amount of quote token to add"
+ "quoteTokenAddress": {
+ "type": "string"
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- }
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
- }
- }
- }
+ },
+ "required": [
+ "address",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "price",
+ "baseTokenAmount",
+ "quoteTokenAmount"
+ ]
+ },
+ "AmmAddLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- "500": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "error": {
- "type": "string"
- }
- }
- }
- }
- }
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/AmmAddLiquidityResponseData"
}
- }
- }
- },
- "/connectors/raydium/amm/quote-swap": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get swap quote for Raydium AMM",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "AmmAddLiquidityResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position the liquidity went into. Absent on fungible-LP AMMs, which hold liquidity as LP tokens rather than a position account.",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "string"
+ },
+ "positionRent": {
+ "format": "decimal",
+ "description": "Native token locked as rent when this call opened the position. Absent when adding to a position that already existed, and on fungible-LP AMMs.",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "string"
+ },
+ "baseTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "baseTokenAmountAdded",
+ "quoteTokenAmountAdded"
+ ]
+ },
+ "AmmQuoteLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "poolAddress": {
+ "description": "Pool the quote was computed against",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2",
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "AMM pool address (optional - can be looked up from baseToken and quoteToken)"
+ "baseLimited": {
+ "type": "boolean"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Token to determine swap direction"
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false,
- "description": "The other token in the pair (optional - required if poolAddress not provided)"
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
+ "baseTokenAmountMax": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction"
+ "quoteTokenAmountMax": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "baseLimited",
+ "baseTokenAmount",
+ "quoteTokenAmount",
+ "baseTokenAmountMax",
+ "quoteTokenAmountMax"
+ ]
+ },
+ "AmmRemoveLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/AmmRemoveLiquidityResponseData"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
- }
- }
- }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "AmmRemoveLiquidityResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position this operation acted on",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "string"
+ },
+ "positionRentRefunded": {
+ "format": "decimal",
+ "description": "Native token rent returned when the position account closed. Present only on a 100% removal from an AMM whose positions are accounts.",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "string"
+ },
+ "baseTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
}
- }
- }
- },
- "/connectors/raydium/amm/execute-swap": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Execute a swap on Raydium AMM or CPMM",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "network": {
- "type": "string",
- "default": "mainnet-beta"
- },
- "poolAddress": {
- "type": "string",
- "example": ""
- },
- "baseToken": {
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "type": "number",
- "example": 0.01
- },
- "side": {
- "type": "string",
- "example": "SELL"
- },
- "slippagePct": {
- "type": "number",
- "example": 1
- }
- },
- "required": ["baseToken", "amount", "side"]
- }
- }
+ },
+ "required": [
+ "fee",
+ "baseTokenAmountRemoved",
+ "quoteTokenAmountRemoved"
+ ]
+ },
+ "AmmCreatePoolResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- "required": true
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "poolAddress": {
+ "description": "Address of the newly created pool",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "description": "Initial price the pool was seeded at (quote per base)",
+ "type": "string"
+ },
+ "data": {
+ "$ref": "#/components/schemas/AmmCreatePoolResponseData"
+ }
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "fee": {
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "signature",
+ "status",
+ "poolAddress"
+ ]
+ },
+ "AmmCreatePoolResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
}
- }
- }
- },
- "/connectors/raydium/amm/add-liquidity": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Add liquidity to a Raydium AMM/CPMM pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "poolAddress": {
- "description": "Raydium AMM pool address",
- "type": "string",
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["poolAddress", "baseTokenAmount", "quoteTokenAmount"]
- }
+ },
+ "required": [
+ "fee",
+ "baseTokenAmountAdded",
+ "quoteTokenAmountAdded"
+ ]
+ },
+ "PositionDetail": {
+ "type": "object",
+ "properties": {
+ "positionAddress": {
+ "description": "Address of the individual position (NFT position account)",
+ "type": "string"
+ },
+ "lpTokenAmount": {
+ "format": "decimal",
+ "description": "Liquidity held by this position (LP units)",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "positionAddress",
+ "lpTokenAmount",
+ "baseTokenAmount",
+ "quoteTokenAmount"
+ ]
+ },
+ "AmmPositionInfo": {
+ "type": "object",
+ "properties": {
+ "poolAddress": {
+ "type": "string"
+ },
+ "walletAddress": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "lpTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "positions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PositionDetail"
}
+ }
+ },
+ "required": [
+ "poolAddress",
+ "walletAddress",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "lpTokenAmount",
+ "baseTokenAmount",
+ "quoteTokenAmount",
+ "price"
+ ]
+ },
+ "EstimateGasRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
+ }
+ }
+ },
+ "EstimateGasResponse": {
+ "type": "object",
+ "properties": {
+ "feePerComputeUnit": {
+ "format": "decimal",
+ "type": "string"
},
- "required": true
+ "denomination": {
+ "type": "string"
+ },
+ "computeUnits": {
+ "type": "number"
+ },
+ "feeAsset": {
+ "type": "string"
+ },
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "timestamp": {
+ "type": "number"
+ },
+ "gasType": {
+ "type": "string"
+ },
+ "maxFeePerGas": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "maxPriorityFeePerGas": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "priorityFeeLevel": {
+ "type": "string"
+ },
+ "priorityFeePerCUEstimate": {
+ "format": "decimal",
+ "type": "string"
+ }
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "feePerComputeUnit",
+ "denomination",
+ "computeUnits",
+ "feeAsset",
+ "fee",
+ "timestamp"
+ ]
+ },
+ "BalanceRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
+ },
+ "address": {
+ "type": "string"
+ },
+ "tokens": {
+ "description": "a list of token symbols or addresses",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "fetchAll": {
+ "description": "fetch all tokens in wallet, not just those in token list (default: false)",
+ "type": "boolean"
}
}
- }
- },
- "/connectors/raydium/amm/remove-liquidity": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Remove liquidity from a Raydium AMM/CPMM pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "poolAddress": {
- "description": "Raydium AMM pool address",
- "type": "string",
- "example": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "type": "number",
- "example": 100
- }
- },
- "required": ["poolAddress", "percentageToRemove"]
- }
+ },
+ "BalanceResponse": {
+ "type": "object",
+ "properties": {
+ "balances": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "number"
}
- },
- "required": true
+ }
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
- }
+ "required": [
+ "balances"
+ ]
+ },
+ "PollRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
+ },
+ "signature": {
+ "description": "Transaction signature/hash",
+ "type": "string"
+ }
+ },
+ "required": [
+ "signature"
+ ]
+ },
+ "PollResponse": {
+ "type": "object",
+ "properties": {
+ "currentBlock": {
+ "type": "number"
+ },
+ "signature": {
+ "type": "string"
+ },
+ "txBlock": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
}
- }
+ ]
+ },
+ "txStatus": {
+ "description": "Transaction status: 1 = confirmed, 0 = pending, -1 = failed, -2 = not found (unknown to the chain: never received or dropped; on Solana this is terminal once the transaction blockhash expires)",
+ "type": "number"
+ },
+ "fee": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "error": {
+ "anyOf": [
+ {
+ "description": "Error info if failed: \"TYPE (code): message\"",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "txData": {
+ "anyOf": [
+ {
+ "type": "object",
+ "additionalProperties": {}
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "required": [
+ "currentBlock",
+ "signature",
+ "txBlock",
+ "txStatus",
+ "fee",
+ "error",
+ "txData"
+ ]
+ },
+ "StatusRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
}
}
- }
- },
- "/connectors/raydium/clmm/pool-info": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get CLMM pool information from Raydium",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "StatusResponse": {
+ "type": "object",
+ "properties": {
+ "chain": {
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Raydium CLMM pool address"
+ "network": {
+ "type": "string"
+ },
+ "rpcUrl": {
+ "type": "string"
+ },
+ "rpcProvider": {
+ "type": "string"
+ },
+ "currentBlockNumber": {
+ "type": "number"
+ },
+ "nativeCurrency": {
+ "type": "string"
+ },
+ "swapProvider": {
+ "type": "string"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ]
- }
- }
- }
+ },
+ "required": [
+ "chain",
+ "network",
+ "rpcUrl",
+ "rpcProvider",
+ "currentBlockNumber",
+ "nativeCurrency",
+ "swapProvider"
+ ]
+ },
+ "ChainQuoteSwapResponse": {
+ "type": "object",
+ "properties": {
+ "tokenIn": {
+ "description": "Address of the token being swapped from",
+ "type": "string"
+ },
+ "tokenOut": {
+ "description": "Address of the token being swapped to",
+ "type": "string"
+ },
+ "amountIn": {
+ "format": "decimal",
+ "description": "Amount of tokenIn to be swapped",
+ "type": "string"
+ },
+ "amountOut": {
+ "format": "decimal",
+ "description": "Expected amount of tokenOut to receive",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "description": "Exchange rate between tokenIn and tokenOut",
+ "type": "string"
+ },
+ "priceImpactPct": {
+ "format": "decimal",
+ "description": "Estimated price impact percentage (0-100)",
+ "type": "string"
+ },
+ "minAmountOut": {
+ "format": "decimal",
+ "description": "Minimum amount of tokenOut that will be accepted",
+ "type": "string"
+ },
+ "maxAmountIn": {
+ "format": "decimal",
+ "description": "Maximum amount of tokenIn that will be spent",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool address for AMM/CLMM swaps",
+ "type": "string"
+ },
+ "routePath": {
+ "description": "Route path for router-based swaps",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "description": "Slippage tolerance percentage",
+ "type": "string"
}
- }
- }
- },
- "/connectors/raydium/clmm/positions-owned": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Retrieve all positions owned by a user's wallet across all Raydium CLMM pools",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "required": [
+ "tokenIn",
+ "tokenOut",
+ "amountIn",
+ "amountOut",
+ "price",
+ "priceImpactPct",
+ "minAmountOut",
+ "maxAmountIn"
+ ]
+ },
+ "ChainExecuteSwapResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "description": "Transaction signature/hash",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "in": "query",
- "name": "walletAddress",
- "required": true,
- "description": "Solana wallet address to check for positions"
+ "status": {
+ "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ChainExecuteSwapResponseData"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ChainExecuteSwapResponseData": {
+ "type": "object",
+ "properties": {
+ "tokenIn": {
+ "description": "Address of the token swapped from",
+ "type": "string"
+ },
+ "tokenOut": {
+ "description": "Address of the token swapped to",
+ "type": "string"
+ },
+ "amountIn": {
+ "format": "decimal",
+ "description": "Actual amount of tokenIn swapped",
+ "type": "string"
+ },
+ "amountOut": {
+ "format": "decimal",
+ "description": "Actual amount of tokenOut received",
+ "type": "string"
+ },
+ "fee": {
+ "format": "decimal",
+ "description": "Transaction fee paid",
+ "type": "string"
+ },
+ "baseTokenBalanceChange": {
+ "format": "decimal",
+ "description": "Change in base token balance (negative for decrease)",
+ "type": "string"
+ },
+ "quoteTokenBalanceChange": {
+ "format": "decimal",
+ "description": "Change in quote token balance (negative for decrease)",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "description": "Slippage tolerance percentage actually applied to the swap",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool the swap executed against. Set by the pool-scoped routes (/trading/clmm, /trading/amm), which resolve exactly one pool; a router picks its own path across pools and leaves this unset. Without it a settled fill cannot be reconciled to a venue without refetching the transaction.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "tokenIn",
+ "tokenOut",
+ "amountIn",
+ "amountOut",
+ "fee",
+ "baseTokenBalanceChange",
+ "quoteTokenBalanceChange"
+ ]
+ },
+ "WrapRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
+ },
+ "address": {
+ "description": "Wallet address holding the native token",
+ "type": "string"
+ },
+ "amount": {
+ "description": "Amount of the native token to wrap, in whole units (not lamports/wei)",
+ "type": "string",
+ "example": "1.0"
+ }
+ },
+ "required": [
+ "address",
+ "amount"
+ ]
+ },
+ "UnwrapRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "Network to use. Defaults to the chain's configured default network.",
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string",
+ "example": "mainnet-beta"
+ },
+ "address": {
+ "description": "Wallet address holding the wrapped token",
+ "type": "string"
+ },
+ "amount": {
+ "description": "Amount of the wrapped token to unwrap, in whole units. Solana unwraps the full balance when omitted; EVM chains require it.",
+ "type": "string",
+ "example": "1.0"
+ }
+ },
+ "required": [
+ "address"
+ ]
+ },
+ "ChainWrapResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
+ },
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ChainWrapResponseData"
+ }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ChainWrapResponseData": {
+ "type": "object",
+ "properties": {
+ "nonce": {
+ "description": "EVM transaction nonce; absent on non-EVM chains",
+ "type": "number"
+ },
+ "fee": {
+ "type": "string"
+ },
+ "amount": {
+ "type": "string"
+ },
+ "wrappedAddress": {
+ "type": "string"
+ },
+ "nativeToken": {
+ "type": "string"
+ },
+ "wrappedToken": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "amount",
+ "wrappedAddress",
+ "nativeToken",
+ "wrappedToken"
+ ]
+ },
+ "RouterQuoteSwapResponse": {
+ "type": "object",
+ "properties": {
+ "tokenIn": {
+ "description": "Address of the token being swapped from",
+ "type": "string"
+ },
+ "tokenOut": {
+ "description": "Address of the token being swapped to",
+ "type": "string"
+ },
+ "amountIn": {
+ "format": "decimal",
+ "description": "Amount of tokenIn to be swapped",
+ "type": "string"
+ },
+ "amountOut": {
+ "format": "decimal",
+ "description": "Expected amount of tokenOut to receive",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "description": "Exchange rate between tokenIn and tokenOut",
+ "type": "string"
+ },
+ "priceImpactPct": {
+ "format": "decimal",
+ "description": "Estimated price impact percentage (0-100)",
+ "type": "string"
+ },
+ "minAmountOut": {
+ "format": "decimal",
+ "description": "Minimum amount of tokenOut that will be accepted",
+ "type": "string"
+ },
+ "maxAmountIn": {
+ "format": "decimal",
+ "description": "Maximum amount of tokenIn that will be spent",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool address for AMM/CLMM swaps",
+ "type": "string"
+ },
+ "routePath": {
+ "description": "Route path for router-based swaps",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "description": "Slippage tolerance percentage",
+ "type": "string"
+ },
+ "quoteId": {
+ "description": "Identifier to pass to /trading/router/execute-quote",
+ "type": "string"
+ },
+ "approximation": {
+ "description": "True when a BUY was approximated via a sell-leg ExactIn quote because the router has no ExactOut route; amountOut is an estimate rather than exact",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "tokenIn",
+ "tokenOut",
+ "amountIn",
+ "amountOut",
+ "price",
+ "priceImpactPct",
+ "minAmountOut",
+ "maxAmountIn",
+ "quoteId"
+ ]
+ },
+ "PoolListItem": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "description": "Pool address",
+ "type": "string"
+ },
+ "name": {
+ "description": "Pool name (e.g., SOL-USDC)",
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "description": "Base token address",
+ "type": "string"
+ },
+ "baseTokenSymbol": {
+ "description": "Base token symbol",
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "description": "Quote token address",
+ "type": "string"
+ },
+ "quoteTokenSymbol": {
+ "description": "Quote token symbol",
+ "type": "string"
+ },
+ "binStep": {
+ "description": "Bin step / tick spacing",
+ "type": "number"
+ },
+ "baseFee": {
+ "format": "decimal",
+ "description": "Base fee percentage",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "description": "Current price",
+ "type": "string"
+ },
+ "tvl": {
+ "format": "decimal",
+ "description": "Total value locked in USD",
+ "type": "string"
+ },
+ "apr": {
+ "format": "decimal",
+ "description": "Annual percentage rate",
+ "type": "string"
+ },
+ "apy": {
+ "format": "decimal",
+ "description": "Annual percentage yield",
+ "type": "string"
+ },
+ "volume24h": {
+ "format": "decimal",
+ "description": "24-hour trading volume",
+ "type": "string"
+ },
+ "fees24h": {
+ "format": "decimal",
+ "description": "24-hour fees collected",
+ "type": "string"
+ }
+ },
+ "required": [
+ "address",
+ "name",
+ "baseTokenAddress",
+ "baseTokenSymbol",
+ "quoteTokenAddress",
+ "quoteTokenSymbol",
+ "binStep",
+ "baseFee",
+ "price",
+ "tvl"
+ ]
+ },
+ "ClmmFetchPoolsResponse": {
+ "type": "object",
+ "properties": {
+ "pools": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PoolListItem"
}
+ },
+ "total": {
+ "description": "Total number of matching pools",
+ "type": "number"
+ },
+ "page": {
+ "description": "Current page number",
+ "type": "number"
+ },
+ "pageSize": {
+ "description": "Number of pools per page",
+ "type": "number"
}
- }
- }
- },
- "/connectors/raydium/clmm/position-info": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get info about a Raydium CLMM position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "required": [
+ "pools",
+ "total",
+ "page",
+ "pageSize"
+ ]
+ },
+ "BinLiquidity": {
+ "type": "object",
+ "properties": {
+ "binId": {
+ "type": "number"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "\u003Csample-position-address\u003E",
- "in": "query",
- "name": "positionAddress",
- "required": true,
- "description": "Position NFT address"
+ "price": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "in": "query",
- "name": "walletAddress",
- "required": false,
- "description": "Solana wallet address"
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
+ },
+ "required": [
+ "binId",
+ "price",
+ "baseTokenAmount",
+ "quoteTokenAmount"
+ ]
+ },
+ "ClmmPoolInfo": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "binStep": {
+ "type": "number"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "activeBinId": {
+ "type": "number"
+ },
+ "bins": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/BinLiquidity"
}
}
- }
- }
- },
- "/connectors/raydium/clmm/quote-position": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Quote amounts for a new Raydium CLMM position",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "required": [
+ "address",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "price",
+ "baseTokenAmount",
+ "quoteTokenAmount",
+ "activeBinId"
+ ]
+ },
+ "ClmmPositionInfo": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 100,
- "in": "query",
- "name": "lowerPrice",
- "required": true,
- "description": "Lower price bound for the position"
+ "poolAddress": {
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 300,
- "in": "query",
- "name": "upperPrice",
- "required": true,
- "description": "Upper price bound for the position"
+ "baseTokenAddress": {
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Raydium CLMM pool address"
+ "quoteTokenAddress": {
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "baseTokenAmount",
- "required": false,
- "description": "Amount of base token to deposit"
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": false,
- "description": "Amount of quote token to deposit"
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "baseFeeAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteFeeAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "lowerBinId": {
+ "type": "number"
+ },
+ "upperBinId": {
+ "type": "number"
+ },
+ "lowerPrice": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "upperPrice": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "type": "string"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
- }
- }
- }
+ },
+ "required": [
+ "address",
+ "poolAddress",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "baseTokenAmount",
+ "quoteTokenAmount",
+ "baseFeeAmount",
+ "quoteFeeAmount",
+ "lowerBinId",
+ "upperBinId",
+ "lowerPrice",
+ "upperPrice",
+ "price"
+ ]
+ },
+ "ClmmOpenPositionResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
+ },
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmOpenPositionResponseData"
}
- }
- }
- },
- "/connectors/raydium/clmm/quote-swap": {
- "get": {
- "tags": ["/connector/raydium"],
- "description": "Get swap quote for Raydium CLMM",
- "parameters": [
- {
- "schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ClmmOpenPositionResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv",
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "CLMM pool address (optional - can be looked up from tokens)"
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "type": "string"
+ },
+ "positionRent": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "positionAddress",
+ "positionRent",
+ "baseTokenAmountAdded",
+ "quoteTokenAmountAdded"
+ ]
+ },
+ "ClmmAddLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
+ },
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmAddLiquidityResponseData"
+ }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ClmmAddLiquidityResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position this operation acted on",
+ "type": "string"
+ },
+ "baseTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountAdded": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "baseTokenAmountAdded",
+ "quoteTokenAmountAdded"
+ ]
+ },
+ "ClmmRemoveLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
+ },
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmRemoveLiquidityResponseData"
+ }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ClmmRemoveLiquidityResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position this operation acted on",
+ "type": "string"
+ },
+ "baseTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "baseTokenAmountRemoved",
+ "quoteTokenAmountRemoved"
+ ]
+ },
+ "ClmmCollectFeesResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
+ },
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmCollectFeesResponseData"
+ }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ClmmCollectFeesResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "Token to determine swap direction"
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false,
- "description": "The other token in the pair"
+ "positionAddress": {
+ "description": "Position this operation acted on",
+ "type": "string"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 0.01,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
+ "baseFeeAmountCollected": {
+ "format": "decimal",
+ "type": "string"
},
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction"
+ "quoteFeeAmountCollected": {
+ "format": "decimal",
+ "type": "string"
+ }
+ },
+ "required": [
+ "fee",
+ "baseFeeAmountCollected",
+ "quoteFeeAmountCollected"
+ ]
+ },
+ "ClmmClosePositionResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmClosePositionResponseData"
}
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
- }
- }
- }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ClmmClosePositionResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool this operation acted on",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position this operation acted on",
+ "type": "string"
+ },
+ "positionRentRefunded": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountRemoved": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseFeeAmountCollected": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteFeeAmountCollected": {
+ "format": "decimal",
+ "type": "string"
}
- }
- }
- },
- "/connectors/raydium/clmm/execute-swap": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Execute a swap on Raydium CLMM",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "poolAddress": {
- "description": "CLMM pool address (optional)",
- "type": "string",
- "example": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv"
- },
- "baseToken": {
- "description": "Base token symbol or address",
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "description": "Quote token symbol or address",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 0.01
- },
- "side": {
- "description": "Trade direction",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string",
- "example": "SELL"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["baseToken", "amount", "side"]
- }
- }
+ },
+ "required": [
+ "fee",
+ "positionRentRefunded",
+ "baseTokenAmountRemoved",
+ "quoteTokenAmountRemoved",
+ "baseFeeAmountCollected",
+ "quoteFeeAmountCollected"
+ ]
+ },
+ "ClmmCreatePoolResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- "required": true
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
+ },
+ "poolAddress": {
+ "description": "Address of the newly created pool",
+ "type": "string"
+ },
+ "price": {
+ "format": "decimal",
+ "description": "Initial price the pool was initialized at (quote per base)",
+ "type": "string"
+ },
+ "data": {
+ "$ref": "#/components/schemas/ClmmCreatePoolResponseData"
+ }
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "fee": {
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "signature",
+ "status",
+ "poolAddress"
+ ]
+ },
+ "ClmmCreatePoolResponseData": {
+ "type": "object",
+ "properties": {
+ "fee": {
+ "format": "decimal",
+ "type": "string"
}
- }
- }
- },
- "/connectors/raydium/clmm/open-position": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Open a new Raydium CLMM position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "lowerPrice": {
- "description": "Lower price bound for the position",
- "type": "number",
- "example": 100
- },
- "upperPrice": {
- "description": "Upper price bound for the position",
- "type": "number",
- "example": 300
- },
- "poolAddress": {
- "description": "Raydium CLMM pool address",
- "type": "string",
- "example": "3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["lowerPrice", "upperPrice", "poolAddress"]
- }
- }
+ },
+ "required": [
+ "fee"
+ ]
+ },
+ "ClmmQuoteLiquidityResponse": {
+ "type": "object",
+ "properties": {
+ "poolAddress": {
+ "description": "Pool the quote was computed against",
+ "type": "string"
},
- "required": true
+ "baseLimited": {
+ "type": "boolean"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "baseTokenAmountMax": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "quoteTokenAmountMax": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "liquidity": {}
+ },
+ "required": [
+ "baseLimited",
+ "baseTokenAmount",
+ "quoteTokenAmount",
+ "baseTokenAmountMax",
+ "quoteTokenAmountMax"
+ ]
+ },
+ "AmmCreatePoolRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address (pool creator + payer)",
+ "default": "",
+ "type": "string"
+ },
+ "baseToken": {
+ "description": "Base token symbol or address (becomes the pool base)",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Quote token symbol or address (becomes the pool quote)",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to seed the pool with",
+ "type": "number"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to seed with. If provided, the base:quote ratio sets the initial price. If omitted (and no initialPrice), the price is fetched from the market.",
+ "type": "number"
+ },
+ "initialPrice": {
+ "format": "decimal",
+ "description": "Initial price as quote per base. Overrides quoteTokenAmount. If both are omitted, the current market price is fetched from the unified swap router so the pool opens on-market.",
+ "type": "number"
+ },
+ "configAddress": {
+ "x-connectors": [
+ "meteora"
+ ],
+ "description": "Meteora DAMM v2 config account address (required for the meteora connector — configs are permissionless accounts with no index derivation, so the address must be explicit).",
+ "type": "string"
+ },
+ "ammConfigIndex": {
+ "x-connectors": [
+ "raydium"
+ ],
+ "description": "Raydium CPMM fee-config index (optional; defaults to the first available config).",
+ "type": "number"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Uniswap/PancakeSwap seeding slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "baseToken",
+ "quoteToken",
+ "baseTokenAmount"
+ ]
+ },
+ "AmmAddRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to add",
+ "type": "number"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to add",
+ "type": "number"
+ },
+ "positionAddress": {
+ "x-connectors": [
+ "meteora"
+ ],
+ "description": "meteora only (DAMM v2 positions are NFTs): add to this specific position. Omit to open a new position. Ignored by fungible-LP AMMs.",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "poolAddress",
+ "baseTokenAmount",
+ "quoteTokenAmount"
+ ]
+ },
+ "AmmRemoveRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string"
+ },
+ "positionAddress": {
+ "x-connectors": [
+ "meteora"
+ ],
+ "description": "Required for meteora (DAMM v2 positions are NFTs): the specific position to remove from. List positions with position-info or positions-owned. Ignored by fungible-LP AMMs.",
+ "type": "string"
+ },
+ "percentageToRemove": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Percentage of liquidity to remove",
+ "default": 100,
+ "type": "number",
+ "example": 100
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "poolAddress",
+ "percentageToRemove"
+ ]
+ },
+ "AmmPoolInfoRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "poolAddress"
+ ]
+ },
+ "AmmPositionInfoRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "poolAddress",
+ "walletAddress"
+ ]
+ },
+ "AmmPositionsOwnedRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector (only non-fungible-LP AMMs supported: meteora)",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address to list positions for",
+ "default": "",
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress"
+ ]
+ },
+ "AmmQuoteLiquidityRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "AMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to deposit",
+ "type": "number"
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to deposit",
+ "type": "number"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "poolAddress",
+ "baseTokenAmount",
+ "quoteTokenAmount"
+ ]
+ },
+ "ClmmOpenRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "lowerPrice": {
+ "format": "decimal",
+ "description": "Lower price bound for the position",
+ "type": "number",
+ "example": 150
+ },
+ "upperPrice": {
+ "format": "decimal",
+ "description": "Upper price bound for the position",
+ "type": "number",
+ "example": 250
+ },
+ "poolAddress": {
+ "description": "Pool address",
+ "type": "string",
+ "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to deposit",
+ "type": "number",
+ "example": 0.01
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to deposit",
+ "type": "number",
+ "example": 2
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ },
+ "strategyType": {
+ "x-connectors": [
+ "meteora"
+ ],
+ "description": "Strategy type for Meteora positions (0=Spot, 1=Curve). Only applies to Meteora connector.",
+ "type": "number",
+ "example": 0
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "lowerPrice",
+ "upperPrice",
+ "poolAddress"
+ ]
+ },
+ "ClmmAddRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position address",
+ "type": "string",
+ "example": ""
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to deposit (omit for single-sided quote deposit)",
+ "type": "number",
+ "example": 0.01
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to deposit (omit for single-sided base deposit)",
+ "type": "number",
+ "example": 2
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ },
+ "strategyType": {
+ "x-connectors": [
+ "meteora"
+ ],
+ "description": "Strategy type for Meteora positions (0=Spot, 1=Curve). Only applies to Meteora connector.",
+ "type": "number",
+ "example": 0
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "positionAddress"
+ ]
+ },
+ "ClmmRemoveRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position address",
+ "type": "string",
+ "example": ""
+ },
+ "percentageToRemove": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Percentage of liquidity to remove",
+ "default": 100,
+ "type": "number",
+ "example": 100
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Honored by orca, uniswap and pancakeswap; the other connectors remove at their configured slippagePct. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "positionAddress",
+ "percentageToRemove"
+ ]
+ },
+ "ClmmCollectFeesRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position address",
+ "type": "string",
+ "example": ""
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "positionAddress"
+ ]
+ },
+ "ClmmCloseRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "positionAddress": {
+ "description": "Position address",
+ "type": "string",
+ "example": ""
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage for the withdrawal. Enforced by orca, uniswap and pancakeswap; meteora, raydium and pancakeswap-sol close with no minimum-amount check at all, so it changes nothing there. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "positionAddress"
+ ]
+ },
+ "ClmmCreatePoolRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address (pool creator + payer)",
+ "default": "",
+ "type": "string"
+ },
+ "baseToken": {
+ "type": "string"
+ },
+ "quoteToken": {
+ "type": "string"
+ },
+ "initialPrice": {
+ "format": "decimal",
+ "description": "Initial pool price as quote per base. If omitted, the current market price is fetched from the unified swap router so the pool opens on-market.",
+ "type": "number"
+ },
+ "binStep": {
+ "x-connectors": [
+ "meteora",
+ "orca"
+ ],
+ "description": "Bin/tick granularity: Meteora DLMM bin step (bps); Orca Whirlpool tick spacing.",
+ "type": "number"
+ },
+ "feeBps": {
+ "x-connectors": [
+ "meteora",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "description": "Base fee in basis points: Meteora DLMM base fee; Uniswap/PancakeSwap V3 fee tier (1, 5, 30 or 100 bps; PancakeSwap also 25).",
+ "type": "number"
+ },
+ "ammConfigIndex": {
+ "x-connectors": [
+ "raydium",
+ "pancakeswap-sol"
+ ],
+ "description": "Fee-config index for the Raydium CLMM family: Raydium API config list index; pancakeswap-sol amm_config PDA index. Default 0.",
+ "type": "number"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress",
+ "baseToken",
+ "quoteToken"
+ ]
+ },
+ "ClmmFetchPoolsRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "CLMM connector whose pool-discovery API to query",
+ "enum": [
+ "meteora",
+ "orca"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "limit": {
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 50,
+ "description": "Maximum number of pools to return",
+ "type": "number"
+ },
+ "query": {
+ "description": "Search pools by name, token, or address",
+ "type": "string",
+ "example": "SOL"
+ },
+ "sortBy": {
+ "description": "Sort field. Meteora takes a \"field:direction\" pair; Orca takes the field alone with sortDirection.",
+ "type": "string",
+ "example": "tvl"
+ },
+ "page": {
+ "minimum": 0,
+ "description": "0-based page index. Only connectors whose API paginates honor this.",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "number"
+ },
+ "includeUnverified": {
+ "description": "Include unverified pools",
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "boolean"
+ },
+ "sortDirection": {
+ "description": "Sort direction",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "x-connectors": [
+ "orca"
+ ],
+ "type": "string"
+ },
+ "verifiedOnly": {
+ "description": "Return only verified pools",
+ "x-connectors": [
+ "orca"
+ ],
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "chainNetwork",
+ "connector"
+ ]
+ },
+ "ClmmPoolInfoRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string",
+ "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
+ },
+ "binCount": {
+ "description": "If > 0, include a `bins` array of per-tick liquidity around the active tick. Supported by every connector except Meteora, which always returns its bins and ignores this. Default 0 = skip the bin fetch.",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 401,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "poolAddress"
+ ]
+ },
+ "ClmmPositionInfoRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "positionAddress": {
+ "description": "Position address or NFT token ID",
+ "type": "string",
+ "example": ""
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "positionAddress"
+ ]
+ },
+ "ClmmPositionsOwnedRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "walletAddress": {
+ "description": "Wallet address",
+ "default": "",
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "walletAddress"
+ ]
+ },
+ "ClmmQuoteLiquidityRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "CLMM connector",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "lowerPrice": {
+ "format": "decimal",
+ "description": "Lower price bound for the position",
+ "type": "number",
+ "example": 150
+ },
+ "upperPrice": {
+ "format": "decimal",
+ "description": "Upper price bound for the position",
+ "type": "number",
+ "example": 250
+ },
+ "poolAddress": {
+ "description": "Pool contract address",
+ "type": "string",
+ "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3"
+ },
+ "baseTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of base token to deposit",
+ "type": "number",
+ "example": 0.01
+ },
+ "quoteTokenAmount": {
+ "format": "decimal",
+ "description": "Amount of quote token to deposit",
+ "type": "number",
+ "example": 2
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ }
+ },
+ "required": [
+ "connector",
+ "chainNetwork",
+ "lowerPrice",
+ "upperPrice",
+ "poolAddress"
+ ]
+ },
+ "RouterExecuteQuoteRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "Router connector. Defaults to the network's swapProvider",
+ "enum": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan",
+ "uniswap",
+ "pancakeswap",
+ "0x"
+ ],
+ "type": "string",
+ "example": "jupiter"
+ },
+ "walletAddress": {
+ "description": "Wallet address that will execute the quote",
+ "default": "",
+ "type": "string"
+ },
+ "quoteId": {
+ "description": "ID of a quote returned by /trading/router/quote-swap",
+ "type": "string"
+ }
+ },
+ "required": [
+ "chainNetwork",
+ "walletAddress",
+ "quoteId"
+ ]
+ },
+ "RouterExecuteSwapRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "Router connector. Defaults to the network's swapProvider",
+ "enum": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan",
+ "uniswap",
+ "pancakeswap",
+ "0x"
+ ],
+ "type": "string",
+ "example": "jupiter"
+ },
+ "walletAddress": {
+ "description": "Wallet address that will execute the swap",
+ "default": "",
+ "type": "string"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 0.01,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ },
+ "approximateIfNoExactOut": {
+ "description": "For BUY orders when the router has no ExactOut route: approximate via a sell-leg ExactIn swap instead of failing.",
+ "default": true,
+ "x-connectors": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan"
+ ],
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "chainNetwork",
+ "walletAddress",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "RouterQuoteSwapRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "Router connector. Defaults to the network's swapProvider",
+ "enum": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan",
+ "uniswap",
+ "pancakeswap",
+ "0x"
+ ],
+ "type": "string",
+ "example": "jupiter"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 1,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
+ },
+ "walletAddress": {
+ "description": "Taker the quote is priced for. Required by routers that quote per-wallet or return wallet-specific calldata.",
+ "type": "string"
+ },
+ "approximateIfNoExactOut": {
+ "description": "For BUY orders when the router has no ExactOut route: approximate via a sell-leg ExactIn quote instead of failing.",
+ "default": true,
+ "x-connectors": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan"
+ ],
+ "type": "boolean"
+ },
+ "indicativePrice": {
+ "description": "Return an indicative price instead of a firm, executable quote. An indicative quote cannot be executed with /trading/router/execute-quote.",
+ "x-connectors": [
+ "0x"
+ ],
+ "type": "boolean"
+ }
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "chainNetwork",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "AmmQuoteSwapRequest": {
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "AMM connector to price the swap against",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 1,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list.",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
}
- }
- }
- },
- "/connectors/raydium/clmm/add-liquidity": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Add liquidity to existing Raydium CLMM position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": "\u003Csample-position-address\u003E"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["positionAddress", "baseTokenAmount", "quoteTokenAmount"]
- }
- }
- },
- "required": true
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "chainNetwork",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "ClmmQuoteSwapRequest": {
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "CLMM connector to price the swap against",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 1,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list.",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
}
- }
- }
- },
- "/connectors/raydium/clmm/remove-liquidity": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Remove liquidity from Raydium CLMM position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address to remove liquidity from",
- "type": "string",
- "example": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "type": "number",
- "example": 100
- }
- },
- "required": ["positionAddress", "percentageToRemove"]
- }
- }
- },
- "required": true
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "chainNetwork",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "AmmExecuteSwapRequest": {
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "AMM connector to execute the swap against",
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "walletAddress": {
+ "description": "Wallet address that will execute the swap",
+ "default": "",
+ "type": "string"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 0.01,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list.",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
}
- }
- }
- },
- "/connectors/raydium/clmm/collect-fees": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Collect fees from a Raydium CLMM position by removing 1% of liquidity",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "mainnet-beta"
- },
- "walletAddress": {
- "type": "string",
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn"
- },
- "positionAddress": {
- "type": "string"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "chainNetwork",
+ "walletAddress",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "ClmmExecuteSwapRequest": {
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "CLMM connector to execute the swap against",
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string",
+ "example": "meteora"
+ },
+ "walletAddress": {
+ "description": "Wallet address that will execute the swap",
+ "default": "",
+ "type": "string"
+ },
+ "baseToken": {
+ "description": "Symbol or address of the base token",
+ "default": "SOL",
+ "type": "string"
+ },
+ "quoteToken": {
+ "description": "Symbol or address of the quote token",
+ "default": "USDC",
+ "type": "string"
+ },
+ "amount": {
+ "format": "decimal",
+ "description": "Amount of base token to trade",
+ "default": 0.01,
+ "type": "number"
+ },
+ "side": {
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token",
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
+ },
+ "poolAddress": {
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list.",
+ "type": "string"
+ },
+ "slippagePct": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct.",
+ "type": "number",
+ "example": 1
}
- }
- }
- },
- "/connectors/raydium/clmm/close-position": {
- "post": {
- "tags": ["/connector/raydium"],
- "description": "Close a Raydium CLMM position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address to close",
- "type": "string",
- "example": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"
- }
- },
- "required": ["positionAddress"]
- }
- }
- },
- "required": true
},
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
+ "required": [
+ "chainNetwork",
+ "walletAddress",
+ "baseToken",
+ "quoteToken",
+ "amount",
+ "side"
+ ]
+ },
+ "AllowancesRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "The Ethereum network to use",
+ "default": "mainnet",
+ "enum": [
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string"
+ },
+ "address": {
+ "description": "Ethereum wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "spender": {
+ "description": "Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) or contract address",
+ "type": "string",
+ "example": "uniswap/router"
+ },
+ "tokens": {
+ "description": "Array of token symbols or addresses",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "USDC",
+ "WETH"
+ ]
}
- }
- }
- },
- "/connectors/uniswap/router/quote-swap": {
- "get": {
- "tags": ["/connector/uniswap"],
- "description": "Get an executable swap quote from Uniswap Universal Router",
- "parameters": [
- {
- "schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
+ },
+ "required": [
+ "spender",
+ "tokens"
+ ]
+ },
+ "AllowancesResponse": {
+ "type": "object",
+ "properties": {
+ "spender": {
+ "type": "string"
},
- {
- "schema": {
+ "approvals": {
+ "type": "object",
+ "additionalProperties": {
"type": "string"
- },
- "example": "WETH",
- "in": "query",
- "name": "baseToken",
- "required": true,
- "description": "First token in the trading pair"
+ }
+ }
+ },
+ "required": [
+ "spender",
+ "approvals"
+ ]
+ },
+ "ApproveRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "network": {
+ "description": "The Ethereum network to use",
+ "default": "mainnet",
+ "enum": [
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string"
+ },
+ "address": {
+ "description": "Ethereum wallet address",
+ "default": "",
+ "type": "string"
+ },
+ "spender": {
+ "description": "Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) contract address",
+ "type": "string",
+ "example": "uniswap/router"
+ },
+ "token": {
+ "description": "Token symbol or address",
+ "type": "string",
+ "example": "USDC"
+ },
+ "amount": {
+ "description": "The amount to approve. If not provided, defaults to maximum amount (unlimited approval).",
+ "default": "",
+ "type": "string"
+ }
+ },
+ "required": [
+ "spender",
+ "token"
+ ]
+ },
+ "ApproveResponse": {
+ "type": "object",
+ "properties": {
+ "signature": {
+ "type": "string"
},
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "Second token in the trading pair"
+ "status": {
+ "description": "TransactionStatus enum value",
+ "type": "number"
},
- {
- "schema": {
- "type": "number"
- },
- "example": 0.001,
- "in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount of base token to trade"
+ "data": {
+ "$ref": "#/components/schemas/ApproveResponseData"
+ }
+ },
+ "required": [
+ "signature",
+ "status"
+ ]
+ },
+ "ApproveResponseData": {
+ "type": "object",
+ "properties": {
+ "tokenAddress": {
+ "type": "string"
},
- {
- "schema": {
- "enum": ["BUY", "SELL"],
- "type": "string"
- },
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token"
+ "spender": {
+ "type": "string"
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "amount": {
+ "type": "string"
+ },
+ "nonce": {
+ "type": "number"
},
+ "fee": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "tokenAddress",
+ "spender",
+ "amount",
+ "nonce",
+ "fee"
+ ]
+ },
+ "RemoveWalletRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chain": {
+ "description": "Blockchain to remove wallet from",
+ "enum": [
+ "ethereum",
+ "solana"
+ ],
+ "type": "string",
+ "example": "solana"
+ },
+ "address": {
+ "description": "Wallet address to remove",
+ "type": "string"
+ }
+ },
+ "required": [
+ "chain",
+ "address"
+ ]
+ },
+ "AddHardwareWalletRequest": {
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "chain": {
+ "description": "Blockchain for hardware wallet",
+ "enum": [
+ "ethereum",
+ "solana"
+ ],
+ "default": "solana",
+ "type": "string",
+ "example": "solana"
+ },
+ "address": {
+ "description": "Hardware wallet address to add (must exist on connected Ledger device)",
+ "type": "string"
+ },
+ "setDefault": {
+ "description": "Set this wallet as the default for the chain",
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "chain",
+ "address"
+ ]
+ },
+ "Token": {
+ "type": "object",
+ "properties": {
+ "chainId": {
+ "description": "The chain ID",
+ "type": "number",
+ "example": 1
+ },
+ "name": {
+ "description": "The full name of the token",
+ "type": "string",
+ "example": "USD Coin"
+ },
+ "symbol": {
+ "description": "The token symbol",
+ "type": "string",
+ "example": "USDC"
+ },
+ "address": {
+ "description": "The token contract address",
+ "type": "string",
+ "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
+ },
+ "decimals": {
+ "description": "The number of decimals the token uses",
+ "minimum": 0,
+ "maximum": 255,
+ "type": "number",
+ "example": 6
+ }
+ },
+ "required": [
+ "name",
+ "symbol",
+ "address",
+ "decimals"
+ ]
+ },
+ "ErrorResponse": {
+ "type": "object",
+ "properties": {
+ "statusCode": {
+ "description": "HTTP status code",
+ "type": "integer",
+ "example": 400
+ },
+ "error": {
+ "description": "HTTP status name",
+ "type": "string",
+ "example": "Bad Request"
+ },
+ "message": {
+ "description": "What went wrong, in terms of the request that caused it",
+ "type": "string",
+ "example": "Connector 'meteora' runs on solana, not ethereum"
+ },
+ "code": {
+ "description": "Machine-readable cause, present when Gateway can name one. This is what a caller branches on: TRANSACTION_TIMEOUT and RATE_LIMITED are retryable, the rest are not.",
+ "enum": [
+ "TRANSACTION_TIMEOUT",
+ "SIMULATION_FAILED",
+ "TRANSACTION_FAILED",
+ "INSUFFICIENT_BALANCE",
+ "INVALID_PARAMS",
+ "SLIPPAGE_EXCEEDED",
+ "NO_ROUTE_FOUND",
+ "RATE_LIMITED"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "statusCode",
+ "error",
+ "message"
+ ]
+ }
+ }
+ },
+ "paths": {
+ "/config/": {
+ "get": {
+ "operationId": "getConfig",
+ "tags": [
+ "/config"
+ ],
+ "description": "Get configuration settings. Returns all configurations if no parameters are specified. Use namespace to get a specific config (e.g., server, ethereum-mainnet, solana-mainnet-beta, uniswap).",
+ "parameters": [
{
"schema": {
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
"type": "string"
},
+ "examples": {
+ "server": {
+ "value": "server"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "uniswap": {
+ "value": "uniswap"
+ }
+ },
"in": "query",
- "name": "walletAddress",
+ "name": "namespace",
"required": false,
- "description": "Wallet address for more accurate quotes (optional)"
+ "description": "Optional configuration namespace (e.g., \"server\", \"ethereum-mainnet\", \"solana-mainnet-beta\", \"uniswap\")"
}
],
"responses": {
@@ -9787,160 +3806,27 @@
"application/json": {
"schema": {
"type": "object",
- "properties": {
- "quoteId": {
- "description": "Unique identifier for this quote",
- "type": "string"
- },
- "tokenIn": {
- "description": "Address of the token being swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token being swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Amount of tokenIn to be swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Expected amount of tokenOut to receive",
- "type": "number"
- },
- "price": {
- "description": "Exchange rate between tokenIn and tokenOut",
- "type": "number"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage (0-100)",
- "type": "number"
- },
- "minAmountOut": {
- "description": "Minimum amount of tokenOut that will be accepted",
- "type": "number"
- },
- "maxAmountIn": {
- "description": "Maximum amount of tokenIn that will be spent",
- "type": "number"
- },
- "routePath": {
- "description": "Human-readable route path",
- "type": "string"
- }
- },
- "required": [
- "quoteId",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "priceImpactPct",
- "minAmountOut",
- "maxAmountIn"
- ]
+ "additionalProperties": true
}
}
}
- }
- }
- }
- },
- "/connectors/uniswap/router/execute-quote": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Execute a previously fetched quote from Uniswap Universal Router",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "quoteId": {
- "description": "ID of the quote to execute",
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- }
- },
- "required": ["quoteId"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -9948,58 +3834,94 @@
}
}
},
- "/connectors/uniswap/router/execute-swap": {
+ "/config/update": {
"post": {
- "tags": ["/connector/uniswap"],
- "description": "Quote and execute a token swap on Uniswap Universal Router in one step",
+ "operationId": "updateConfig",
+ "tags": [
+ "/config"
+ ],
+ "description": "Update a specific configuration value",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "baseToken": {
- "description": "Token to determine swap direction",
+ "namespace": {
+ "description": "Configuration namespace (e.g., \"server\", \"ethereum-mainnet\", \"solana-mainnet-beta\", \"uniswap\")",
"type": "string",
- "example": "WETH"
+ "example": "server"
},
- "quoteToken": {
- "description": "The other token in the pair",
+ "path": {
+ "description": "Configuration path within the namespace (e.g., \"nodeURL\", \"manualGasPrice\")",
"type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 0.001
- },
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "type": "string"
+ "example": "nodeURL"
},
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 1
+ "value": {
+ "description": "Configuration value",
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "object",
+ "properties": {}
+ },
+ {
+ "type": "array",
+ "items": {}
+ }
+ ]
+ }
+ },
+ "required": [
+ "namespace",
+ "path",
+ "value"
+ ]
+ },
+ "examples": {
+ "example1": {
+ "value": {
+ "namespace": "solana-mainnet-beta",
+ "path": "maxFee",
+ "value": 0.01
+ }
+ },
+ "example2": {
+ "value": {
+ "namespace": "ethereum-mainnet",
+ "path": "nodeURL",
+ "value": "https://eth-mainnet.g.alchemy.com/v2/your-api-key"
+ }
+ },
+ "example3": {
+ "value": {
+ "namespace": "ethereum-mainnet",
+ "path": "gasLimitTransaction",
+ "value": 3000000
+ }
+ },
+ "example4": {
+ "value": {
+ "namespace": "solana-devnet",
+ "path": "retryCount",
+ "value": 5
}
},
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ "example5": {
+ "value": {
+ "namespace": "server",
+ "path": "port",
+ "value": 15888
+ }
+ }
}
}
},
@@ -10013,58 +3935,34 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
- "description": "Transaction signature/hash",
+ "message": {
+ "description": "Status message",
"type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
}
},
- "required": ["signature", "status"]
+ "required": [
+ "message"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10072,33 +3970,13 @@
}
}
},
- "/connectors/uniswap/amm/pool-info": {
+ "/config/chains": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get AMM pool information from Uniswap V2",
- "parameters": [
- {
- "schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C",
- "in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Uniswap V2 pool address"
- }
+ "operationId": "listChains",
+ "tags": [
+ "/config"
],
+ "description": "Returns a list of available blockchain networks supported by Gateway.",
"responses": {
"200": {
"description": "Default Response",
@@ -10107,95 +3985,65 @@
"schema": {
"type": "object",
"properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
+ "chains": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "chain": {
+ "type": "string"
+ },
+ "networks": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "chain",
+ "networks"
+ ]
+ }
}
},
"required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount"
+ "chains"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/uniswap/amm/position-info": {
+ "/config/connectors": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get position information for a Uniswap V2 pool",
- "parameters": [
- {
- "schema": {
- "type": "string",
- "default": "base"
- },
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "in": "query",
- "name": "walletAddress",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "",
- "in": "query",
- "name": "poolAddress",
- "required": true
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "WETH",
- "in": "query",
- "name": "baseToken",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false
- }
+ "operationId": "listConnectors",
+ "tags": [
+ "/config"
],
+ "description": "Returns a list of available DEX connectors and their supported blockchain networks.",
"responses": {
"200": {
"description": "Default Response",
@@ -10204,118 +4052,76 @@
"schema": {
"type": "object",
"properties": {
- "poolAddress": {
- "type": "string"
- },
- "walletAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "lpTokenAmount": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "price": {
- "type": "number"
+ "connectors": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "trading_types": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "chain": {
+ "type": "string"
+ },
+ "networks": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "name",
+ "trading_types",
+ "chain",
+ "networks"
+ ]
+ }
}
},
"required": [
- "poolAddress",
- "walletAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "lpTokenAmount",
- "baseTokenAmount",
- "quoteTokenAmount",
- "price"
+ "connectors"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/uniswap/amm/quote-swap": {
+ "/config/namespaces": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get swap quote for Uniswap V2 AMM",
- "parameters": [
- {
- "schema": {
- "type": "string",
- "default": "base"
- },
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "",
- "in": "query",
- "name": "poolAddress",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "WETH",
- "in": "query",
- "name": "baseToken",
- "required": true
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.001,
- "in": "query",
- "name": "amount",
- "required": true
- },
- {
- "schema": {
- "type": "string",
- "enum": ["BUY", "SELL"]
- },
- "example": "SELL",
- "in": "query",
- "name": "side",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false
- }
+ "operationId": "listNamespaces",
+ "tags": [
+ "/config"
],
+ "description": "Returns a list of all configuration namespaces available in Gateway.",
"responses": {
"200": {
"description": "Default Response",
@@ -10324,121 +4130,58 @@
"schema": {
"type": "object",
"properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
+ "namespaces": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
}
},
"required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
+ "namespaces"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/uniswap/amm/quote-liquidity": {
+ "/wallet/": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get liquidity quote for a Uniswap V2 pool",
+ "operationId": "listWallets",
+ "tags": [
+ "/wallet"
+ ],
+ "description": "Get all wallets across different chains",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "base"
- },
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "",
- "in": "query",
- "name": "poolAddress",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.001,
- "in": "query",
- "name": "baseTokenAmount",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 2.5,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "WETH",
- "in": "query",
- "name": "baseToken",
- "required": false
- },
- {
- "schema": {
- "type": "string"
+ "default": true,
+ "type": "boolean"
},
- "example": "USDC",
"in": "query",
- "name": "quoteToken",
+ "name": "showHardware",
"required": false
}
],
@@ -10448,31 +4191,57 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "chain": {
+ "description": "Blockchain name",
+ "type": "string",
+ "example": "solana"
+ },
+ "walletAddresses": {
+ "description": "List of regular wallet addresses with private keys",
+ "type": "array",
+ "items": {
+ "description": "Wallet address (Ethereum format: 0x... or Solana format: base58)",
+ "type": "string"
+ }
+ },
+ "hardwareWalletAddresses": {
+ "description": "List of hardware wallet addresses (Ledger)",
+ "type": "array",
+ "items": {
+ "description": "Wallet address (Ethereum format: 0x... or Solana format: base58)",
+ "type": "string"
+ }
+ }
},
- "quoteTokenAmountMax": {
- "type": "number"
- }
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
+ "required": [
+ "chain",
+ "walletAddresses"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10480,61 +4249,48 @@
}
}
},
- "/connectors/uniswap/amm/execute-swap": {
+ "/wallet/add": {
"post": {
- "tags": ["/connector/uniswap"],
- "description": "Execute a swap on Uniswap V2 AMM using Router02",
+ "operationId": "addWallet",
+ "tags": [
+ "/wallet"
+ ],
+ "description": "Add a new wallet using a private key",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "poolAddress": {
- "description": "Pool address (optional - can be looked up from tokens)",
- "default": "",
- "type": "string"
- },
- "baseToken": {
- "description": "Base token symbol or address",
+ "chain": {
+ "description": "Blockchain to add wallet to",
+ "enum": [
+ "ethereum",
+ "solana"
+ ],
"type": "string",
- "example": "WETH"
+ "example": "solana"
},
- "quoteToken": {
- "description": "Quote token symbol or address",
+ "privateKey": {
+ "description": "Private key for the wallet",
"type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 0.001
- },
- "side": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
+ "example": ""
},
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
+ "setDefault": {
+ "description": "Set this wallet as the default for the chain",
+ "default": false,
+ "type": "boolean"
}
},
- "required": ["baseToken", "amount", "side"]
+ "required": [
+ "chain",
+ "privateKey"
+ ]
+ },
+ "example": {
+ "chain": "solana",
+ "privateKey": "",
+ "setDefault": true
}
}
},
@@ -10548,58 +4304,34 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
- "description": "Transaction signature/hash",
+ "address": {
+ "description": "The wallet address that was added",
"type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
}
},
- "required": ["signature", "status"]
+ "required": [
+ "address"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10607,61 +4339,95 @@
}
}
},
- "/connectors/uniswap/amm/add-liquidity": {
+ "/wallet/add-hardware": {
"post": {
- "tags": ["/connector/uniswap"],
- "description": "Add liquidity to a Uniswap V2 pool",
+ "operationId": "addHardwareWallet",
+ "tags": [
+ "/wallet"
+ ],
+ "description": "Add a hardware wallet",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Wallet address that will add liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "poolAddress": {
- "description": "Address of the Uniswap V2 pool",
- "type": "string"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number"
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
+ "$ref": "#/components/schemas/AddHardwareWalletRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "description": "The hardware wallet address that was added",
+ "type": "string"
+ },
+ "publicKey": {
+ "description": "Public key of the hardware wallet",
+ "type": "string"
+ },
+ "derivationPath": {
+ "description": "BIP32/BIP44 derivation path used",
+ "type": "string"
+ },
+ "message": {
+ "description": "Success message",
+ "type": "string"
+ }
},
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
- }
- },
- "required": ["poolAddress", "baseTokenAmount", "quoteTokenAmount"]
+ "required": [
+ "address",
+ "publicKey",
+ "derivationPath",
+ "message"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
- },
- "required": true
+ }
+ }
+ }
+ },
+ "/wallet/remove": {
+ "delete": {
+ "operationId": "removeWallet",
+ "tags": [
+ "/wallet"
+ ],
+ "description": "Remove a wallet by its address (automatically detects wallet type)",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RemoveWalletRequest"
+ }
+ }
+ }
},
"responses": {
"200": {
@@ -10671,30 +4437,34 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
+ "message": {
+ "description": "Success message indicating wallet type removed",
"type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
}
},
- "required": ["signature", "status"]
+ "required": [
+ "message"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10702,48 +4472,51 @@
}
}
},
- "/connectors/uniswap/amm/remove-liquidity": {
+ "/wallet/setDefault": {
"post": {
- "tags": ["/connector/uniswap"],
- "description": "Remove liquidity from a Uniswap V2 pool",
+ "operationId": "setDefaultWallet",
+ "tags": [
+ "/wallet"
+ ],
+ "description": "Set a wallet as default for a specific chain",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Wallet address that will remove liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "poolAddress": {
- "description": "Address of the Uniswap V2 pool",
- "type": "string"
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "type": "number"
+ "chain": {
+ "description": "Blockchain to set default wallet for",
+ "enum": [
+ "ethereum",
+ "solana"
+ ],
+ "type": "string",
+ "example": "solana"
},
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
+ "address": {
+ "description": "Wallet address to set as default",
"type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
}
},
- "required": ["poolAddress", "percentageToRemove"]
+ "required": [
+ "chain",
+ "address"
+ ]
+ },
+ "examples": {
+ "example1": {
+ "value": {
+ "chain": "ethereum",
+ "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2BDf8"
+ }
+ },
+ "example2": {
+ "value": {
+ "chain": "solana",
+ "address": "7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi"
+ }
+ }
}
}
},
@@ -10757,30 +4530,44 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
+ "message": {
+ "description": "Success message",
"type": "string"
},
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
+ "chain": {
+ "description": "Chain name",
+ "type": "string"
},
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
+ "address": {
+ "description": "Default wallet address",
+ "type": "string"
}
},
- "required": ["signature", "status"]
+ "required": [
+ "message",
+ "chain",
+ "address"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10788,31 +4575,48 @@
}
}
},
- "/connectors/uniswap/clmm/pool-info": {
+ "/tokens/{symbolOrAddress}": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get CLMM pool information from Uniswap V3",
+ "operationId": "getToken",
+ "tags": [
+ "/tokens"
+ ],
+ "description": "Get a specific token by symbol or address",
"parameters": [
{
"schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
"type": "string"
},
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "0xd0b53d9277642d899df5c87a3966a349a798f224",
- "in": "query",
- "name": "poolAddress",
+ "in": "path",
+ "name": "symbolOrAddress",
"required": true,
- "description": "Uniswap V3 pool address"
+ "description": "Token symbol or address"
}
],
"responses": {
@@ -10823,74 +4627,91 @@
"schema": {
"type": "object",
"properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
+ "token": {
+ "$ref": "#/components/schemas/Token"
},
- "quoteTokenAddress": {
+ "chainNetwork": {
"type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
}
},
"required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
+ "token",
+ "chainNetwork"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/uniswap/clmm/position-info": {
+ "/tokens/find/{address}": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get position information for a Uniswap V3 position",
+ "operationId": "findToken",
+ "tags": [
+ "/tokens"
+ ],
+ "description": "Get token information with market data from GeckoTerminal by address",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "base"
+ "type": "string"
+ },
+ "examples": {
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "ethereum-base": {
+ "value": "ethereum-base"
+ },
+ "ethereum-polygon": {
+ "value": "ethereum-polygon"
+ }
},
"in": "query",
- "name": "network",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "1234",
- "in": "query",
- "name": "positionAddress",
+ "examples": {
+ "So11111111111111111111111111111111111111112": {
+ "value": "So11111111111111111111111111111111111111112"
+ },
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
+ "value": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
+ }
+ },
+ "in": "path",
+ "name": "address",
"required": true,
- "description": "Position NFT token ID"
+ "description": "Token contract address"
}
],
"responses": {
@@ -10899,69 +4720,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
+ "$ref": "#/components/schemas/Token"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -10969,29 +4748,56 @@
}
}
},
- "/connectors/uniswap/clmm/positions-owned": {
+ "/tokens/": {
"get": {
- "tags": ["/connector/uniswap"],
- "description": "Get all Uniswap V3 positions owned by a wallet",
+ "operationId": "listTokens",
+ "tags": [
+ "/tokens"
+ ],
+ "description": "List tokens from token lists with optional filtering",
"parameters": [
{
"schema": {
- "default": "base",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
"type": "string"
},
- "example": "base",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "network",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
+ "examples": {
+ "USDC": {
+ "value": "USDC"
+ },
+ "USD": {
+ "value": "USD"
+ }
+ },
"in": "query",
- "name": "walletAddress",
- "required": true
+ "name": "search",
+ "required": false,
+ "description": "Search term for filtering tokens by symbol or name"
}
],
"responses": {
@@ -11000,151 +4806,90 @@
"content": {
"application/json": {
"schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
+ "type": "object",
+ "properties": {
+ "tokens": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Token"
}
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
+ }
+ },
+ "required": [
+ "tokens"
+ ]
}
}
}
- }
- }
- }
- },
- "/connectors/uniswap/clmm/quote-position": {
- "get": {
- "tags": ["/connector/uniswap"],
- "description": "Get a quote for opening a position on Uniswap V3",
- "parameters": [
- {
- "schema": {
- "type": "string",
- "default": "base"
- },
- "example": "base",
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 2000,
- "in": "query",
- "name": "lowerPrice",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 4000,
- "in": "query",
- "name": "upperPrice",
- "required": true
- },
- {
- "schema": {
- "type": "string",
- "default": "0xd0b53d9277642d899df5c87a3966a349a798f224"
- },
- "example": "0xd0b53d9277642d899df5c87a3966a349a798f224",
- "in": "query",
- "name": "poolAddress",
- "required": true
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.001,
- "in": "query",
- "name": "baseTokenAmount",
- "required": false
},
- {
- "schema": {
- "type": "number"
- },
- "example": 3,
- "in": "query",
- "name": "quoteTokenAmount",
- "required": false
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
},
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "type": "number"
- },
- "in": "query",
- "name": "slippagePct",
- "required": false
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
+ }
+ },
+ "post": {
+ "operationId": "addToken",
+ "tags": [
+ "/tokens"
],
+ "description": "Add a new token to a token list",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "token": {
+ "$ref": "#/components/schemas/Token"
+ }
+ },
+ "required": [
+ "chainNetwork",
+ "token"
+ ]
+ }
+ }
+ },
+ "required": true
+ },
"responses": {
"200": {
"description": "Default Response",
@@ -11153,105 +4898,88 @@
"schema": {
"type": "object",
"properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
+ "message": {
+ "description": "Success message",
+ "type": "string"
+ }
},
"required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
+ "message"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/uniswap/clmm/quote-swap": {
- "get": {
- "tags": ["/connector/uniswap"],
- "description": "Get swap quote for Uniswap V3 CLMM",
+ "/tokens/save/{address}": {
+ "post": {
+ "operationId": "saveToken",
+ "tags": [
+ "/tokens"
+ ],
+ "description": "Find token from GeckoTerminal and save it to the token list",
"parameters": [
- {
- "schema": {
- "type": "string",
- "default": "base"
- },
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "Pool address (optional - can be looked up from baseToken and quoteToken)"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "WETH",
- "in": "query",
- "name": "baseToken",
- "required": true
- },
{
"schema": {
"type": "string"
},
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false
- },
- {
- "schema": {
- "type": "number"
- },
- "example": 0.001,
- "in": "query",
- "name": "amount",
- "required": true
- },
- {
- "schema": {
- "type": "string",
- "enum": ["BUY", "SELL"]
+ "examples": {
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "ethereum-base": {
+ "value": "ethereum-base"
+ },
+ "ethereum-polygon": {
+ "value": "ethereum-polygon"
+ }
},
- "example": "SELL",
"in": "query",
- "name": "side",
- "required": true
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
- "type": "number"
+ "type": "string"
},
- "example": 1,
- "in": "query",
- "name": "slippagePct",
- "required": false
+ "examples": {
+ "So11111111111111111111111111111111111111112": {
+ "value": "So11111111111111111111111111111111111111112"
+ },
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
+ "value": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
+ }
+ },
+ "in": "path",
+ "name": "address",
+ "required": true,
+ "description": "Token contract address"
}
],
"responses": {
@@ -11262,172 +4990,37 @@
"schema": {
"type": "object",
"properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
+ "message": {
"type": "string"
},
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
+ "token": {
+ "$ref": "#/components/schemas/Token"
}
},
"required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
+ "message",
+ "token"
]
}
}
}
- }
- }
- }
- },
- "/connectors/uniswap/clmm/execute-swap": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Execute a swap on Uniswap V3 CLMM using SwapRouter02",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "baseToken": {
- "description": "Token to determine swap direction",
- "type": "string",
- "example": "WETH"
- },
- "quoteToken": {
- "description": "The other token in the pair",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 0.001
- },
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "type": "string"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 1
- }
- },
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -11435,55 +5028,50 @@
}
}
},
- "/connectors/uniswap/clmm/open-position": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Open a new liquidity position in a Uniswap V3 pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "base"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "lowerPrice": {
- "type": "number",
- "example": 1000
- },
- "upperPrice": {
- "type": "number",
- "example": 4000
- },
- "poolAddress": {
- "type": "string",
- "example": "0xd0b53d9277642d899df5c87a3966a349a798f224"
- },
- "baseTokenAmount": {
- "type": "number",
- "example": 0.001
- },
- "quoteTokenAmount": {
- "type": "number",
- "example": 3
- },
- "slippagePct": {
- "type": "number",
- "example": 1
- }
- },
- "required": ["lowerPrice", "upperPrice", "poolAddress"]
- }
- }
+ "/tokens/{address}": {
+ "delete": {
+ "operationId": "removeToken",
+ "tags": [
+ "/tokens"
+ ],
+ "description": "Remove a token from a token list by address",
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
- "required": true
- },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "in": "path",
+ "name": "address",
+ "required": true,
+ "description": "Token address to remove"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
@@ -11492,42 +5080,34 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
+ "message": {
+ "description": "Success message",
"type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
}
},
- "required": ["signature", "status"]
+ "required": [
+ "message"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -11535,62 +5115,102 @@
}
}
},
- "/connectors/uniswap/clmm/add-liquidity": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Add liquidity to an existing Uniswap V3 position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "celo", "mainnet", "optimism", "polygon"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Wallet address that will add liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "positionAddress": {
- "description": "NFT token ID of the position",
- "type": "string"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number"
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
- }
- },
- "required": ["positionAddress", "baseTokenAmount", "quoteTokenAmount"]
+ "/pools/{tradingPair}": {
+ "get": {
+ "operationId": "getPool",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Get a specific pool by trading pair",
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
+ },
+ {
+ "schema": {
+ "enum": [
+ "amm",
+ "clmm"
+ ],
+ "type": "string"
+ },
+ "examples": {
+ "amm": {
+ "value": "amm"
+ },
+ "clmm": {
+ "value": "clmm"
}
- }
+ },
+ "in": "query",
+ "name": "type",
+ "required": true,
+ "description": "Pool type"
+ },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "examples": {
+ "raydium": {
+ "value": "raydium"
+ },
+ "meteora": {
+ "value": "meteora"
+ },
+ "uniswap": {
+ "value": "uniswap"
+ },
+ "orca": {
+ "value": "orca"
+ }
+ },
+ "in": "query",
+ "name": "connector",
+ "required": false,
+ "description": "Optional: filter by connector (raydium, meteora, uniswap, orca)"
},
- "required": true
- },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "examples": {
+ "SOL-USDC": {
+ "value": "SOL-USDC"
+ },
+ "ETH-USDC": {
+ "value": "ETH-USDC"
+ }
+ },
+ "in": "path",
+ "name": "tradingPair",
+ "required": true,
+ "description": "Trading pair (e.g., SOL-USDC, ETH-USDC)"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
@@ -11599,105 +5219,74 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
+ "connector": {
+ "description": "Connector name (raydium, uniswap, orca, etc)",
+ "type": "string",
+ "example": "raydium"
+ },
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "type": "string",
+ "example": "clmm"
+ },
+ "network": {
"type": "string"
},
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
+ "baseSymbol": {
+ "type": "string"
},
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
+ "quoteSymbol": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "address": {
+ "type": "string"
}
},
- "required": ["signature", "status"]
+ "required": [
+ "connector",
+ "type",
+ "network",
+ "baseSymbol",
+ "quoteSymbol",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "address"
+ ]
}
}
}
- }
- }
- }
- },
- "/connectors/uniswap/clmm/remove-liquidity": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Remove liquidity from a Uniswap V3 position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "base"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "positionAddress": {
- "type": "string",
- "description": "Position NFT token ID",
- "example": "1234"
- },
- "percentageToRemove": {
- "type": "number",
- "minimum": 0,
- "maximum": 100,
- "example": 50
- }
- },
- "required": ["positionAddress", "percentageToRemove"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -11705,36 +5294,55 @@
}
}
},
- "/connectors/uniswap/clmm/collect-fees": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Collect fees from a Uniswap V3 position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "base"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "positionAddress": {
- "type": "string",
- "description": "Position NFT token ID",
- "example": "1234"
- }
- },
- "required": ["positionAddress"]
+ "/pools/find/{address}": {
+ "get": {
+ "operationId": "findPool",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Get detailed pool information by address from GeckoTerminal",
+ "parameters": [
+ {
+ "schema": {
+ "type": "string"
+ },
+ "examples": {
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "ethereum-base": {
+ "value": "ethereum-base"
+ },
+ "ethereum-polygon": {
+ "value": "ethereum-polygon"
}
- }
+ },
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
- "required": true
- },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "examples": {
+ "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2": {
+ "value": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
+ },
+ "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640": {
+ "value": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
+ }
+ },
+ "in": "path",
+ "name": "address",
+ "required": true,
+ "description": "Pool contract address"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
@@ -11743,111 +5351,74 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
+ "connector": {
+ "description": "Connector name (raydium, uniswap, orca, etc)",
+ "type": "string",
+ "example": "raydium"
+ },
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "type": "string",
+ "example": "clmm"
+ },
+ "network": {
"type": "string"
},
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
+ "baseSymbol": {
+ "type": "string"
},
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
+ "quoteSymbol": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "address": {
+ "type": "string"
}
},
- "required": ["signature", "status"]
+ "required": [
+ "connector",
+ "type",
+ "network",
+ "baseSymbol",
+ "quoteSymbol",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "address"
+ ]
}
}
}
- }
- }
- }
- },
- "/connectors/uniswap/clmm/close-position": {
- "post": {
- "tags": ["/connector/uniswap"],
- "description": "Close a Uniswap V3 position by removing all liquidity and collecting fees",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string"
- },
- "walletAddress": {
- "type": "string"
- },
- "positionAddress": {
- "type": "string"
- }
- },
- "required": ["positionAddress"]
- }
- }
},
- "required": true
- },
- "responses": {
- "200": {
+ "400": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -11855,92 +5426,139 @@
}
}
},
- "/connectors/0x/router/quote-swap": {
+ "/pools/find": {
"get": {
- "tags": ["/connector/0x"],
- "description": "Get a swap quote from 0x. Use indicativePrice=true for price discovery only, or false/undefined for executable quotes",
+ "operationId": "findPools",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Find pools for a token pair from GeckoTerminal",
"parameters": [
{
"schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "mainnet", "optimism", "polygon"],
"type": "string"
},
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
- },
- {
- "schema": {
- "type": "string"
+ "examples": {
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "ethereum-base": {
+ "value": "ethereum-base"
+ },
+ "ethereum-polygon": {
+ "value": "ethereum-polygon"
+ }
},
- "example": "WETH",
"in": "query",
- "name": "baseToken",
+ "name": "chainNetwork",
"required": true,
- "description": "First token in the trading pair"
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "Second token in the trading pair"
- },
- {
- "schema": {
- "type": "number"
+ "examples": {
+ "raydium": {
+ "value": "raydium"
+ },
+ "meteora": {
+ "value": "meteora"
+ },
+ "uniswap": {
+ "value": "uniswap"
+ },
+ "pancakeswap": {
+ "value": "pancakeswap"
+ },
+ "pancakeswap-sol": {
+ "value": "pancakeswap-sol"
+ },
+ "orca": {
+ "value": "orca"
+ }
},
- "example": 1,
"in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount of base token to trade"
+ "name": "connector",
+ "required": false,
+ "description": "Filter by connector name (e.g., raydium, meteora, uniswap, pancakeswap, pancakeswap-sol)"
},
{
"schema": {
- "enum": ["BUY", "SELL"],
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "default": "clmm",
"type": "string"
},
+ "examples": {
+ "clmm": {
+ "value": "clmm"
+ },
+ "amm": {
+ "value": "amm"
+ }
+ },
"in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token"
+ "name": "type",
+ "required": false,
+ "description": "Filter by pool type: clmm (v3-style concentrated liquidity) or amm (v2-style)"
},
{
"schema": {
- "minimum": 0,
- "maximum": 100,
- "type": "number"
+ "type": "string"
+ },
+ "examples": {
+ "SOL": {
+ "value": "SOL"
+ },
+ "So11111111111111111111111111111111111111112": {
+ "value": "So11111111111111111111111111111111111111112"
+ },
+ "USDC": {
+ "value": "USDC"
+ }
},
- "example": 1,
"in": "query",
- "name": "slippagePct",
+ "name": "tokenA",
"required": false,
- "description": "Maximum acceptable slippage percentage"
+ "description": "First token symbol or contract address (optional - for filtering by token pair)"
},
{
"schema": {
- "default": true,
- "type": "boolean"
+ "type": "string"
+ },
+ "examples": {
+ "USDC": {
+ "value": "USDC"
+ },
+ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": {
+ "value": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
+ },
+ "SOL": {
+ "value": "SOL"
+ }
},
"in": "query",
- "name": "indicativePrice",
+ "name": "tokenB",
"required": false,
- "description": "If true, returns indicative pricing only (no commitment). If false, returns firm quote ready for execution"
+ "description": "Second token symbol or contract address (optional - for filtering by token pair)"
},
{
"schema": {
- "type": "string"
+ "minimum": 1,
+ "maximum": 10,
+ "default": 10,
+ "type": "number"
},
"in": "query",
- "name": "takerAddress",
+ "name": "pages",
"required": false,
- "description": "Ethereum wallet address that will execute the swap (optional for quotes)"
+ "description": "Number of pages to fetch from GeckoTerminal (1-10, default: 10)"
}
],
"responses": {
@@ -11949,329 +5567,79 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "quoteId": {
- "description": "Unique identifier for this quote",
- "type": "string"
- },
- "tokenIn": {
- "description": "Address of the token being swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token being swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Amount of tokenIn to be swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Expected amount of tokenOut to receive",
- "type": "number"
- },
- "price": {
- "description": "Exchange rate between tokenIn and tokenOut",
- "type": "number"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage (0-100)",
- "type": "number"
- },
- "minAmountOut": {
- "description": "Minimum amount of tokenOut that will be accepted",
- "type": "number"
- },
- "maxAmountIn": {
- "description": "Maximum amount of tokenIn that will be spent",
- "type": "number"
- },
- "expirationTime": {
- "description": "Unix timestamp when this quote expires (only for firm quotes)",
- "type": "number"
- },
- "gasEstimate": {
- "description": "Estimated gas required for the swap",
- "type": "string"
- },
- "sources": {
- "description": "Liquidity sources used for this quote",
- "type": "array",
- "items": {}
- },
- "allowanceTarget": {
- "description": "Contract address that needs token approval",
- "type": "string"
- },
- "to": {
- "description": "Contract address to send transaction to",
- "type": "string"
- },
- "data": {
- "description": "Encoded transaction data",
- "type": "string"
- },
- "value": {
- "description": "ETH value to send with transaction",
- "type": "string"
- }
- },
- "required": [
- "quoteId",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "priceImpactPct",
- "minAmountOut",
- "maxAmountIn",
- "gasEstimate"
- ]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/0x/router/execute-quote": {
- "post": {
- "tags": ["/connector/0x"],
- "description": "Execute a previously fetched quote from 0x",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "mainnet", "optimism", "polygon"],
- "type": "string",
- "example": "arbitrum"
- },
- "quoteId": {
- "description": "ID of the quote to execute",
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 1000000
- }
- },
- "required": ["quoteId"]
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "Connector name (raydium, uniswap, orca, etc)",
+ "type": "string",
+ "example": "raydium"
},
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
- }
- }
- }
- }
- }
- }
- },
- "/connectors/0x/router/execute-swap": {
- "post": {
- "tags": ["/connector/0x"],
- "description": "Quote and execute a token swap on 0x in one step",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "avalanche", "base", "bsc", "mainnet", "optimism", "polygon"],
- "type": "string",
- "example": "arbitrum"
- },
- "baseToken": {
- "description": "Token to determine swap direction",
- "type": "string",
- "example": "WETH"
- },
- "quoteToken": {
- "description": "The other token in the pair",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 1
- },
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "type": "string"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "type": "number",
- "example": 1
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "type": "string",
+ "example": "clmm"
+ },
+ "network": {
+ "type": "string"
+ },
+ "baseSymbol": {
+ "type": "string"
+ },
+ "quoteSymbol": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "address": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "type",
+ "network",
+ "baseSymbol",
+ "quoteSymbol",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "address"
+ ]
}
- },
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "400": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -12279,83 +5647,92 @@
}
}
},
- "/connectors/pancakeswap/router/quote-swap": {
+ "/pools/": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get an executable swap quote from Pancakeswap Universal Router",
+ "operationId": "listPools",
+ "tags": [
+ "/pools"
+ ],
+ "description": "List all pools for a chain/network, optionally filtered by connector, type, or search term",
"parameters": [
{
"schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
- },
- {
- "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
"type": "string"
},
- "example": "USDT",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "baseToken",
+ "name": "chainNetwork",
"required": true,
- "description": "First token in the trading pair"
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "WBNB",
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "Second token in the trading pair"
- },
- {
- "schema": {
- "type": "number"
+ "examples": {
+ "raydium": {
+ "value": "raydium"
+ },
+ "meteora": {
+ "value": "meteora"
+ },
+ "uniswap": {
+ "value": "uniswap"
+ },
+ "orca": {
+ "value": "orca"
+ }
},
- "example": 10,
"in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount of base token to trade"
+ "name": "connector",
+ "required": false,
+ "description": "Optional: filter by connector (raydium, meteora, uniswap, orca)"
},
{
"schema": {
- "enum": ["BUY", "SELL"],
+ "enum": [
+ "clmm",
+ "amm"
+ ],
"type": "string"
},
- "in": "query",
- "name": "side",
- "required": true,
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
+ "examples": {
+ "clmm": {
+ "value": "clmm"
+ },
+ "amm": {
+ "value": "amm"
+ }
},
"in": "query",
- "name": "slippagePct",
+ "name": "type",
"required": false,
- "description": "Maximum acceptable slippage percentage"
+ "description": "Optional: filter by pool type"
},
{
"schema": {
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
"type": "string"
},
"in": "query",
- "name": "walletAddress",
+ "name": "search",
"required": false,
- "description": "Wallet address for more accurate quotes (optional)"
+ "description": "Optional: search by token symbol or address"
}
],
"responses": {
@@ -12364,220 +5741,173 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "quoteId": {
- "description": "Unique identifier for this quote",
- "type": "string"
- },
- "tokenIn": {
- "description": "Address of the token being swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token being swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Amount of tokenIn to be swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Expected amount of tokenOut to receive",
- "type": "number"
- },
- "price": {
- "description": "Exchange rate between tokenIn and tokenOut",
- "type": "number"
- },
- "priceImpactPct": {
- "description": "Estimated price impact percentage (0-100)",
- "type": "number"
- },
- "minAmountOut": {
- "description": "Minimum amount of tokenOut that will be accepted",
- "type": "number"
- },
- "maxAmountIn": {
- "description": "Maximum amount of tokenIn that will be spent",
- "type": "number"
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "Connector name (raydium, uniswap, orca, etc)",
+ "type": "string",
+ "example": "raydium"
+ },
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "type": "string",
+ "example": "clmm"
+ },
+ "network": {
+ "type": "string"
+ },
+ "baseSymbol": {
+ "type": "string"
+ },
+ "quoteSymbol": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "address": {
+ "type": "string"
+ }
},
- "routePath": {
- "description": "Human-readable route path",
- "type": "string"
- }
- },
- "required": [
- "quoteId",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "priceImpactPct",
- "minAmountOut",
- "maxAmountIn"
- ]
+ "required": [
+ "connector",
+ "type",
+ "network",
+ "baseSymbol",
+ "quoteSymbol",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "address"
+ ]
+ }
}
}
}
- }
- }
- }
- },
- "/connectors/pancakeswap/router/execute-quote": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Execute a previously fetched quote from Pancakeswap Universal Router",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "quoteId": {
- "description": "ID of the quote to execute",
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- }
- },
- "required": ["quoteId"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
- }
- },
- "/connectors/pancakeswap/router/execute-swap": {
+ },
"post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Quote and execute a token swap on Pancakeswap Universal Router in one step",
+ "operationId": "addPool",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Add a new pool",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
+ "chainNetwork": {
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "type": "string",
+ "example": "solana-mainnet-beta"
+ },
+ "connector": {
+ "description": "Connector (raydium, meteora, uniswap, orca)",
+ "type": "string",
+ "example": "raydium"
+ },
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
"type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
+ "example": "clmm"
},
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
+ "address": {
+ "description": "Pool contract address",
"type": "string"
},
- "baseToken": {
- "description": "Token to determine swap direction",
+ "baseSymbol": {
+ "description": "Base token symbol (optional - fetched automatically if not provided)",
"type": "string",
- "example": "USDT"
+ "example": "SOL"
},
- "quoteToken": {
- "description": "The other token in the pair",
+ "quoteSymbol": {
+ "description": "Quote token symbol (optional - fetched automatically if not provided)",
"type": "string",
- "example": "WBNB"
+ "example": "USDC"
},
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 10
+ "baseTokenAddress": {
+ "description": "Base token contract address",
+ "type": "string",
+ "example": "So11111111111111111111111111111111111111112"
},
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "type": "string"
+ "quoteTokenAddress": {
+ "description": "Quote token contract address",
+ "type": "string",
+ "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
},
- "slippagePct": {
+ "feePct": {
+ "format": "decimal",
+ "description": "Pool fee percentage (optional - fetched from pool-info if not provided)",
"minimum": 0,
"maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
"type": "number",
- "example": 1
+ "example": 0.25
}
},
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ "required": [
+ "chainNetwork",
+ "connector",
+ "type",
+ "address",
+ "baseTokenAddress",
+ "quoteTokenAddress"
+ ]
}
}
},
@@ -12591,58 +5921,33 @@
"schema": {
"type": "object",
"properties": {
- "signature": {
- "description": "Transaction signature/hash",
+ "message": {
"type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
}
},
- "required": ["signature", "status"]
+ "required": [
+ "message"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -12650,31 +5955,53 @@
}
}
},
- "/connectors/pancakeswap/amm/pool-info": {
- "get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get AMM pool information from Pancakeswap V2",
+ "/pools/save/{address}": {
+ "post": {
+ "operationId": "savePool",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Find pool from GeckoTerminal and save it to the pool list. Auto-adds missing tokens.",
"parameters": [
{
"schema": {
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
"type": "string"
},
+ "examples": {
+ "solana-mainnet-beta": {
+ "value": "solana-mainnet-beta"
+ },
+ "ethereum-mainnet": {
+ "value": "ethereum-mainnet"
+ },
+ "ethereum-base": {
+ "value": "ethereum-base"
+ },
+ "ethereum-polygon": {
+ "value": "ethereum-polygon"
+ }
+ },
"in": "query",
- "name": "network",
- "required": false,
- "description": "The EVM network to use"
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C",
- "in": "query",
- "name": "poolAddress",
+ "examples": {
+ "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2": {
+ "value": "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"
+ },
+ "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640": {
+ "value": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
+ }
+ },
+ "in": "path",
+ "name": "address",
"required": true,
- "description": "Pancakeswap V2 pool address"
+ "description": "Pool contract address"
}
],
"responses": {
@@ -12685,93 +6012,141 @@
"schema": {
"type": "object",
"properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
+ "message": {
"type": "string"
},
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
+ "pool": {
+ "type": "object",
+ "properties": {
+ "connector": {
+ "description": "Connector name (raydium, uniswap, orca, etc)",
+ "type": "string",
+ "example": "raydium"
+ },
+ "type": {
+ "description": "Pool type",
+ "enum": [
+ "clmm",
+ "amm"
+ ],
+ "type": "string",
+ "example": "clmm"
+ },
+ "network": {
+ "type": "string"
+ },
+ "baseSymbol": {
+ "type": "string"
+ },
+ "quoteSymbol": {
+ "type": "string"
+ },
+ "baseTokenAddress": {
+ "type": "string"
+ },
+ "quoteTokenAddress": {
+ "type": "string"
+ },
+ "feePct": {
+ "format": "decimal",
+ "type": "string"
+ },
+ "address": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "connector",
+ "type",
+ "network",
+ "baseSymbol",
+ "quoteSymbol",
+ "baseTokenAddress",
+ "quoteTokenAddress",
+ "feePct",
+ "address"
+ ]
},
- "quoteTokenAmount": {
- "type": "number"
+ "tokensAdded": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
}
},
"required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount"
+ "message",
+ "pool"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/pancakeswap/amm/position-info": {
- "get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get position information for a Pancakeswap V2 pool",
+ "/pools/{address}": {
+ "delete": {
+ "operationId": "removePool",
+ "tags": [
+ "/pools"
+ ],
+ "description": "Remove a pool by address",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "base"
- },
- "in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "in": "query",
- "name": "walletAddress",
- "required": false
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "",
- "in": "query",
- "name": "poolAddress",
- "required": true
- },
- {
- "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
"type": "string"
},
- "example": "WETH",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "baseToken",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": false
+ "in": "path",
+ "name": "address",
+ "required": true,
+ "description": "Pool contract address to remove"
}
],
"responses": {
@@ -12782,116 +6157,188 @@
"schema": {
"type": "object",
"properties": {
- "poolAddress": {
- "type": "string"
- },
- "walletAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
+ "message": {
"type": "string"
- },
- "lpTokenAmount": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "price": {
- "type": "number"
}
},
"required": [
- "poolAddress",
- "walletAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "lpTokenAmount",
- "baseTokenAmount",
- "quoteTokenAmount",
- "price"
+ "message"
]
}
}
}
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
}
}
},
- "/connectors/pancakeswap/amm/quote-swap": {
+ "/trading/router/quote-swap": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get swap quote for Pancakeswap V2 AMM",
+ "operationId": "quoteRouterSwap",
+ "tags": [
+ "/trading/router"
+ ],
+ "description": "Get a swap quote from a router connector on any supported chain",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "base"
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
},
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "network",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
+ "enum": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan",
+ "uniswap",
+ "pancakeswap",
+ "0x"
+ ],
"type": "string"
},
- "example": "",
+ "example": "jupiter",
"in": "query",
- "name": "poolAddress",
- "required": false
+ "name": "connector",
+ "required": false,
+ "description": "Router connector. Defaults to the network's swapProvider"
},
{
"schema": {
+ "default": "SOL",
"type": "string"
},
- "example": "WETH",
"in": "query",
"name": "baseToken",
- "required": true
+ "required": true,
+ "description": "Symbol or address of the base token"
},
{
"schema": {
+ "default": "USDC",
"type": "string"
},
- "example": "USDC",
"in": "query",
"name": "quoteToken",
- "required": false
+ "required": true,
+ "description": "Symbol or address of the quote token"
},
{
"schema": {
+ "format": "decimal",
+ "default": 1,
"type": "number"
},
- "example": 0.001,
"in": "query",
"name": "amount",
- "required": true
+ "required": true,
+ "description": "Amount of base token to trade"
},
{
"schema": {
- "type": "string",
- "enum": ["BUY", "SELL"]
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
},
- "example": "SELL",
"in": "query",
"name": "side",
- "required": true
+ "required": true,
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token"
},
{
"schema": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
"type": "number"
},
"example": 1,
"in": "query",
"name": "slippagePct",
- "required": false
+ "required": false,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct."
+ },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "in": "query",
+ "name": "walletAddress",
+ "required": false,
+ "description": "Taker the quote is priced for. Required by routers that quote per-wallet or return wallet-specific calldata."
+ },
+ {
+ "schema": {
+ "default": true,
+ "x-connectors": [
+ "jupiter",
+ "dflow",
+ "okx",
+ "titan"
+ ],
+ "type": "boolean"
+ },
+ "in": "query",
+ "name": "approximateIfNoExactOut",
+ "required": false,
+ "description": "For BUY orders when the router has no ExactOut route: approximate via a sell-leg ExactIn quote instead of failing."
+ },
+ {
+ "schema": {
+ "x-connectors": [
+ "0x"
+ ],
+ "type": "boolean"
+ },
+ "in": "query",
+ "name": "indicativePrice",
+ "required": false,
+ "description": "Return an indicative price instead of a firm, executable quote. An indicative quote cannot be executed with /trading/router/execute-quote."
}
],
"responses": {
@@ -12900,50 +6347,127 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
+ "$ref": "#/components/schemas/RouterQuoteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/router/execute-quote": {
+ "post": {
+ "operationId": "executeRouterQuote",
+ "tags": [
+ "/trading/router"
+ ],
+ "description": "Execute a previously fetched router quote by its quote id",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RouterExecuteQuoteRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ChainExecuteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/router/execute-swap": {
+ "post": {
+ "operationId": "executeRouterSwap",
+ "tags": [
+ "/trading/router"
+ ],
+ "description": "Quote and execute a swap through a router connector on any supported chain",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RouterExecuteSwapRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ChainExecuteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -12951,73 +6475,180 @@
}
}
},
- "/connectors/pancakeswap/amm/quote-liquidity": {
+ "/trading/clmm/pool-info": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get liquidity quote for a Pancakeswap V2 pool",
+ "operationId": "getClmmPoolInfo",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Get CLMM pool information from any supported connector",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "base"
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "network",
- "required": false
- },
- {
- "schema": {
+ "name": "connector",
+ "required": true,
+ "description": "CLMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
"type": "string"
},
- "example": "",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "poolAddress",
- "required": true
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
- "type": "number"
+ "type": "string"
},
- "example": 0.001,
+ "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
"in": "query",
- "name": "baseTokenAmount",
- "required": true
+ "name": "poolAddress",
+ "required": true,
+ "description": "Pool contract address"
},
{
"schema": {
- "type": "number"
+ "default": 0,
+ "minimum": 0,
+ "maximum": 401,
+ "type": "integer"
},
- "example": 2.5,
"in": "query",
- "name": "quoteTokenAmount",
- "required": true
+ "name": "binCount",
+ "required": false,
+ "description": "If > 0, include a `bins` array of per-tick liquidity around the active tick. Supported by every connector except Meteora, which always returns its bins and ignores this. Default 0 = skip the bin fetch."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmPoolInfo"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
},
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/clmm/position-info": {
+ "get": {
+ "operationId": "getClmmPositionInfo",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Get CLMM position information from any supported connector",
+ "parameters": [
{
"schema": {
- "type": "number"
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string"
},
- "example": 1,
+ "example": "meteora",
"in": "query",
- "name": "slippagePct",
- "required": false
- },
- {
- "schema": {
+ "name": "connector",
+ "required": true,
+ "description": "CLMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
"type": "string"
},
- "example": "WETH",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "baseToken",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "USDC",
+ "example": "",
"in": "query",
- "name": "quoteToken",
- "required": false
+ "name": "positionAddress",
+ "required": true,
+ "description": "Position address or NFT token ID"
}
],
"responses": {
@@ -13026,158 +6657,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- }
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
+ "$ref": "#/components/schemas/ClmmPositionInfo"
}
}
}
- }
- }
- }
- },
- "/connectors/pancakeswap/amm/execute-swap": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Execute a swap on Pancakeswap V2 AMM using Router02",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "poolAddress": {
- "description": "Pool address (optional - can be looked up from tokens)",
- "default": "",
- "type": "string"
- },
- "baseToken": {
- "description": "Base token symbol or address",
- "type": "string",
- "example": "USDT"
- },
- "quoteToken": {
- "description": "Quote token symbol or address",
- "type": "string",
- "example": "WBNB"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 10
- },
- "side": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
- }
- },
- "required": ["baseToken", "amount", "side"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -13185,180 +6685,101 @@
}
}
},
- "/connectors/pancakeswap/amm/add-liquidity": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Add liquidity to a Pancakeswap V2 pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Wallet address that will add liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "poolAddress": {
- "description": "Address of the Pancakeswap V2 pool",
- "type": "string"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number"
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
- }
- },
- "required": ["poolAddress", "baseTokenAmount", "quoteTokenAmount"]
- }
- }
+ "/trading/clmm/positions-owned": {
+ "get": {
+ "operationId": "listClmmPositions",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Get all CLMM positions owned by a wallet from any supported connector",
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string"
+ },
+ "example": "meteora",
+ "in": "query",
+ "name": "connector",
+ "required": true,
+ "description": "CLMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
- "required": true
- },
+ {
+ "schema": {
+ "default": "",
+ "type": "string"
+ },
+ "in": "query",
+ "name": "walletAddress",
+ "required": true,
+ "description": "Wallet address"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ClmmPositionInfo"
+ }
}
}
}
- }
- }
- }
- },
- "/connectors/pancakeswap/amm/remove-liquidity": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Remove liquidity from a Pancakeswap V2 pool",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Wallet address that will remove liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "poolAddress": {
- "description": "Address of the Pancakeswap V2 pool",
- "type": "string"
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "type": "number"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
- }
- },
- "required": ["poolAddress", "percentageToRemove"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -13366,32 +6787,126 @@
}
}
},
- "/connectors/pancakeswap/clmm/pool-info": {
+ "/trading/clmm/quote-liquidity": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get CLMM pool information from Pancakeswap V3",
+ "operationId": "quoteClmmLiquidity",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Quote amounts for a new CLMM position from any supported connector",
"parameters": [
{
"schema": {
- "default": "bsc",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string"
+ },
+ "example": "meteora",
+ "in": "query",
+ "name": "connector",
+ "required": true,
+ "description": "CLMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "type": "number"
+ },
+ "example": 150,
+ "in": "query",
+ "name": "lowerPrice",
+ "required": true,
+ "description": "Lower price bound for the position"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "type": "number"
+ },
+ "example": 250,
+ "in": "query",
+ "name": "upperPrice",
+ "required": true,
+ "description": "Upper price bound for the position"
+ },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "example": "2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3",
+ "in": "query",
+ "name": "poolAddress",
+ "required": true,
+ "description": "Pool contract address"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "type": "number"
+ },
+ "example": 0.01,
+ "in": "query",
+ "name": "baseTokenAmount",
+ "required": false,
+ "description": "Amount of base token to deposit"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "type": "number"
},
- "example": "bsc",
+ "example": 2,
"in": "query",
- "name": "network",
+ "name": "quoteTokenAmount",
"required": false,
- "description": "The EVM network to use"
+ "description": "Amount of quote token to deposit"
},
{
"schema": {
- "type": "string"
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "type": "number"
},
- "example": "0x172fcd41e0913e95784454622d1c3724f546f849",
+ "example": 1,
"in": "query",
- "name": "poolAddress",
- "required": true,
- "description": "Pancakeswap V3 pool address"
+ "name": "slippagePct",
+ "required": false,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct."
}
],
"responses": {
@@ -13400,148 +6915,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ]
+ "$ref": "#/components/schemas/ClmmQuoteLiquidityResponse"
}
}
}
- }
- }
- }
- },
- "/connectors/pancakeswap/clmm/position-info": {
- "get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get position information for a Pancakeswap V3 position",
- "parameters": [
- {
- "schema": {
- "type": "string",
- "default": "bsc"
- },
- "example": "bsc",
- "in": "query",
- "name": "network",
- "required": false
},
- {
- "schema": {
- "type": "string"
- },
- "example": "1234",
- "in": "query",
- "name": "positionAddress",
- "required": true,
- "description": "Position NFT token ID"
- }
- ],
- "responses": {
- "200": {
+ "400": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -13549,180 +6943,154 @@
}
}
},
- "/connectors/pancakeswap/clmm/positions-owned": {
+ "/trading/clmm/fetch-pools": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get all Pancakeswap V3 positions owned by a wallet",
+ "operationId": "fetchClmmPools",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Discover pools from a CLMM connector's own pool-listing API",
"parameters": [
{
"schema": {
- "default": "bsc",
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
"type": "string"
},
- "example": "bsc",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "network",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
+ "enum": [
+ "meteora",
+ "orca"
+ ],
+ "default": "meteora",
"type": "string"
},
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
+ "example": "meteora",
"in": "query",
- "name": "walletAddress",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
- }
- }
- }
- }
- }
- }
- },
- "/connectors/pancakeswap/clmm/quote-position": {
- "get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get a quote for opening a position on Pancakeswap V3",
- "parameters": [
+ "name": "connector",
+ "required": true,
+ "description": "CLMM connector whose pool-discovery API to query"
+ },
{
"schema": {
- "type": "string",
- "default": "bsc"
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 50,
+ "type": "number"
},
- "example": "bsc",
"in": "query",
- "name": "network",
- "required": false
+ "name": "limit",
+ "required": false,
+ "description": "Maximum number of pools to return"
},
{
"schema": {
- "type": "number"
+ "type": "string"
+ },
+ "examples": {
+ "SOL": {
+ "value": "SOL"
+ },
+ "SOL-USDC": {
+ "value": "SOL-USDC"
+ }
},
- "example": 0.0008,
"in": "query",
- "name": "lowerPrice",
- "required": true
+ "name": "query",
+ "required": false,
+ "description": "Search pools by name, token, or address"
},
{
"schema": {
- "type": "number"
+ "type": "string"
+ },
+ "examples": {
+ "tvl": {
+ "value": "tvl"
+ },
+ "tvl:desc": {
+ "value": "tvl:desc"
+ }
},
- "example": 0.001,
"in": "query",
- "name": "upperPrice",
- "required": true
+ "name": "sortBy",
+ "required": false,
+ "description": "Sort field. Meteora takes a \"field:direction\" pair; Orca takes the field alone with sortDirection."
},
{
"schema": {
- "type": "string",
- "default": "0x172fcd41e0913e95784454622d1c3724f546f849"
+ "minimum": 0,
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "number"
},
- "example": "0x172fcd41e0913e95784454622d1c3724f546f849",
"in": "query",
- "name": "poolAddress",
- "required": true
+ "name": "page",
+ "required": false,
+ "description": "0-based page index. Only connectors whose API paginates honor this."
},
{
"schema": {
- "type": "number"
+ "x-connectors": [
+ "meteora"
+ ],
+ "type": "boolean"
},
- "example": 10,
"in": "query",
- "name": "baseTokenAmount",
- "required": false
+ "name": "includeUnverified",
+ "required": false,
+ "description": "Include unverified pools"
},
{
"schema": {
- "type": "number"
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "x-connectors": [
+ "orca"
+ ],
+ "type": "string"
},
- "example": 0.01,
"in": "query",
- "name": "quoteTokenAmount",
- "required": false
+ "name": "sortDirection",
+ "required": false,
+ "description": "Sort direction"
},
{
"schema": {
- "minimum": 0,
- "maximum": 100,
- "type": "number"
+ "x-connectors": [
+ "orca"
+ ],
+ "type": "boolean"
},
"in": "query",
- "name": "slippagePct",
- "required": false
+ "name": "verifiedOnly",
+ "required": false,
+ "description": "Return only verified pools"
}
],
"responses": {
@@ -13731,32 +7099,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
+ "$ref": "#/components/schemas/ClmmFetchPoolsResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -13764,75 +7127,126 @@
}
}
},
- "/connectors/pancakeswap/clmm/quote-swap": {
+ "/trading/clmm/quote-swap": {
"get": {
- "tags": ["/connector/pancakeswap"],
- "description": "Get swap quote for Pancakeswap V3 CLMM",
+ "operationId": "quoteClmmSwap",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Get a swap quote from a single CLMM pool",
"parameters": [
{
"schema": {
- "type": "string",
- "default": "bsc"
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
},
- "example": "bsc",
+ "example": "solana-mainnet-beta",
"in": "query",
- "name": "network",
- "required": false
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
+ "enum": [
+ "meteora",
+ "raydium",
+ "orca",
+ "pancakeswap-sol",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
"type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "poolAddress",
+ "name": "connector",
"required": false,
- "description": "Pool address (optional - can be looked up from baseToken and quoteToken)"
+ "description": "CLMM connector to price the swap against"
},
{
"schema": {
+ "default": "SOL",
"type": "string"
},
- "example": "USDT",
"in": "query",
"name": "baseToken",
- "required": true
+ "required": true,
+ "description": "Symbol or address of the base token"
},
{
"schema": {
+ "default": "USDC",
"type": "string"
},
- "example": "WBNB",
"in": "query",
"name": "quoteToken",
- "required": false
+ "required": true,
+ "description": "Symbol or address of the quote token"
},
{
"schema": {
+ "format": "decimal",
+ "default": 1,
"type": "number"
},
- "example": 10,
"in": "query",
"name": "amount",
- "required": true
+ "required": true,
+ "description": "Amount of base token to trade"
},
{
"schema": {
- "type": "string",
- "enum": ["BUY", "SELL"]
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
},
- "example": "SELL",
"in": "query",
"name": "side",
- "required": true
+ "required": true,
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token"
+ },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "in": "query",
+ "name": "poolAddress",
+ "required": false,
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list."
},
{
"schema": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
"type": "number"
},
"example": 1,
"in": "query",
"name": "slippagePct",
- "required": false
+ "required": false,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct."
}
],
"responses": {
@@ -13841,50 +7255,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
+ "$ref": "#/components/schemas/ChainQuoteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -13892,62 +7283,71 @@
}
}
},
- "/connectors/pancakeswap/clmm/execute-swap": {
+ "/trading/clmm/execute-swap": {
"post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Execute a swap on Pancakeswap V3 CLMM using SwapRouter02",
+ "operationId": "executeClmmSwap",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Execute a swap against a single CLMM pool",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "walletAddress": {
- "description": "Wallet address that will execute the swap",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "network": {
- "description": "The blockchain network to use",
- "default": "mainnet",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string"
- },
- "baseToken": {
- "description": "Token to determine swap direction",
- "type": "string",
- "example": "USDT"
- },
- "quoteToken": {
- "description": "The other token in the pair",
- "type": "string",
- "example": "WBNB"
- },
- "amount": {
- "description": "Amount of base token to trade",
- "type": "number",
- "example": 10
- },
- "side": {
- "description": "Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token",
- "enum": ["BUY", "SELL"],
- "type": "string"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 1
- }
- },
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ "$ref": "#/components/schemas/ClmmExecuteSwapRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ChainExecuteSwapResponse"
+ }
}
}
},
- "required": true
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/clmm/open": {
+ "post": {
+ "operationId": "openClmmPosition",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Open a new CLMM position across supported connectors",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmOpenRequest"
+ }
+ }
+ }
},
"responses": {
"200": {
@@ -13955,60 +7355,127 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "description": "Transaction signature/hash",
- "type": "string"
- },
- "status": {
- "description": "Transaction status: 0 = PENDING, 1 = CONFIRMED, -1 = FAILED",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "description": "Address of the token swapped from",
- "type": "string"
- },
- "tokenOut": {
- "description": "Address of the token swapped to",
- "type": "string"
- },
- "amountIn": {
- "description": "Actual amount of tokenIn swapped",
- "type": "number"
- },
- "amountOut": {
- "description": "Actual amount of tokenOut received",
- "type": "number"
- },
- "fee": {
- "description": "Transaction fee paid",
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "description": "Change in base token balance (negative for decrease)",
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "description": "Change in quote token balance (negative for decrease)",
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ClmmOpenPositionResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/clmm/add": {
+ "post": {
+ "operationId": "addClmmLiquidity",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Add liquidity to an existing CLMM position across supported connectors",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmAddRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmAddLiquidityResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/clmm/remove": {
+ "post": {
+ "operationId": "removeClmmLiquidity",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Remove liquidity from a CLMM position across supported connectors",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmRemoveRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ClmmRemoveLiquidityResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14016,56 +7483,21 @@
}
}
},
- "/connectors/pancakeswap/clmm/open-position": {
+ "/trading/clmm/collect-fees": {
"post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Open a new liquidity position in a Pancakeswap V3 pool",
+ "operationId": "collectClmmFees",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Collect fees from a CLMM position across supported connectors",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "bsc",
- "example": "bsc"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "lowerPrice": {
- "type": "number",
- "example": 0.0008
- },
- "upperPrice": {
- "type": "number",
- "example": 0.001
- },
- "poolAddress": {
- "type": "string",
- "default": "0x172fcd41e0913e95784454622d1c3724f546f849",
- "example": "0x172fcd41e0913e95784454622d1c3724f546f849"
- },
- "baseTokenAmount": {
- "type": "number",
- "example": 10
- },
- "quoteTokenAmount": {
- "type": "number",
- "example": 0.01
- },
- "slippagePct": {
- "type": "number",
- "example": 1
- }
- },
- "required": ["lowerPrice", "upperPrice", "poolAddress"]
+ "$ref": "#/components/schemas/ClmmCollectFeesRequest"
}
}
- },
- "required": true
+ }
},
"responses": {
"200": {
@@ -14073,140 +7505,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ClmmCollectFeesResponse"
}
}
}
- }
- }
- }
- },
- "/connectors/pancakeswap/clmm/add-liquidity": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Add liquidity to an existing Pancakeswap V3 position",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "The EVM network to use",
- "default": "bsc",
- "enum": ["arbitrum", "base", "bsc", "mainnet"],
- "type": "string",
- "example": "bsc"
- },
- "walletAddress": {
- "description": "Wallet address that will add liquidity",
- "default": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50",
- "type": "string"
- },
- "positionAddress": {
- "description": "NFT token ID of the position",
- "type": "string"
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number"
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number"
- },
- "gasPrice": {
- "description": "Gas price in wei for the transaction",
- "type": "string"
- },
- "maxGas": {
- "description": "Maximum gas limit for the transaction",
- "type": "number",
- "example": 300000
- }
- },
- "required": ["positionAddress", "baseTokenAmount", "quoteTokenAmount"]
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14214,42 +7533,21 @@
}
}
},
- "/connectors/pancakeswap/clmm/remove-liquidity": {
+ "/trading/clmm/close": {
"post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Remove liquidity from a Pancakeswap V3 position",
+ "operationId": "closeClmmPosition",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Close a CLMM position across supported connectors",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "bsc",
- "example": "bsc"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "positionAddress": {
- "type": "string",
- "description": "Position NFT token ID",
- "example": "1234"
- },
- "percentageToRemove": {
- "type": "number",
- "minimum": 0,
- "maximum": 100,
- "example": 50
- }
- },
- "required": ["positionAddress", "percentageToRemove"]
+ "$ref": "#/components/schemas/ClmmCloseRequest"
}
}
- },
- "required": true
+ }
},
"responses": {
"200": {
@@ -14257,32 +7555,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ClmmClosePositionResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14290,36 +7583,21 @@
}
}
},
- "/connectors/pancakeswap/clmm/collect-fees": {
+ "/trading/clmm/create-pool": {
"post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Collect fees from a Pancakeswap V3 position",
+ "operationId": "createClmmPool",
+ "tags": [
+ "/trading/clmm"
+ ],
+ "description": "Create and initialize a new CLMM pool across supported connectors (Meteora DLMM, Raydium CLMM, PancakeSwap Solana CLMM, Orca Whirlpool, Uniswap V3, PancakeSwap V3)",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string",
- "default": "bsc",
- "example": "bsc"
- },
- "walletAddress": {
- "type": "string",
- "example": "0xB6B3140Eb3953BCE564f937948f98Ab5A8286a50"
- },
- "positionAddress": {
- "type": "string",
- "description": "Position NFT token ID",
- "example": "1234"
- }
- },
- "required": ["positionAddress"]
+ "$ref": "#/components/schemas/ClmmCreatePoolRequest"
}
}
- },
- "required": true
+ }
},
"responses": {
"200": {
@@ -14327,32 +7605,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ClmmCreatePoolResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14360,80 +7633,95 @@
}
}
},
- "/connectors/pancakeswap/clmm/close-position": {
- "post": {
- "tags": ["/connector/pancakeswap"],
- "description": "Close a Pancakeswap V3 position by removing all liquidity and collecting fees",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "network": {
- "type": "string"
- },
- "walletAddress": {
- "type": "string"
- },
- "positionAddress": {
- "type": "string"
- }
- },
- "required": ["positionAddress"]
+ "/trading/amm/pool-info": {
+ "get": {
+ "operationId": "getAmmPoolInfo",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Get AMM pool information from any supported connector",
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
+ "type": "string"
+ },
+ "example": "meteora",
+ "in": "query",
+ "name": "connector",
+ "required": true,
+ "description": "AMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
+ },
+ {
+ "schema": {
+ "type": "string"
+ },
+ "in": "query",
+ "name": "poolAddress",
+ "required": true,
+ "description": "Pool contract address"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmPoolInfo"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
}
}
},
- "required": true
- },
- "responses": {
- "200": {
+ "500": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14441,31 +7729,76 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/pool-info": {
+ "/trading/amm/position-info": {
"get": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Get CLMM pool information from PancakeSwap Solana",
+ "operationId": "getAmmPositionInfo",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Get a wallet's aggregated AMM liquidity in a pool from any supported connector",
"parameters": [
{
"schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
"type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ "name": "connector",
+ "required": true,
+ "description": "AMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN",
"in": "query",
"name": "poolAddress",
"required": true,
- "description": "PancakeSwap CLMM pool address"
+ "description": "Pool contract address"
+ },
+ {
+ "schema": {
+ "default": "",
+ "type": "string"
+ },
+ "in": "query",
+ "name": "walletAddress",
+ "required": true,
+ "description": "Wallet address"
}
],
"responses": {
@@ -14474,46 +7807,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "binStep": {
- "type": "number"
- },
- "feePct": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "activeBinId": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "baseTokenAddress",
- "quoteTokenAddress",
- "feePct",
- "price",
- "baseTokenAmount",
- "quoteTokenAmount",
- "activeBinId"
- ]
+ "$ref": "#/components/schemas/AmmPositionInfo"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14521,31 +7835,67 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/position-info": {
+ "/trading/amm/positions-owned": {
"get": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Get CLMM position information from PancakeSwap Solana",
+ "operationId": "listAmmPositions",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "List all AMM positions a wallet owns across pools. Supported only for non-fungible-LP AMMs (meteora DAMM v2). Fungible-LP AMMs (raydium, uniswap, pancakeswap) have no enumerable positions — use position-info with a specific pool address instead.",
"parameters": [
{
"schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
"type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ "name": "connector",
+ "required": true,
+ "description": "AMM connector (only non-fungible-LP AMMs supported: meteora)"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
+ "default": "",
"type": "string"
},
- "example": "",
"in": "query",
- "name": "positionAddress",
+ "name": "walletAddress",
"required": true,
- "description": "Position NFT address"
+ "description": "Wallet address to list positions for"
}
],
"responses": {
@@ -14554,69 +7904,30 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/AmmPositionInfo"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14624,115 +7935,128 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/positions-owned": {
+ "/trading/amm/quote-liquidity": {
"get": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Retrieve all positions owned by a user's wallet across all PancakeSwap Solana CLMM pools",
+ "operationId": "quoteAmmLiquidity",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Quote amounts for adding liquidity to an AMM pool from any supported connector",
"parameters": [
{
"schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
"type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "network",
- "required": false,
- "description": "Solana network to use"
+ "name": "connector",
+ "required": true,
+ "description": "AMM connector"
+ },
+ {
+ "schema": {
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
},
{
"schema": {
"type": "string"
},
- "example": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
"in": "query",
- "name": "walletAddress",
+ "name": "poolAddress",
"required": true,
- "description": "Solana wallet address to check for positions"
+ "description": "Pool contract address"
},
{
"schema": {
- "type": "string"
+ "format": "decimal",
+ "type": "number"
},
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN",
"in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "Optional pool address to filter positions by specific pool"
- }
- ],
- "responses": {
- "200": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "address": {
- "type": "string"
- },
- "poolAddress": {
- "type": "string"
- },
- "baseTokenAddress": {
- "type": "string"
- },
- "quoteTokenAddress": {
- "type": "string"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseFeeAmount": {
- "type": "number"
- },
- "quoteFeeAmount": {
- "type": "number"
- },
- "lowerBinId": {
- "type": "number"
- },
- "upperBinId": {
- "type": "number"
- },
- "lowerPrice": {
- "type": "number"
- },
- "upperPrice": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "rewardTokenAddress": {
- "type": "string"
- },
- "rewardAmount": {
- "type": "number"
- }
- },
- "required": [
- "address",
- "poolAddress",
- "baseTokenAddress",
- "quoteTokenAddress",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseFeeAmount",
- "quoteFeeAmount",
- "lowerBinId",
- "upperBinId",
- "lowerPrice",
- "upperPrice",
- "price"
- ]
- }
+ "name": "baseTokenAmount",
+ "required": true,
+ "description": "Amount of base token to deposit"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "type": "number"
+ },
+ "in": "query",
+ "name": "quoteTokenAmount",
+ "required": true,
+ "description": "Amount of quote token to deposit"
+ },
+ {
+ "schema": {
+ "format": "decimal",
+ "minimum": 0,
+ "maximum": 100,
+ "type": "number"
+ },
+ "example": 1,
+ "in": "query",
+ "name": "slippagePct",
+ "required": false,
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmQuoteLiquidityResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14740,118 +8064,353 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/quote-position": {
+ "/trading/amm/quote-swap": {
"get": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Quote position amounts for PancakeSwap Solana CLMM (simplified)",
+ "operationId": "quoteAmmSwap",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Get a swap quote from a single AMM pool",
"parameters": [
{
"schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
+ "enum": [
+ "ethereum-arbitrum",
+ "ethereum-avalanche",
+ "ethereum-base",
+ "ethereum-bsc",
+ "ethereum-celo",
+ "ethereum-mainnet",
+ "ethereum-optimism",
+ "ethereum-polygon",
+ "ethereum-robinhoodchain",
+ "ethereum-robinhoodchain-testnet",
+ "ethereum-sepolia",
+ "ethereum-unichain",
+ "solana-devnet",
+ "solana-mainnet-beta"
+ ],
+ "default": "solana-mainnet-beta",
+ "type": "string"
+ },
+ "example": "solana-mainnet-beta",
+ "in": "query",
+ "name": "chainNetwork",
+ "required": true,
+ "description": "Chain and network in format: chain-network (e.g., solana-mainnet-beta, ethereum-mainnet)"
+ },
+ {
+ "schema": {
+ "enum": [
+ "meteora",
+ "raydium",
+ "uniswap",
+ "pancakeswap"
+ ],
+ "default": "meteora",
"type": "string"
},
+ "example": "meteora",
"in": "query",
- "name": "network",
+ "name": "connector",
"required": false,
- "description": "Solana network to use"
+ "description": "AMM connector to price the swap against"
},
{
"schema": {
+ "default": "SOL",
"type": "string"
},
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN",
"in": "query",
- "name": "poolAddress",
+ "name": "baseToken",
"required": true,
- "description": "PancakeSwap CLMM pool address"
+ "description": "Symbol or address of the base token"
},
{
"schema": {
- "type": "number"
+ "default": "USDC",
+ "type": "string"
},
- "example": 150,
"in": "query",
- "name": "lowerPrice",
+ "name": "quoteToken",
"required": true,
- "description": "Lower price bound for the position"
+ "description": "Symbol or address of the quote token"
},
{
"schema": {
+ "format": "decimal",
+ "default": 1,
"type": "number"
},
- "example": 250,
"in": "query",
- "name": "upperPrice",
+ "name": "amount",
"required": true,
- "description": "Upper price bound for the position"
+ "description": "Amount of base token to trade"
},
{
"schema": {
- "type": "number"
+ "enum": [
+ "BUY",
+ "SELL"
+ ],
+ "default": "SELL",
+ "type": "string"
},
- "example": 0.01,
"in": "query",
- "name": "baseTokenAmount",
- "required": false,
- "description": "Amount of base token to deposit"
+ "name": "side",
+ "required": true,
+ "description": "BUY means buying base token with quote token, SELL means selling base token for quote token"
},
{
"schema": {
- "type": "number"
+ "type": "string"
},
- "example": 2,
"in": "query",
- "name": "quoteTokenAmount",
+ "name": "poolAddress",
"required": false,
- "description": "Amount of quote token to deposit"
+ "description": "Pool to trade against. Omit to resolve it from Gateway's configured pool list by token pair; pass an address to pin a pool that is not in that list."
},
{
"schema": {
+ "format": "decimal",
"minimum": 0,
"maximum": 100,
- "default": 2,
"type": "number"
},
- "example": 2,
+ "example": 1,
"in": "query",
"name": "slippagePct",
"required": false,
- "description": "Maximum acceptable slippage percentage"
+ "description": "Maximum acceptable slippage percentage. Defaults to the connector's configured slippagePct."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ChainQuoteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/amm/execute-swap": {
+ "post": {
+ "operationId": "executeAmmSwap",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Execute a swap against a single AMM pool",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmExecuteSwapRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ChainExecuteSwapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/amm/add": {
+ "post": {
+ "operationId": "addAmmLiquidity",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Add liquidity to an AMM pool from any supported connector",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmAddRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmAddLiquidityResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
}
+ }
+ }
+ },
+ "/trading/amm/remove": {
+ "post": {
+ "operationId": "removeAmmLiquidity",
+ "tags": [
+ "/trading/amm"
+ ],
+ "description": "Remove liquidity from an AMM pool from any supported connector",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmRemoveRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmRemoveLiquidityResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/trading/amm/create-pool": {
+ "post": {
+ "operationId": "createAmmPool",
+ "tags": [
+ "/trading/amm"
],
+ "description": "Create and seed a new AMM pool across supported connectors (Meteora DAMM v2, Raydium CPMM, Uniswap V2, PancakeSwap V2)",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AmmCreatePoolRequest"
+ }
+ }
+ }
+ },
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "baseLimited": {
- "type": "boolean"
- },
- "baseTokenAmount": {
- "type": "number"
- },
- "quoteTokenAmount": {
- "type": "number"
- },
- "baseTokenAmountMax": {
- "type": "number"
- },
- "quoteTokenAmountMax": {
- "type": "number"
- },
- "liquidity": {}
- },
- "required": [
- "baseLimited",
- "baseTokenAmount",
- "quoteTokenAmount",
- "baseTokenAmountMax",
- "quoteTokenAmountMax"
- ]
+ "$ref": "#/components/schemas/AmmCreatePoolResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14859,85 +8418,136 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/quote-swap": {
+ "/chains/{chain}/status": {
"get": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Get swap quote for PancakeSwap Solana CLMM with fee and estimated price impact based on pool liquidity",
+ "operationId": "getChainStatus",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Get the status of a chain and network",
"parameters": [
{
"schema": {
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
"type": "string"
},
+ "example": "mainnet-beta",
"in": "query",
"name": "network",
"required": false,
- "description": "Solana network to use"
- },
- {
- "schema": {
- "type": "string"
- },
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN",
- "in": "query",
- "name": "poolAddress",
- "required": false,
- "description": "CLMM pool address (optional - can be looked up from tokens)"
+ "description": "Network to use. Defaults to the chain's configured default network."
},
{
"schema": {
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
"type": "string"
},
- "example": "SOL",
- "in": "query",
- "name": "baseToken",
+ "in": "path",
+ "name": "chain",
"required": true,
- "description": "Base token symbol or address"
+ "description": "Chain to operate on"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/StatusResponse"
+ }
+ }
+ }
},
- {
- "schema": {
- "type": "string"
- },
- "example": "USDC",
- "in": "query",
- "name": "quoteToken",
- "required": true,
- "description": "Quote token symbol or address"
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
},
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/chains/{chain}/estimate-gas": {
+ "get": {
+ "operationId": "estimateGas",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Estimate the current transaction fee on a chain",
+ "parameters": [
{
"schema": {
- "type": "number"
+ "enum": [
+ "devnet",
+ "mainnet-beta",
+ "arbitrum",
+ "avalanche",
+ "base",
+ "bsc",
+ "celo",
+ "mainnet",
+ "optimism",
+ "polygon",
+ "robinhoodchain-testnet",
+ "robinhoodchain",
+ "sepolia",
+ "unichain"
+ ],
+ "type": "string"
},
- "example": 0.01,
+ "example": "mainnet-beta",
"in": "query",
- "name": "amount",
- "required": true,
- "description": "Amount to swap"
+ "name": "network",
+ "required": false,
+ "description": "Network to use. Defaults to the chain's configured default network."
},
{
"schema": {
- "enum": ["BUY", "SELL"],
- "default": "SELL",
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
"type": "string"
},
- "in": "query",
- "name": "side",
+ "in": "path",
+ "name": "chain",
"required": true,
- "description": "Trade direction"
- },
- {
- "schema": {
- "minimum": 0,
- "maximum": 100,
- "default": 2,
- "type": "number"
- },
- "example": 2,
- "in": "query",
- "name": "slippagePct",
- "required": false,
- "description": "Maximum acceptable slippage percentage"
+ "description": "Chain to operate on"
}
],
"responses": {
@@ -14946,50 +8556,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "poolAddress": {
- "type": "string"
- },
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "price": {
- "type": "number"
- },
- "slippagePct": {
- "type": "number"
- },
- "minAmountOut": {
- "type": "number"
- },
- "maxAmountIn": {
- "type": "number"
- },
- "priceImpactPct": {
- "type": "number"
- }
- },
- "required": [
- "poolAddress",
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "price",
- "minAmountOut",
- "maxAmountIn",
- "priceImpactPct"
- ]
+ "$ref": "#/components/schemas/EstimateGasResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -14997,121 +8584,65 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/execute-swap": {
+ "/chains/{chain}/balances": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Execute a swap on PancakeSwap Solana CLMM",
+ "operationId": "getBalances",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Get token balances for a wallet",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "poolAddress": {
- "description": "CLMM pool address (optional)",
- "type": "string",
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN"
- },
- "baseToken": {
- "description": "Base token symbol or address",
- "type": "string",
- "example": "SOL"
- },
- "quoteToken": {
- "description": "Quote token symbol or address",
- "type": "string",
- "example": "USDC"
- },
- "amount": {
- "description": "Amount to swap",
- "type": "number",
- "example": 0.01
- },
- "side": {
- "description": "Trade direction",
- "enum": ["BUY", "SELL"],
- "default": "SELL",
- "type": "string",
- "example": "SELL"
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["baseToken", "quoteToken", "amount", "side"]
+ "$ref": "#/components/schemas/BalanceRequest"
}
}
- },
- "required": true
+ }
},
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
+ "type": "string"
+ },
+ "in": "path",
+ "name": "chain",
+ "required": true,
+ "description": "Chain to operate on"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "tokenIn": {
- "type": "string"
- },
- "tokenOut": {
- "type": "string"
- },
- "amountIn": {
- "type": "number"
- },
- "amountOut": {
- "type": "number"
- },
- "fee": {
- "type": "number"
- },
- "baseTokenBalanceChange": {
- "type": "number"
- },
- "quoteTokenBalanceChange": {
- "type": "number"
- }
- },
- "required": [
- "tokenIn",
- "tokenOut",
- "amountIn",
- "amountOut",
- "fee",
- "baseTokenBalanceChange",
- "quoteTokenBalanceChange"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/BalanceResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15119,111 +8650,65 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/open-position": {
+ "/chains/{chain}/poll": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Open a new PancakeSwap Solana CLMM position with Token2022 NFT",
+ "operationId": "pollTransaction",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Poll a transaction by signature/hash",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "poolAddress": {
- "description": "PancakeSwap CLMM pool address",
- "type": "string",
- "example": "4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN"
- },
- "lowerPrice": {
- "description": "Lower price bound for the position",
- "type": "number",
- "example": 150
- },
- "upperPrice": {
- "description": "Upper price bound for the position",
- "type": "number",
- "example": 250
- },
- "baseTokenAmount": {
- "description": "Amount of base token to deposit",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to deposit",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["poolAddress", "lowerPrice", "upperPrice"]
+ "$ref": "#/components/schemas/PollRequest"
}
}
- },
- "required": true
+ }
},
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
+ "type": "string"
+ },
+ "in": "path",
+ "name": "chain",
+ "required": true,
+ "description": "Chain to operate on"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionAddress": {
- "type": "string"
- },
- "positionRent": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionAddress",
- "positionRent",
- "baseTokenAmountAdded",
- "quoteTokenAmountAdded"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/PollResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15231,89 +8716,65 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/add-liquidity": {
+ "/chains/{chain}/wrap": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Add liquidity to an existing PancakeSwap Solana CLMM position",
+ "operationId": "wrapNativeToken",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Wrap native token into its wrapped form (SOL to WSOL, ETH to WETH, ...)",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": ""
- },
- "baseTokenAmount": {
- "description": "Amount of base token to add",
- "type": "number",
- "example": 0.01
- },
- "quoteTokenAmount": {
- "description": "Amount of quote token to add",
- "type": "number",
- "example": 2
- },
- "slippagePct": {
- "minimum": 0,
- "maximum": 100,
- "description": "Maximum acceptable slippage percentage",
- "default": 2,
- "type": "number",
- "example": 2
- }
- },
- "required": ["positionAddress", "baseTokenAmount", "quoteTokenAmount"]
+ "$ref": "#/components/schemas/WrapRequest"
}
}
- },
- "required": true
+ }
},
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
+ "type": "string"
+ },
+ "in": "path",
+ "name": "chain",
+ "required": true,
+ "description": "Chain to operate on"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountAdded": {
- "type": "number"
- },
- "quoteTokenAmountAdded": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountAdded", "quoteTokenAmountAdded"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ChainWrapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15321,78 +8782,65 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/remove-liquidity": {
+ "/chains/{chain}/unwrap": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Remove liquidity from a PancakeSwap Solana CLMM position",
+ "operationId": "unwrapNativeToken",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Unwrap a wrapped native token back into the native token",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address to remove liquidity from",
- "type": "string",
- "example": ""
- },
- "percentageToRemove": {
- "minimum": 0,
- "maximum": 100,
- "description": "Percentage of liquidity to remove",
- "type": "number",
- "example": 100
- }
- },
- "required": ["positionAddress", "percentageToRemove"]
+ "$ref": "#/components/schemas/UnwrapRequest"
}
}
- },
- "required": true
+ }
},
+ "parameters": [
+ {
+ "schema": {
+ "enum": [
+ "solana",
+ "ethereum"
+ ],
+ "default": "solana",
+ "type": "string"
+ },
+ "in": "path",
+ "name": "chain",
+ "required": true,
+ "description": "Chain to operate on"
+ }
+ ],
"responses": {
"200": {
"description": "Default Response",
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- }
- },
- "required": ["fee", "baseTokenAmountRemoved", "quoteTokenAmountRemoved"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ChainWrapResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15400,38 +8848,21 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/collect-fees": {
+ "/chains/ethereum/allowances": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Collect accumulated fees from a PancakeSwap Solana CLMM position (removes 1% liquidity)",
+ "operationId": "getAllowances",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Get token allowances",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address",
- "type": "string",
- "example": ""
- }
- },
- "required": ["positionAddress"]
+ "$ref": "#/components/schemas/AllowancesRequest"
}
}
- },
- "required": true
+ }
},
"responses": {
"200": {
@@ -15439,32 +8870,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": ["fee", "baseFeeAmountCollected", "quoteFeeAmountCollected"]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/AllowancesResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15472,38 +8898,21 @@
}
}
},
- "/connectors/pancakeswap-sol/clmm/close-position": {
+ "/chains/ethereum/approve": {
"post": {
- "tags": ["/connector/pancakeswap-sol"],
- "description": "Close a PancakeSwap Solana CLMM position and remove all liquidity and fees if present",
+ "operationId": "approveToken",
+ "tags": [
+ "/chains"
+ ],
+ "description": "Approve token spending",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "network": {
- "description": "Solana network to use",
- "default": "mainnet-beta",
- "enum": ["devnet", "mainnet-beta"],
- "type": "string"
- },
- "walletAddress": {
- "description": "Solana wallet address",
- "default": "Fxu7UU5D9ry1qDQj41Yp3oTeAdqxShzVYna44JE7E1gn",
- "type": "string"
- },
- "positionAddress": {
- "description": "Position NFT address to close",
- "type": "string",
- "example": ""
- }
- },
- "required": ["positionAddress"]
+ "$ref": "#/components/schemas/ApproveRequest"
}
}
- },
- "required": true
+ }
},
"responses": {
"200": {
@@ -15511,48 +8920,27 @@
"content": {
"application/json": {
"schema": {
- "type": "object",
- "properties": {
- "signature": {
- "type": "string"
- },
- "status": {
- "description": "TransactionStatus enum value",
- "type": "number"
- },
- "data": {
- "type": "object",
- "properties": {
- "fee": {
- "type": "number"
- },
- "positionRentRefunded": {
- "type": "number"
- },
- "baseTokenAmountRemoved": {
- "type": "number"
- },
- "quoteTokenAmountRemoved": {
- "type": "number"
- },
- "baseFeeAmountCollected": {
- "type": "number"
- },
- "quoteFeeAmountCollected": {
- "type": "number"
- }
- },
- "required": [
- "fee",
- "positionRentRefunded",
- "baseTokenAmountRemoved",
- "quoteTokenAmountRemoved",
- "baseFeeAmountCollected",
- "quoteFeeAmountCollected"
- ]
- }
- },
- "required": ["signature", "status"]
+ "$ref": "#/components/schemas/ApproveResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -15584,52 +8972,20 @@
"description": "Pool management endpoints"
},
{
- "name": "/trading/swap",
- "description": "Unified cross-chain swap endpoints"
- },
- {
- "name": "/trading/clmm",
- "description": "Unified cross-chain CLMM (Concentrated Liquidity) endpoints"
- },
- {
- "name": "/chain/solana",
- "description": "Solana and SVM-based chain endpoints"
- },
- {
- "name": "/chain/ethereum",
- "description": "Ethereum and EVM-based chain endpoints"
- },
- {
- "name": "/connector/jupiter",
- "description": "Jupiter connector endpoints"
- },
- {
- "name": "/connector/meteora",
- "description": "Meteora connector endpoints"
- },
- {
- "name": "/connector/orca",
- "description": "Orca connector endpoints"
- },
- {
- "name": "/connector/raydium",
- "description": "Raydium connector endpoints"
- },
- {
- "name": "/connector/uniswap",
- "description": "Uniswap connector endpoints"
+ "name": "/chains",
+ "description": "Chain endpoints, parameterized by chain"
},
{
- "name": "/connector/0x",
- "description": "0x connector endpoints"
+ "name": "/trading/router",
+ "description": "Swaps routed across pools by a router connector"
},
{
- "name": "/connector/pancakeswap-sol",
- "description": "PancakeSwap Solana connector endpoints"
+ "name": "/trading/clmm",
+ "description": "Concentrated-liquidity pools: swaps, positions, and pool management"
},
{
- "name": "/connector/pancakeswap",
- "description": "PancakeSwap EVM connector endpoints"
+ "name": "/trading/amm",
+ "description": "Constant-product pools: swaps, liquidity, and pool management"
}
]
}
diff --git a/package.json b/package.json
index 005c7718b4..10c188f704 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"test:scripts": "GATEWAY_TEST_MODE=dev jest --runInBand ./test-scripts/*.test.ts",
"typecheck": "tsc --noEmit",
"wallet:create": "npx ts-node scripts/create-wallet.ts",
- "generate:openapi": "curl http://localhost:15888/docs/json -o openapi.json && echo 'OpenAPI spec saved to openapi.json'",
+ "generate:openapi": "npx ts-node scripts/generate-openapi.ts",
"rebuild-bigint": "cd node_modules/bigint-buffer && pnpm run rebuild",
"prepare": "pnpm husky"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a03794f009..9c9704891d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -16,7 +16,6 @@ overrides:
axios: ^1.8.4
importers:
-
.:
dependencies:
'@coral-xyz/anchor':
@@ -382,155 +381,193 @@ importers:
version: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)
packages:
-
'@adraffy/ens-normalize@1.11.0':
- resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==}
+ resolution:
+ { integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== }
'@ampproject/remapping@2.3.0':
- resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== }
+ engines: { node: '>=6.0.0' }
'@aws-crypto/crc32@5.2.0':
- resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==}
- engines: {node: '>=16.0.0'}
+ resolution:
+ { integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== }
+ engines: { node: '>=16.0.0' }
'@aws-crypto/crc32c@5.2.0':
- resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==}
+ resolution:
+ { integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag== }
'@aws-crypto/sha1-browser@5.2.0':
- resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==}
+ resolution:
+ { integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg== }
'@aws-crypto/sha256-browser@5.2.0':
- resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==}
+ resolution:
+ { integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== }
'@aws-crypto/sha256-js@5.2.0':
- resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==}
- engines: {node: '>=16.0.0'}
+ resolution:
+ { integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== }
+ engines: { node: '>=16.0.0' }
'@aws-crypto/supports-web-crypto@5.2.0':
- resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==}
+ resolution:
+ { integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== }
'@aws-crypto/util@5.2.0':
- resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
+ resolution:
+ { integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== }
'@aws-sdk/client-s3@3.806.0':
- resolution: {integrity: sha512-kQaBBBxEBU/IJ2wKG+LL2BK+uvBwpdvOA9jy1WhW+U2/DIMwMrjVs7M/ZvTlmVOJwhZaONcJbgQqsN4Yirjj4g==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-kQaBBBxEBU/IJ2wKG+LL2BK+uvBwpdvOA9jy1WhW+U2/DIMwMrjVs7M/ZvTlmVOJwhZaONcJbgQqsN4Yirjj4g== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/client-sso@3.806.0':
- resolution: {integrity: sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/core@3.806.0':
- resolution: {integrity: sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-env@3.806.0':
- resolution: {integrity: sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-http@3.806.0':
- resolution: {integrity: sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-ini@3.806.0':
- resolution: {integrity: sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-node@3.806.0':
- resolution: {integrity: sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-process@3.806.0':
- resolution: {integrity: sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-sso@3.806.0':
- resolution: {integrity: sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/credential-provider-web-identity@3.806.0':
- resolution: {integrity: sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-bucket-endpoint@3.806.0':
- resolution: {integrity: sha512-ACjuyKJw9OZl8z8HzPEaqn1o7ElVW94mowyoZvyUIDouwAPGqPGJbJ5V35qx1oDTFSAJX+N3O3AO6RyFc8nUhw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-ACjuyKJw9OZl8z8HzPEaqn1o7ElVW94mowyoZvyUIDouwAPGqPGJbJ5V35qx1oDTFSAJX+N3O3AO6RyFc8nUhw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-expect-continue@3.804.0':
- resolution: {integrity: sha512-YW1hySBolALMII6C8y7Z0CRG2UX1dGJjLEBNFeefhO/xP7ZuE1dvnmfJGaEuBMnvc3wkRS63VZ3aqX6sevM1CA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-YW1hySBolALMII6C8y7Z0CRG2UX1dGJjLEBNFeefhO/xP7ZuE1dvnmfJGaEuBMnvc3wkRS63VZ3aqX6sevM1CA== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-flexible-checksums@3.806.0':
- resolution: {integrity: sha512-YEmuU2Nr/+blhi70gS38fnCe2IoL6OVVZXMp4MbzqZRUqeBbnxZhHQrd5YOiboJz7iq+g98xwFebHY167iejcg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-YEmuU2Nr/+blhi70gS38fnCe2IoL6OVVZXMp4MbzqZRUqeBbnxZhHQrd5YOiboJz7iq+g98xwFebHY167iejcg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-host-header@3.804.0':
- resolution: {integrity: sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-location-constraint@3.804.0':
- resolution: {integrity: sha512-AMtKnllIWKgoo7hiJfphLYotEwTERfjVMO2+cKAncz9w1g+bnYhHxiVhJJoR94y047c06X4PU5MsTxvdQ73Znw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-AMtKnllIWKgoo7hiJfphLYotEwTERfjVMO2+cKAncz9w1g+bnYhHxiVhJJoR94y047c06X4PU5MsTxvdQ73Znw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-logger@3.804.0':
- resolution: {integrity: sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-recursion-detection@3.804.0':
- resolution: {integrity: sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-sdk-s3@3.806.0':
- resolution: {integrity: sha512-K1ssdovHH/kPN9EUS1LznwzoL+r89Cx8qAkp0K8MqdCQuBjZ0KRnjvo9nx69Vg5d/rg01VYTxomFUPXfcPtVXw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-K1ssdovHH/kPN9EUS1LznwzoL+r89Cx8qAkp0K8MqdCQuBjZ0KRnjvo9nx69Vg5d/rg01VYTxomFUPXfcPtVXw== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-ssec@3.804.0':
- resolution: {integrity: sha512-Tk8jK0gOIUBvEPTz/wwSlP1V70zVQ3QYqsLPAjQRMO6zfOK9ax31dln3MgKvFDJxBydS2tS3wsn53v+brxDxTA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Tk8jK0gOIUBvEPTz/wwSlP1V70zVQ3QYqsLPAjQRMO6zfOK9ax31dln3MgKvFDJxBydS2tS3wsn53v+brxDxTA== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/middleware-user-agent@3.806.0':
- resolution: {integrity: sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/nested-clients@3.806.0':
- resolution: {integrity: sha512-ua2gzpfQ9MF8Rny+tOAivowOWWvqEusez2rdcQK8jdBjA1ANd/0xzToSZjZh0ziN8Kl8jOhNnHbQJ0v6dT6+hg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-ua2gzpfQ9MF8Rny+tOAivowOWWvqEusez2rdcQK8jdBjA1ANd/0xzToSZjZh0ziN8Kl8jOhNnHbQJ0v6dT6+hg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/region-config-resolver@3.806.0':
- resolution: {integrity: sha512-cuv5pX55JOlzKC/iLsB5nZ9eUyVgncim3VhhWHZA/KYPh7rLMjOEfZ+xyaE9uLJXGmzOJboFH7+YdTRdIcOgrg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-cuv5pX55JOlzKC/iLsB5nZ9eUyVgncim3VhhWHZA/KYPh7rLMjOEfZ+xyaE9uLJXGmzOJboFH7+YdTRdIcOgrg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/signature-v4-multi-region@3.806.0':
- resolution: {integrity: sha512-IrbEnpKvG8d9rUWAvsF28g8qBlQ02FaOxn4cGXtTs0b0BGMK1M+cGQrYjJ7Ak08kIXDxBqsdIlZGsKYr+Ds9+w==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-IrbEnpKvG8d9rUWAvsF28g8qBlQ02FaOxn4cGXtTs0b0BGMK1M+cGQrYjJ7Ak08kIXDxBqsdIlZGsKYr+Ds9+w== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/token-providers@3.806.0':
- resolution: {integrity: sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/types@3.804.0':
- resolution: {integrity: sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/util-arn-parser@3.804.0':
- resolution: {integrity: sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/util-endpoints@3.806.0':
- resolution: {integrity: sha512-3YRRgZ+qFuWDdm5uAbxKsr65UAil4KkrFKua9f4m7Be3v24ETiFOOqhanFUIk9/WOtvzF7oFEiDjYKDGlwV2xg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-3YRRgZ+qFuWDdm5uAbxKsr65UAil4KkrFKua9f4m7Be3v24ETiFOOqhanFUIk9/WOtvzF7oFEiDjYKDGlwV2xg== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/util-locate-window@3.804.0':
- resolution: {integrity: sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A== }
+ engines: { node: '>=18.0.0' }
'@aws-sdk/util-user-agent-browser@3.804.0':
- resolution: {integrity: sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==}
+ resolution:
+ { integrity: sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A== }
'@aws-sdk/util-user-agent-node@3.806.0':
- resolution: {integrity: sha512-Az2e4/gmPZ4BpB7QRj7U76I+fctXhNcxlcgsaHnMhvt+R30nvzM2EhsyBUvsWl8+r9bnLeYt9BpvEZeq2ANDzA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Az2e4/gmPZ4BpB7QRj7U76I+fctXhNcxlcgsaHnMhvt+R30nvzM2EhsyBUvsWl8+r9bnLeYt9BpvEZeq2ANDzA== }
+ engines: { node: '>=18.0.0' }
peerDependencies:
aws-crt: '>=1.0.0'
peerDependenciesMeta:
@@ -538,625 +575,772 @@ packages:
optional: true
'@aws-sdk/xml-builder@3.804.0':
- resolution: {integrity: sha512-JbGWp36IG9dgxtvC6+YXwt5WDZYfuamWFtVfK6fQpnmL96dx+GUPOXPKRWdw67WLKf2comHY28iX2d3z35I53Q==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-JbGWp36IG9dgxtvC6+YXwt5WDZYfuamWFtVfK6fQpnmL96dx+GUPOXPKRWdw67WLKf2comHY28iX2d3z35I53Q== }
+ engines: { node: '>=18.0.0' }
'@babel/code-frame@7.27.1':
- resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== }
+ engines: { node: '>=6.9.0' }
'@babel/compat-data@7.27.2':
- resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ== }
+ engines: { node: '>=6.9.0' }
'@babel/core@7.27.1':
- resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== }
+ engines: { node: '>=6.9.0' }
'@babel/generator@7.27.1':
- resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-compilation-targets@7.27.2':
- resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-module-imports@7.27.1':
- resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-module-transforms@7.27.1':
- resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-plugin-utils@7.27.1':
- resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-string-parser@7.27.1':
- resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-validator-identifier@7.27.1':
- resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== }
+ engines: { node: '>=6.9.0' }
'@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== }
+ engines: { node: '>=6.9.0' }
'@babel/helpers@7.27.1':
- resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ== }
+ engines: { node: '>=6.9.0' }
'@babel/parser@7.27.2':
- resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw== }
+ engines: { node: '>=6.0.0' }
hasBin: true
'@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ resolution:
+ { integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-bigint@7.8.3':
- resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
+ resolution:
+ { integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ resolution:
+ { integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-class-static-block@7.14.5':
- resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-import-attributes@7.27.1':
- resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+ resolution:
+ { integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ resolution:
+ { integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-jsx@7.27.1':
- resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ resolution:
+ { integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ resolution:
+ { integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ resolution:
+ { integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ resolution:
+ { integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ resolution:
+ { integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ resolution:
+ { integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-private-property-in-object@7.14.5':
- resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-typescript@7.27.1':
- resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== }
+ engines: { node: '>=6.9.0' }
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/runtime@7.27.1':
- resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog== }
+ engines: { node: '>=6.9.0' }
'@babel/template@7.27.2':
- resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== }
+ engines: { node: '>=6.9.0' }
'@babel/traverse@7.27.1':
- resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg== }
+ engines: { node: '>=6.9.0' }
'@babel/types@7.27.1':
- resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q== }
+ engines: { node: '>=6.9.0' }
'@bcoe/v8-coverage@0.2.3':
- resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ resolution:
+ { integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== }
'@bundlr-network/client@0.7.17':
- resolution: {integrity: sha512-1qTDrwgmgeh0pO24JbeGt2W8GlpWYkVnQ8AhEZ02Lm00J7RALSyma3C5pNlKuvAQBczL1r9KhLr9KHK1og3J0g==}
+ resolution:
+ { integrity: sha512-1qTDrwgmgeh0pO24JbeGt2W8GlpWYkVnQ8AhEZ02Lm00J7RALSyma3C5pNlKuvAQBczL1r9KhLr9KHK1og3J0g== }
deprecated: Bundlr is now Irys - please switch to @irys/sdk - this package will remain compatible with Irys for the foreseeable future.
hasBin: true
'@colors/colors@1.6.0':
- resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
- engines: {node: '>=0.1.90'}
+ resolution:
+ { integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== }
+ engines: { node: '>=0.1.90' }
'@coral-xyz/anchor-errors@0.30.1':
- resolution: {integrity: sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ== }
+ engines: { node: '>=10' }
'@coral-xyz/anchor-errors@0.31.1':
- resolution: {integrity: sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ== }
+ engines: { node: '>=10' }
'@coral-xyz/anchor@0.30.1':
- resolution: {integrity: sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ==}
- engines: {node: '>=11'}
+ resolution:
+ { integrity: sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ== }
+ engines: { node: '>=11' }
'@coral-xyz/anchor@0.31.0':
- resolution: {integrity: sha512-Yb1NwP1s4cWhAw7wL7vOLHSWWw3cD5D9pRCVSeJpdqPaI+w7sfRLScnVJL6ViYMZynB7nAG/5HcUPKUnY0L9rw==}
- engines: {node: '>=17'}
+ resolution:
+ { integrity: sha512-Yb1NwP1s4cWhAw7wL7vOLHSWWw3cD5D9pRCVSeJpdqPaI+w7sfRLScnVJL6ViYMZynB7nAG/5HcUPKUnY0L9rw== }
+ engines: { node: '>=17' }
'@coral-xyz/borsh@0.30.1':
- resolution: {integrity: sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ== }
+ engines: { node: '>=10' }
peerDependencies:
'@solana/web3.js': ^1.68.0
'@coral-xyz/borsh@0.31.0':
- resolution: {integrity: sha512-DwdQ5fuj+rGQCTKRnxnW1W2lvcpBaFc9m9M1TcGGlm+bwCcggmDgbLKLgF+LjIrKnc7Nd+bCACx5RA9YTK2I4Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-DwdQ5fuj+rGQCTKRnxnW1W2lvcpBaFc9m9M1TcGGlm+bwCcggmDgbLKLgF+LjIrKnc7Nd+bCACx5RA9YTK2I4Q== }
+ engines: { node: '>=10' }
peerDependencies:
'@solana/web3.js': ^1.69.0
'@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== }
+ engines: { node: '>=12' }
'@dabh/diagnostics@2.0.3':
- resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
+ resolution:
+ { integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== }
'@emnapi/core@1.4.3':
- resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
+ resolution:
+ { integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g== }
'@emnapi/runtime@1.4.3':
- resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
+ resolution:
+ { integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== }
'@emnapi/wasi-threads@1.0.2':
- resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==}
+ resolution:
+ { integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA== }
'@esbuild/aix-ppc64@0.25.5':
- resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA== }
+ engines: { node: '>=18' }
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.25.5':
- resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.25.5':
- resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA== }
+ engines: { node: '>=18' }
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.25.5':
- resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.25.5':
- resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.25.5':
- resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.25.5':
- resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.5':
- resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.25.5':
- resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.25.5':
- resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw== }
+ engines: { node: '>=18' }
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.25.5':
- resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA== }
+ engines: { node: '>=18' }
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.25.5':
- resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg== }
+ engines: { node: '>=18' }
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.25.5':
- resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg== }
+ engines: { node: '>=18' }
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.25.5':
- resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ== }
+ engines: { node: '>=18' }
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.25.5':
- resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA== }
+ engines: { node: '>=18' }
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.25.5':
- resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ== }
+ engines: { node: '>=18' }
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.25.5':
- resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.25.5':
- resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.5':
- resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.25.5':
- resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.5':
- resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.25.5':
- resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.25.5':
- resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw== }
+ engines: { node: '>=18' }
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.25.5':
- resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ== }
+ engines: { node: '>=18' }
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.25.5':
- resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g== }
+ engines: { node: '>=18' }
cpu: [x64]
os: [win32]
'@eslint-community/eslint-utils@4.7.0':
- resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
'@eslint-community/regexpp@4.12.1':
- resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
- engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== }
+ engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 }
'@eslint/eslintrc@2.1.4':
- resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
'@eslint/js@8.57.1':
- resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
'@eth-optimism/contracts@0.6.0':
- resolution: {integrity: sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==}
+ resolution:
+ { integrity: sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w== }
peerDependencies:
ethers: ^5
'@eth-optimism/core-utils@0.12.0':
- resolution: {integrity: sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw==}
+ resolution:
+ { integrity: sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw== }
'@eth-optimism/core-utils@0.13.2':
- resolution: {integrity: sha512-u7TOKm1RxH1V5zw7dHmfy91bOuEAZU68LT/9vJPkuWEjaTl+BgvPDRDTurjzclHzN0GbWdcpOqPZg4ftjkJGaw==}
+ resolution:
+ { integrity: sha512-u7TOKm1RxH1V5zw7dHmfy91bOuEAZU68LT/9vJPkuWEjaTl+BgvPDRDTurjzclHzN0GbWdcpOqPZg4ftjkJGaw== }
'@eth-optimism/sdk@3.3.3':
- resolution: {integrity: sha512-I8xjchsZL6L66N/0Q14QvGZpsIiVfpuXBu+OX4HB3HXGvF7NQxXSRfOXzrQKj3ikhoJUpASsR4gL/yQsH+Vh3Q==}
+ resolution:
+ { integrity: sha512-I8xjchsZL6L66N/0Q14QvGZpsIiVfpuXBu+OX4HB3HXGvF7NQxXSRfOXzrQKj3ikhoJUpASsR4gL/yQsH+Vh3Q== }
peerDependencies:
ethers: ^5
'@ethereumjs/rlp@5.0.2':
- resolution: {integrity: sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA== }
+ engines: { node: '>=18' }
hasBin: true
'@ethereumjs/util@9.1.0':
- resolution: {integrity: sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog== }
+ engines: { node: '>=18' }
'@ethersproject/abi@5.8.0':
- resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==}
+ resolution:
+ { integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== }
'@ethersproject/abstract-provider@5.7.0':
- resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==}
+ resolution:
+ { integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== }
'@ethersproject/abstract-provider@5.8.0':
- resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==}
+ resolution:
+ { integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== }
'@ethersproject/abstract-signer@5.8.0':
- resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==}
+ resolution:
+ { integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== }
'@ethersproject/address@5.7.0':
- resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==}
+ resolution:
+ { integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== }
'@ethersproject/address@5.8.0':
- resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==}
+ resolution:
+ { integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== }
'@ethersproject/base64@5.8.0':
- resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==}
+ resolution:
+ { integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== }
'@ethersproject/basex@5.8.0':
- resolution: {integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==}
+ resolution:
+ { integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q== }
'@ethersproject/bignumber@5.8.0':
- resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==}
+ resolution:
+ { integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== }
'@ethersproject/bytes@5.8.0':
- resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==}
+ resolution:
+ { integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== }
'@ethersproject/constants@5.8.0':
- resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==}
+ resolution:
+ { integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== }
'@ethersproject/contracts@5.7.0':
- resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==}
+ resolution:
+ { integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== }
'@ethersproject/contracts@5.8.0':
- resolution: {integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==}
+ resolution:
+ { integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ== }
'@ethersproject/hash@5.8.0':
- resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==}
+ resolution:
+ { integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== }
'@ethersproject/hdnode@5.8.0':
- resolution: {integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==}
+ resolution:
+ { integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA== }
'@ethersproject/json-wallets@5.8.0':
- resolution: {integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==}
+ resolution:
+ { integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w== }
'@ethersproject/keccak256@5.7.0':
- resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==}
+ resolution:
+ { integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== }
'@ethersproject/keccak256@5.8.0':
- resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==}
+ resolution:
+ { integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== }
'@ethersproject/logger@5.8.0':
- resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==}
+ resolution:
+ { integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== }
'@ethersproject/networks@5.7.0':
- resolution: {integrity: sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA==}
+ resolution:
+ { integrity: sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA== }
'@ethersproject/networks@5.8.0':
- resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==}
+ resolution:
+ { integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== }
'@ethersproject/pbkdf2@5.8.0':
- resolution: {integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==}
+ resolution:
+ { integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg== }
'@ethersproject/properties@5.8.0':
- resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==}
+ resolution:
+ { integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== }
'@ethersproject/providers@5.7.0':
- resolution: {integrity: sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA==}
+ resolution:
+ { integrity: sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA== }
'@ethersproject/providers@5.8.0':
- resolution: {integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==}
+ resolution:
+ { integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw== }
'@ethersproject/random@5.8.0':
- resolution: {integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==}
+ resolution:
+ { integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A== }
'@ethersproject/rlp@5.8.0':
- resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==}
+ resolution:
+ { integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== }
'@ethersproject/sha2@5.8.0':
- resolution: {integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==}
+ resolution:
+ { integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A== }
'@ethersproject/signing-key@5.8.0':
- resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==}
+ resolution:
+ { integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== }
'@ethersproject/solidity@5.7.0':
- resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==}
+ resolution:
+ { integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== }
'@ethersproject/solidity@5.8.0':
- resolution: {integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==}
+ resolution:
+ { integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA== }
'@ethersproject/strings@5.7.0':
- resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==}
+ resolution:
+ { integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== }
'@ethersproject/strings@5.8.0':
- resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==}
+ resolution:
+ { integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== }
'@ethersproject/transactions@5.8.0':
- resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==}
+ resolution:
+ { integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== }
'@ethersproject/units@5.8.0':
- resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==}
+ resolution:
+ { integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ== }
'@ethersproject/wallet@5.8.0':
- resolution: {integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==}
+ resolution:
+ { integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA== }
'@ethersproject/web@5.8.0':
- resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==}
+ resolution:
+ { integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== }
'@ethersproject/wordlists@5.8.0':
- resolution: {integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==}
+ resolution:
+ { integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg== }
'@fastify/accept-negotiator@1.1.0':
- resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ== }
+ engines: { node: '>=14' }
'@fastify/ajv-compiler@3.6.0':
- resolution: {integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==}
+ resolution:
+ { integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ== }
'@fastify/busboy@2.1.1':
- resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== }
+ engines: { node: '>=14' }
'@fastify/error@3.4.1':
- resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==}
+ resolution:
+ { integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ== }
'@fastify/fast-json-stringify-compiler@4.3.0':
- resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
+ resolution:
+ { integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA== }
'@fastify/merge-json-schemas@0.1.1':
- resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==}
+ resolution:
+ { integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA== }
'@fastify/rate-limit@9.1.0':
- resolution: {integrity: sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA==}
+ resolution:
+ { integrity: sha512-h5dZWCkuZXN0PxwqaFQLxeln8/LNwQwH9popywmDCFdKfgpi4b/HoMH1lluy6P+30CG9yzzpSpwTCIPNB9T1JA== }
'@fastify/send@2.1.0':
- resolution: {integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==}
+ resolution:
+ { integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA== }
'@fastify/sensible@5.0.0':
- resolution: {integrity: sha512-JgHXTnjJaiMt3sesAhLeL2KSOCwB7A77L7tUARKpSmJKczGpNPjc2NhLcitTv6YBSgducF3I5H8N46XJdFvFdA==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-JgHXTnjJaiMt3sesAhLeL2KSOCwB7A77L7tUARKpSmJKczGpNPjc2NhLcitTv6YBSgducF3I5H8N46XJdFvFdA== }
+ engines: { node: '>=14.0.0' }
'@fastify/static@7.0.4':
- resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==}
+ resolution:
+ { integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q== }
'@fastify/swagger-ui@4.2.0':
- resolution: {integrity: sha512-pVutmTm49Pn98FS01E2m+eUH0WGhsHlImowWr9PXQt3rQPArSsocON8qF/8mm0dNLmilwtJZJqdsvFTnCUcapw==}
+ resolution:
+ { integrity: sha512-pVutmTm49Pn98FS01E2m+eUH0WGhsHlImowWr9PXQt3rQPArSsocON8qF/8mm0dNLmilwtJZJqdsvFTnCUcapw== }
'@fastify/swagger@8.15.0':
- resolution: {integrity: sha512-zy+HEEKFqPMS2sFUsQU5X0MHplhKJvWeohBwTCkBAJA/GDYGLGUWQaETEhptiqxK7Hs0fQB9B4MDb3pbwIiCwA==}
+ resolution:
+ { integrity: sha512-zy+HEEKFqPMS2sFUsQU5X0MHplhKJvWeohBwTCkBAJA/GDYGLGUWQaETEhptiqxK7Hs0fQB9B4MDb3pbwIiCwA== }
'@fastify/type-provider-typebox@4.1.0':
- resolution: {integrity: sha512-mXNBaBEoS6Yf4/O2ujNhu9yEZwvBC7niqRESsiftE9NP1hV6ZdV3ZsFbPf1S520BK3rTZ0F28zr+sMdIXNJlfw==}
+ resolution:
+ { integrity: sha512-mXNBaBEoS6Yf4/O2ujNhu9yEZwvBC7niqRESsiftE9NP1hV6ZdV3ZsFbPf1S520BK3rTZ0F28zr+sMdIXNJlfw== }
peerDependencies:
'@sinclair/typebox': '>=0.26 <=0.33'
'@graphql-typed-document-node/core@3.2.0':
- resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==}
+ resolution:
+ { integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== }
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
'@hapi/hoek@9.3.0':
- resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
+ resolution:
+ { integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== }
'@hapi/topo@5.1.0':
- resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ resolution:
+ { integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== }
'@humanwhocodes/config-array@0.13.0':
- resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
- engines: {node: '>=10.10.0'}
+ resolution:
+ { integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== }
+ engines: { node: '>=10.10.0' }
deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1':
- resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
- engines: {node: '>=12.22'}
+ resolution:
+ { integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== }
+ engines: { node: '>=12.22' }
'@humanwhocodes/object-schema@2.0.3':
- resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+ resolution:
+ { integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== }
deprecated: Use @eslint/object-schema instead
'@isaacs/cliui@8.0.2':
- resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== }
+ engines: { node: '>=12' }
'@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== }
+ engines: { node: '>=8' }
'@istanbuljs/schema@0.1.3':
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== }
+ engines: { node: '>=8' }
'@jest/console@24.9.0':
- resolution: {integrity: sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== }
+ engines: { node: '>= 6' }
'@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
@@ -1164,28 +1348,34 @@ packages:
optional: true
'@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/expect-utils@29.7.0':
- resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
@@ -1193,366 +1383,467 @@ packages:
optional: true
'@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/source-map@24.9.0':
- resolution: {integrity: sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== }
+ engines: { node: '>= 6' }
'@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/test-result@24.9.0':
- resolution: {integrity: sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== }
+ engines: { node: '>= 6' }
'@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jest/types@24.9.0':
- resolution: {integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== }
+ engines: { node: '>= 6' }
'@jest/types@29.6.3':
- resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
'@jridgewell/gen-mapping@0.3.8':
- resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== }
+ engines: { node: '>=6.0.0' }
'@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== }
+ engines: { node: '>=6.0.0' }
'@jridgewell/set-array@1.2.1':
- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== }
+ engines: { node: '>=6.0.0' }
'@jridgewell/sourcemap-codec@1.5.0':
- resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+ resolution:
+ { integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== }
'@jridgewell/trace-mapping@0.3.25':
- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ resolution:
+ { integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== }
'@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ resolution:
+ { integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== }
'@ledgerhq/cryptoassets-evm-signatures@13.5.9':
- resolution: {integrity: sha512-S3OMEb14GspNj7wnvHwHzuMUXJSfd+EcKhhlmboIZo7c7kj0ZhHONmEQK6Ad9eVEd/TryI8YG5HMTJ+D7mtSaA==}
+ resolution:
+ { integrity: sha512-S3OMEb14GspNj7wnvHwHzuMUXJSfd+EcKhhlmboIZo7c7kj0ZhHONmEQK6Ad9eVEd/TryI8YG5HMTJ+D7mtSaA== }
'@ledgerhq/devices@8.4.7':
- resolution: {integrity: sha512-CljHIaPmtv93H2If1Zs1xW0pgg+M37bAoJkm6+V6Yw5S0MgFWFpLnTTNgCvHXyD8pG0+uq8TuOXUiG1oAV5AyA==}
+ resolution:
+ { integrity: sha512-CljHIaPmtv93H2If1Zs1xW0pgg+M37bAoJkm6+V6Yw5S0MgFWFpLnTTNgCvHXyD8pG0+uq8TuOXUiG1oAV5AyA== }
'@ledgerhq/domain-service@1.2.35':
- resolution: {integrity: sha512-7CzwI08nFIuiXz24mAT9vp0o7n5Q8uez4DYNWMvC4thyBY0ZovE1XmqAYPS/t+SgDfzJyCapD03fkyxxw/sVrQ==}
+ resolution:
+ { integrity: sha512-7CzwI08nFIuiXz24mAT9vp0o7n5Q8uez4DYNWMvC4thyBY0ZovE1XmqAYPS/t+SgDfzJyCapD03fkyxxw/sVrQ== }
'@ledgerhq/errors@6.22.0':
- resolution: {integrity: sha512-rXtpIOfHL62jWB7o77PNFD4EDYdcqyMeVgt7TZcmTkWT78cK+YYSUTMrNuGLhnZZZTMLWH023Wgt65OfKIdGBQ==}
+ resolution:
+ { integrity: sha512-rXtpIOfHL62jWB7o77PNFD4EDYdcqyMeVgt7TZcmTkWT78cK+YYSUTMrNuGLhnZZZTMLWH023Wgt65OfKIdGBQ== }
'@ledgerhq/evm-tools@1.7.0':
- resolution: {integrity: sha512-aNmkwOJ+DQNSeVNRY1/vdglmJJIeynqNUI01kpnbSL7oLpF/S7Cvwscx0wkqTWeaH80GAuxBPkVTRxRL8W/SPw==}
+ resolution:
+ { integrity: sha512-aNmkwOJ+DQNSeVNRY1/vdglmJJIeynqNUI01kpnbSL7oLpF/S7Cvwscx0wkqTWeaH80GAuxBPkVTRxRL8W/SPw== }
'@ledgerhq/hw-app-eth@6.45.10':
- resolution: {integrity: sha512-9NAoYg1hnX0fvhRCwTfkllP86Et6NkEMVNwzdCJEULVJGvhnEK7j5dC+xHayzZeMs7fUZ8zj3zRCUWhHCDve5w==}
+ resolution:
+ { integrity: sha512-9NAoYg1hnX0fvhRCwTfkllP86Et6NkEMVNwzdCJEULVJGvhnEK7j5dC+xHayzZeMs7fUZ8zj3zRCUWhHCDve5w== }
'@ledgerhq/hw-app-solana@7.5.0':
- resolution: {integrity: sha512-Fk9sFpiOBpB0OuT3MkPCDqKdbbHB1Eh+uslOBkPWxzW6rwpO285X3NEcfrMYwEAdvqX9UUL7hUoH4zkHYBQ9wg==}
+ resolution:
+ { integrity: sha512-Fk9sFpiOBpB0OuT3MkPCDqKdbbHB1Eh+uslOBkPWxzW6rwpO285X3NEcfrMYwEAdvqX9UUL7hUoH4zkHYBQ9wg== }
'@ledgerhq/hw-transport-mocker@6.29.7':
- resolution: {integrity: sha512-0FEEbS9XRH/Fu8G4xIZq+QbRDnsy0tO3xf2H1wDkhVv0AGHvDHSp1l7fAQZz6Q1sBmLgqjXhKvZRKzNOX4tnfQ==}
+ resolution:
+ { integrity: sha512-0FEEbS9XRH/Fu8G4xIZq+QbRDnsy0tO3xf2H1wDkhVv0AGHvDHSp1l7fAQZz6Q1sBmLgqjXhKvZRKzNOX4tnfQ== }
'@ledgerhq/hw-transport-node-hid-noevents@6.30.8':
- resolution: {integrity: sha512-MwJOGLvfAvoSDG1ZHxrB/7squCIaAB8dhSAKN8LpjxeMhz/99SzXOr4MwSo0B/jytMkE0gBezVB3ADkPomkNkQ==}
+ resolution:
+ { integrity: sha512-MwJOGLvfAvoSDG1ZHxrB/7squCIaAB8dhSAKN8LpjxeMhz/99SzXOr4MwSo0B/jytMkE0gBezVB3ADkPomkNkQ== }
'@ledgerhq/hw-transport-node-hid-singleton@6.31.8':
- resolution: {integrity: sha512-Gx4mu7siqpbXscyIc22lycWpOGTG65KxVCvbG87xrFZYWaKE1YrbhNZ93hGa96qQPb9KOTN7sQPVsXmEAiahHQ==}
+ resolution:
+ { integrity: sha512-Gx4mu7siqpbXscyIc22lycWpOGTG65KxVCvbG87xrFZYWaKE1YrbhNZ93hGa96qQPb9KOTN7sQPVsXmEAiahHQ== }
'@ledgerhq/hw-transport-node-hid@6.29.8':
- resolution: {integrity: sha512-lQrhdu7JyxDL1DzDfvj9HDjQd9OHkYs5yDI13NH92qBTxuVneNfuu9DiHFLpCCpm2OUghTMmw9MRUwaTwYDTLg==}
+ resolution:
+ { integrity: sha512-lQrhdu7JyxDL1DzDfvj9HDjQd9OHkYs5yDI13NH92qBTxuVneNfuu9DiHFLpCCpm2OUghTMmw9MRUwaTwYDTLg== }
'@ledgerhq/hw-transport@6.31.7':
- resolution: {integrity: sha512-R+QMlqoLJDPeCiqwWv85PbZ3m0hel5PwQzWwSIbyEwialqjXnG7LFQgytkgXlgMcayT0chvvLeYjuY5ZfMPY7w==}
+ resolution:
+ { integrity: sha512-R+QMlqoLJDPeCiqwWv85PbZ3m0hel5PwQzWwSIbyEwialqjXnG7LFQgytkgXlgMcayT0chvvLeYjuY5ZfMPY7w== }
'@ledgerhq/live-env@2.11.0':
- resolution: {integrity: sha512-7xVQfi1IdifCS50LDX7qpEkrl8fa5s4MnETM7igJcmIeIE2qIGddBnjyToh/CIbJ1benBVZBY23iJmwul4/IhQ==}
+ resolution:
+ { integrity: sha512-7xVQfi1IdifCS50LDX7qpEkrl8fa5s4MnETM7igJcmIeIE2qIGddBnjyToh/CIbJ1benBVZBY23iJmwul4/IhQ== }
'@ledgerhq/logs@6.13.0':
- resolution: {integrity: sha512-4+qRW2Pc8V+btL0QEmdB2X+uyx0kOWMWE1/LWsq5sZy3Q5tpi4eItJS6mB0XL3wGW59RQ+8bchNQQ1OW/va8Og==}
+ resolution:
+ { integrity: sha512-4+qRW2Pc8V+btL0QEmdB2X+uyx0kOWMWE1/LWsq5sZy3Q5tpi4eItJS6mB0XL3wGW59RQ+8bchNQQ1OW/va8Og== }
'@ledgerhq/types-live@6.76.0':
- resolution: {integrity: sha512-XgshTvNSie5CkudV/ebLDAR7WVEqTDX/xiqg68NZbTr+exJE5t2C4fKEzCMq8wcGVjpbqLZA+RfL/uK/9j385A==}
+ resolution:
+ { integrity: sha512-XgshTvNSie5CkudV/ebLDAR7WVEqTDX/xiqg68NZbTr+exJE5t2C4fKEzCMq8wcGVjpbqLZA+RfL/uK/9j385A== }
'@lukeed/ms@2.0.2':
- resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA== }
+ engines: { node: '>=8' }
'@metaplex-foundation/beet-solana@0.1.1':
- resolution: {integrity: sha512-QV2DbxjaJWLkMvn12OC09g+r7a6R0uNwf8msYuOUSw4cG7amXzvFb7s0bh4IxY3Rk8/0ma0PfKi/FEdC7Hi4Pg==}
+ resolution:
+ { integrity: sha512-QV2DbxjaJWLkMvn12OC09g+r7a6R0uNwf8msYuOUSw4cG7amXzvFb7s0bh4IxY3Rk8/0ma0PfKi/FEdC7Hi4Pg== }
'@metaplex-foundation/beet-solana@0.3.1':
- resolution: {integrity: sha512-tgyEl6dvtLln8XX81JyBvWjIiEcjTkUwZbrM5dIobTmoqMuGewSyk9CClno8qsMsFdB5T3jC91Rjeqmu/6xk2g==}
+ resolution:
+ { integrity: sha512-tgyEl6dvtLln8XX81JyBvWjIiEcjTkUwZbrM5dIobTmoqMuGewSyk9CClno8qsMsFdB5T3jC91Rjeqmu/6xk2g== }
'@metaplex-foundation/beet-solana@0.4.1':
- resolution: {integrity: sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ==}
+ resolution:
+ { integrity: sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ== }
'@metaplex-foundation/beet@0.2.0':
- resolution: {integrity: sha512-H570hkJxmx/FxET1OggPPLkPL7psYQa71rNI9NJjYRM8WXdrEvmI/IRIEUW2KR6RqwWWN3FvlRHnKoQUV/lQtA==}
+ resolution:
+ { integrity: sha512-H570hkJxmx/FxET1OggPPLkPL7psYQa71rNI9NJjYRM8WXdrEvmI/IRIEUW2KR6RqwWWN3FvlRHnKoQUV/lQtA== }
'@metaplex-foundation/beet@0.4.0':
- resolution: {integrity: sha512-2OAKJnLatCc3mBXNL0QmWVQKAWK2C7XDfepgL0p/9+8oSx4bmRAFHFqptl1A/C0U5O3dxGwKfmKluW161OVGcA==}
+ resolution:
+ { integrity: sha512-2OAKJnLatCc3mBXNL0QmWVQKAWK2C7XDfepgL0p/9+8oSx4bmRAFHFqptl1A/C0U5O3dxGwKfmKluW161OVGcA== }
'@metaplex-foundation/beet@0.6.1':
- resolution: {integrity: sha512-OYgnijLFzw0cdUlRKH5POp0unQECPOW9muJ2X3QIVyak5G6I6l/rKo72sICgPLIFKdmsi2jmnkuLY7wp14iXdw==}
+ resolution:
+ { integrity: sha512-OYgnijLFzw0cdUlRKH5POp0unQECPOW9muJ2X3QIVyak5G6I6l/rKo72sICgPLIFKdmsi2jmnkuLY7wp14iXdw== }
'@metaplex-foundation/beet@0.7.2':
- resolution: {integrity: sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==}
+ resolution:
+ { integrity: sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg== }
'@metaplex-foundation/cusper@0.0.2':
- resolution: {integrity: sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==}
+ resolution:
+ { integrity: sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA== }
'@metaplex-foundation/js@0.11.7':
- resolution: {integrity: sha512-zL3Ac++8lUOoKjjhDArdNSimvVYcOqg4uhxfBVRKLV6H8q6E/sOepXuzYSLXxzYWdvapYWEPKFdEDFluYzk7DA==}
- engines: {node: ^14.0 || >=16.0}
+ resolution:
+ { integrity: sha512-zL3Ac++8lUOoKjjhDArdNSimvVYcOqg4uhxfBVRKLV6H8q6E/sOepXuzYSLXxzYWdvapYWEPKFdEDFluYzk7DA== }
+ engines: { node: ^14.0 || >=16.0 }
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
'@metaplex-foundation/mpl-auction-house@2.5.1':
- resolution: {integrity: sha512-O+IAdYVaoOvgACB8pm+1lF5BNEjl0COkqny2Ho8KQZwka6aC/vHbZ239yRwAMtJhf5992BPFdT4oifjyE0O+Mw==}
+ resolution:
+ { integrity: sha512-O+IAdYVaoOvgACB8pm+1lF5BNEjl0COkqny2Ho8KQZwka6aC/vHbZ239yRwAMtJhf5992BPFdT4oifjyE0O+Mw== }
'@metaplex-foundation/mpl-candy-machine@4.7.1':
- resolution: {integrity: sha512-tBNRAfBE/rYy9pe2aJD4gTFw+pgQ11o3AJjoYGB4+05ow0VjJMSt6kQGzHm2LRPgdLY4diKAq8qHvgsbV5ikNQ==}
+ resolution:
+ { integrity: sha512-tBNRAfBE/rYy9pe2aJD4gTFw+pgQ11o3AJjoYGB4+05ow0VjJMSt6kQGzHm2LRPgdLY4diKAq8qHvgsbV5ikNQ== }
'@metaplex-foundation/mpl-core@0.6.1':
- resolution: {integrity: sha512-6R4HkfAqU2EUakNbVLcCmka0YuQTLGTbHJ62ig765+NRWuB2HNGUQ1HfHcRsGnyxhlCvwKK79JE01XUjFE+dzw==}
+ resolution:
+ { integrity: sha512-6R4HkfAqU2EUakNbVLcCmka0YuQTLGTbHJ62ig765+NRWuB2HNGUQ1HfHcRsGnyxhlCvwKK79JE01XUjFE+dzw== }
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
'@metaplex-foundation/mpl-token-metadata@2.13.0':
- resolution: {integrity: sha512-Fl/8I0L9rv4bKTV/RAl5YIbJe9SnQPInKvLz+xR1fEc4/VQkuCn3RPgypfUMEKWmCznzaw4sApDxy6CFS4qmJw==}
+ resolution:
+ { integrity: sha512-Fl/8I0L9rv4bKTV/RAl5YIbJe9SnQPInKvLz+xR1fEc4/VQkuCn3RPgypfUMEKWmCznzaw4sApDxy6CFS4qmJw== }
'@meteora-ag/cp-amm-sdk@1.4.5':
- resolution: {integrity: sha512-Uw1tj0llVf61FUkkx3aRcT868d/2fiBK+7GpP/rH3yZaDC15JBmjtCpx6ghS8jA2ZM4qvMb1cnmF3hLH9C3wAA==}
+ resolution:
+ { integrity: sha512-Uw1tj0llVf61FUkkx3aRcT868d/2fiBK+7GpP/rH3yZaDC15JBmjtCpx6ghS8jA2ZM4qvMb1cnmF3hLH9C3wAA== }
'@meteora-ag/dlmm@1.7.5':
- resolution: {integrity: sha512-cXfEvAaInhuBwz4pKcMaJHMWbysEEApMTeYnL4kMD38e6YyOht6hfJme2cjaWXct5jAbVvA0AEoFZdjcC/nQhA==}
+ resolution:
+ { integrity: sha512-cXfEvAaInhuBwz4pKcMaJHMWbysEEApMTeYnL4kMD38e6YyOht6hfJme2cjaWXct5jAbVvA0AEoFZdjcC/nQhA== }
'@napi-rs/wasm-runtime@0.2.11':
- resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==}
+ resolution:
+ { integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA== }
'@noble/ciphers@1.3.0':
- resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/curves@1.4.2':
- resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==}
+ resolution:
+ { integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== }
'@noble/curves@1.8.2':
- resolution: {integrity: sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/curves@1.9.0':
- resolution: {integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/curves@1.9.1':
- resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/curves@1.9.2':
- resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/ed25519@1.7.5':
- resolution: {integrity: sha512-xuS0nwRMQBvSxDa7UxMb61xTiH3MxTgUfhyPUALVIe0FlOAz4sjELwyDRyUvqeEYfRSG9qNjFIycqLZppg4RSA==}
+ resolution:
+ { integrity: sha512-xuS0nwRMQBvSxDa7UxMb61xTiH3MxTgUfhyPUALVIe0FlOAz4sjELwyDRyUvqeEYfRSG9qNjFIycqLZppg4RSA== }
'@noble/hashes@1.2.0':
- resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==}
+ resolution:
+ { integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== }
'@noble/hashes@1.4.0':
- resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
- engines: {node: '>= 16'}
+ resolution:
+ { integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== }
+ engines: { node: '>= 16' }
'@noble/hashes@1.7.2':
- resolution: {integrity: sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/hashes@1.8.0':
- resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
- engines: {node: ^14.21.3 || >=16}
+ resolution:
+ { integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== }
+ engines: { node: ^14.21.3 || >=16 }
'@noble/secp256k1@1.7.1':
- resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==}
+ resolution:
+ { integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== }
'@nodelib/fs.scandir@2.1.5':
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== }
+ engines: { node: '>= 8' }
'@nodelib/fs.stat@2.0.5':
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== }
+ engines: { node: '>= 8' }
'@nodelib/fs.walk@1.2.8':
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== }
+ engines: { node: '>= 8' }
'@nomicfoundation/edr-darwin-arm64@0.11.0':
- resolution: {integrity: sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-aYTVdcSs27XG7ayTzvZ4Yn9z/ABSaUwicrtrYK2NR8IH0ik4N4bWzo/qH8rax6rewVLbHUkGyGYnsy5ZN4iiMw== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-darwin-x64@0.11.0':
- resolution: {integrity: sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-RxX7UYgvJrfcyT/uHUn44Nsy1XaoW+Q1khKMdHKxeW7BrgIi+Lz+siz3bX5vhSoAnKilDPhIVLrnC8zxQhjR2A== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-linux-arm64-gnu@0.11.0':
- resolution: {integrity: sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-J0j+rs0s11FuSipt/ymqrFmpJ7c0FSz1/+FohCIlUXDxFv//+1R/8lkGPjEYFmy8DPpk/iO8mcpqHTGckREbqA== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-linux-arm64-musl@0.11.0':
- resolution: {integrity: sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-4r32zkGMN7WT/CMEuW0VjbuEdIeCskHNDMW4SSgQSJOE/N9L1KSLJCSsAbPD3aYE+e4WRDTyOwmuLjeUTcLZKQ== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-linux-x64-gnu@0.11.0':
- resolution: {integrity: sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-SmdncQHLYtVNWLIMyGaY6LpAfamzTDe3fxjkirmJv3CWR5tcEyC6LMui/GsIVnJzXeNJBXAzwl8hTUAxHTM6kQ== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-linux-x64-musl@0.11.0':
- resolution: {integrity: sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-w6hUqpn/trwiH6SRuRGysj37LsQVCX5XDCA3Xi81sbOaLhbHrNvK9TXWyZmcuzbdTKQQW6VNywcSxDdOiChcJg== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr-win32-x64-msvc@0.11.0':
- resolution: {integrity: sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-BLmULjRKoH9BsX+c4Na2ypV7NGeJ+M6Zpqj/faPOwleVscDdSr/IhriyPaXCe8dyfwbge7lWsbekiADtPSnB2Q== }
+ engines: { node: '>= 18' }
'@nomicfoundation/edr@0.11.0':
- resolution: {integrity: sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw==}
- engines: {node: '>= 18'}
+ resolution:
+ { integrity: sha512-36WERf8ldvyHR6UAbcYsa+vpbW7tCrJGBwF4gXSsb8+STj1n66Hz85Y/O7B9+8AauX3PhglvV5dKl91tk43mWw== }
+ engines: { node: '>= 18' }
'@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2':
- resolution: {integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2':
- resolution: {integrity: sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2':
- resolution: {integrity: sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2':
- resolution: {integrity: sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2':
- resolution: {integrity: sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2':
- resolution: {integrity: sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2':
- resolution: {integrity: sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA== }
+ engines: { node: '>= 12' }
'@nomicfoundation/solidity-analyzer@0.1.2':
- resolution: {integrity: sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA== }
+ engines: { node: '>= 12' }
'@openzeppelin/contracts-upgradeable@3.4.2-solc-0.7':
- resolution: {integrity: sha512-I5iKKS8U9L1XdSxsNAIBQekN0U9hTgdleoyntIdR7Jy3U/z/NZ/1oUM0v5HnUMrmn/bXLvYL94rBvaLF++Ndnw==}
+ resolution:
+ { integrity: sha512-I5iKKS8U9L1XdSxsNAIBQekN0U9hTgdleoyntIdR7Jy3U/z/NZ/1oUM0v5HnUMrmn/bXLvYL94rBvaLF++Ndnw== }
'@openzeppelin/contracts@4.9.6':
- resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==}
+ resolution:
+ { integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA== }
'@orca-so/common-sdk@0.6.11':
- resolution: {integrity: sha512-7MJs71F8XJsYCx3+agsLc3MMGnzAC8l3FDbUq0qP3lEPI6B5IS/u2iKU4rWkK3IqIkynWcvuYL6WCi+90vu52w==}
+ resolution:
+ { integrity: sha512-7MJs71F8XJsYCx3+agsLc3MMGnzAC8l3FDbUq0qP3lEPI6B5IS/u2iKU4rWkK3IqIkynWcvuYL6WCi+90vu52w== }
peerDependencies:
'@solana/spl-token': ^0.4.12
'@solana/web3.js': ^1.90.0
'@orca-so/tx-sender@3.0.1':
- resolution: {integrity: sha512-WuH9ACW4iIZgeF8cmFZxlQkI0pI9W/2VRt0k2AsPUp96scNqDTJFYsyAnvXxOXCloVr7sunU4MSMCTm6d/jTew==}
+ resolution:
+ { integrity: sha512-WuH9ACW4iIZgeF8cmFZxlQkI0pI9W/2VRt0k2AsPUp96scNqDTJFYsyAnvXxOXCloVr7sunU4MSMCTm6d/jTew== }
peerDependencies:
'@solana/kit': ^5.0.0
'@orca-so/whirlpools-client@7.0.0':
- resolution: {integrity: sha512-bpWG+cXe2VqLaH9wBvtsZKdnaH0iWO/dmGCgdrntxOarsS28FTF4fh5ahZnf9gYP8DiwN/8DrOKiXWO4Jn49/A==}
+ resolution:
+ { integrity: sha512-bpWG+cXe2VqLaH9wBvtsZKdnaH0iWO/dmGCgdrntxOarsS28FTF4fh5ahZnf9gYP8DiwN/8DrOKiXWO4Jn49/A== }
peerDependencies:
'@solana/kit': ^5.0.0
'@orca-so/whirlpools-core@3.1.0':
- resolution: {integrity: sha512-PuP5II56ZHkjjVaE6C7lgQR4x+9HtyvEzUWw2hpHW+Be80MerEjqEuBpUXECTgiG+pPCp1RBzmN/1LbyAT8uAw==}
+ resolution:
+ { integrity: sha512-PuP5II56ZHkjjVaE6C7lgQR4x+9HtyvEzUWw2hpHW+Be80MerEjqEuBpUXECTgiG+pPCp1RBzmN/1LbyAT8uAw== }
'@orca-so/whirlpools-core@3.1.1':
- resolution: {integrity: sha512-pZqemzQrtLW214yTpc117SNGMk3KIxVw9i77DT5235TUj+v+MkX0EZcriAkDfAeVMr0Il6XKS9hTz8ynZ8lXcA==}
+ resolution:
+ { integrity: sha512-pZqemzQrtLW214yTpc117SNGMk3KIxVw9i77DT5235TUj+v+MkX0EZcriAkDfAeVMr0Il6XKS9hTz8ynZ8lXcA== }
'@orca-so/whirlpools@8.0.1':
- resolution: {integrity: sha512-4R+BhxZWRL1nVAuV0rz6MI8w+8HiUuv5PUQzEmvyy/Cj8mgfZUJxU4DvNA8E9IM3zpZRQM/sDR9Tc0jbjQvlFQ==}
+ resolution:
+ { integrity: sha512-4R+BhxZWRL1nVAuV0rz6MI8w+8HiUuv5PUQzEmvyy/Cj8mgfZUJxU4DvNA8E9IM3zpZRQM/sDR9Tc0jbjQvlFQ== }
peerDependencies:
'@solana/kit': ^5.0.0
'@pancakeswap/chains@0.5.1':
- resolution: {integrity: sha512-wIYRrC7iQfd/ILe4/SJ6nQ+GZmHcy3ylKYH8O8Thfd1WmbJ9G4qnQkL0wJBmA2NUkMO/qceWQAthr2BCosl/ZA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-wIYRrC7iQfd/ILe4/SJ6nQ+GZmHcy3ylKYH8O8Thfd1WmbJ9G4qnQkL0wJBmA2NUkMO/qceWQAthr2BCosl/ZA== }
+ engines: { node: '>=10' }
'@pancakeswap/chains@0.6.0':
- resolution: {integrity: sha512-deg+CtkP8ZzCQ4W9XnTUm89jtzkhmg8FPczwStqpysL0HSFWqHsCh+tsZRHskfVPS8AqnlSA7uo1Z7nv9KrOMA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-deg+CtkP8ZzCQ4W9XnTUm89jtzkhmg8FPczwStqpysL0HSFWqHsCh+tsZRHskfVPS8AqnlSA7uo1Z7nv9KrOMA== }
+ engines: { node: '>=10' }
'@pancakeswap/infinity-sdk@1.0.5':
- resolution: {integrity: sha512-NPoYyiJIzPu+HAv0qp5UBWKRLIqEejSRD1TVicB9ylJsamUMW8Q8m+LFqX6lVxX/ykI/7sOX5RdhU+dhLOQsTQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-NPoYyiJIzPu+HAv0qp5UBWKRLIqEejSRD1TVicB9ylJsamUMW8Q8m+LFqX6lVxX/ykI/7sOX5RdhU+dhLOQsTQ== }
+ engines: { node: '>=10' }
'@pancakeswap/multicall@3.7.2':
- resolution: {integrity: sha512-HE64KWfdZwsgB8ZFnZakdFuqBCQullfjm/wxLHjRnWW9hQnEcxZES2ZQ9pW1loIeZ4BC6AV+YfDJ/xxXzb+Lrw==}
+ resolution:
+ { integrity: sha512-HE64KWfdZwsgB8ZFnZakdFuqBCQullfjm/wxLHjRnWW9hQnEcxZES2ZQ9pW1loIeZ4BC6AV+YfDJ/xxXzb+Lrw== }
'@pancakeswap/permit2-sdk@1.1.5':
- resolution: {integrity: sha512-23mlRyaR2OP3u9rQn3gSZA4NNlqgRR6AnHhG8etYyKzGfFz8joJP1JcRxfRkWJqtLSjUPB0o3oMWNNzsSRT26Q==}
+ resolution:
+ { integrity: sha512-23mlRyaR2OP3u9rQn3gSZA4NNlqgRR6AnHhG8etYyKzGfFz8joJP1JcRxfRkWJqtLSjUPB0o3oMWNNzsSRT26Q== }
'@pancakeswap/sdk@5.8.12':
- resolution: {integrity: sha512-eubv5+9ilGIXRB1C4AwCwcnDQU/JzlXBGmJq+JxFRSfh8+XMtuLf+KZyWN5i0M0WK3z+hP/Xwo69j+6vRfJJuA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-eubv5+9ilGIXRB1C4AwCwcnDQU/JzlXBGmJq+JxFRSfh8+XMtuLf+KZyWN5i0M0WK3z+hP/Xwo69j+6vRfJJuA== }
+ engines: { node: '>=10' }
'@pancakeswap/sdk@5.8.16':
- resolution: {integrity: sha512-vv6fOZM8jZlcdS7M8kLSs7eP3jDYKZ6w/OjjfuQPEE2+1SVN6LFZzkuXzkNGtKAYgf6N7lUzFBPyStaXEUynsw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-vv6fOZM8jZlcdS7M8kLSs7eP3jDYKZ6w/OjjfuQPEE2+1SVN6LFZzkuXzkNGtKAYgf6N7lUzFBPyStaXEUynsw== }
+ engines: { node: '>=10' }
'@pancakeswap/smart-router@7.5.2':
- resolution: {integrity: sha512-2aROSXQJWoOfrib/mUkM9FnOjl+oihhrXe9XpHcjYEOtzEIYAf5C34CTUxgUpflplaHNVkCHxJ+mbaP0xs7ALQ==}
+ resolution:
+ { integrity: sha512-2aROSXQJWoOfrib/mUkM9FnOjl+oihhrXe9XpHcjYEOtzEIYAf5C34CTUxgUpflplaHNVkCHxJ+mbaP0xs7ALQ== }
'@pancakeswap/stable-swap-sdk@2.0.9':
- resolution: {integrity: sha512-51EGjmaefA/c2NnCz2yAzy2DHtWfVwy1t0XQrDj79RM4+NtjuMe9lyaJZozcl+J/rQPB1Cb5p9+8IiX52J+7mg==}
+ resolution:
+ { integrity: sha512-51EGjmaefA/c2NnCz2yAzy2DHtWfVwy1t0XQrDj79RM4+NtjuMe9lyaJZozcl+J/rQPB1Cb5p9+8IiX52J+7mg== }
'@pancakeswap/swap-sdk-core@1.3.0':
- resolution: {integrity: sha512-nkeDs3GyNfvRGsTbTAO30yl6ccOTr5WQERsKAaxKTe1fbGvpDRFLo3nlR1ZddRCj+RYZSS+B4Sll4A39k7nFDQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-nkeDs3GyNfvRGsTbTAO30yl6ccOTr5WQERsKAaxKTe1fbGvpDRFLo3nlR1ZddRCj+RYZSS+B4Sll4A39k7nFDQ== }
+ engines: { node: '>=10' }
'@pancakeswap/swap-sdk-core@1.5.0':
- resolution: {integrity: sha512-XedyPJ7DCuxcSSTPg7kX0E5UVELWoqQSri4Gv78qWT9fQ590ikF3tFlNF7fcc4yo/TSRzwXgC9WqYjeFJ8lKwA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-XedyPJ7DCuxcSSTPg7kX0E5UVELWoqQSri4Gv78qWT9fQ590ikF3tFlNF7fcc4yo/TSRzwXgC9WqYjeFJ8lKwA== }
+ engines: { node: '>=10' }
'@pancakeswap/swap-sdk-evm@1.1.1':
- resolution: {integrity: sha512-z5nDhNf9NzbZFElq8pC2MPzWrI5WDT9mVQ1NkWDOh1wqJijv4+jCTBCoOi9cLsBGBkoMJ/yZYZ2YlxBcSwVjAQ==}
+ resolution:
+ { integrity: sha512-z5nDhNf9NzbZFElq8pC2MPzWrI5WDT9mVQ1NkWDOh1wqJijv4+jCTBCoOi9cLsBGBkoMJ/yZYZ2YlxBcSwVjAQ== }
'@pancakeswap/swap-sdk-evm@1.1.5':
- resolution: {integrity: sha512-ZQaz86yELhtar9+8HfYrt9L+IWFJXU/viKj6JiDJZhZ8zDBErxrzHYswFMvmX9bsnmgoLpWpcallIEwqDmMbJw==}
+ resolution:
+ { integrity: sha512-ZQaz86yELhtar9+8HfYrt9L+IWFJXU/viKj6JiDJZhZ8zDBErxrzHYswFMvmX9bsnmgoLpWpcallIEwqDmMbJw== }
'@pancakeswap/swap-sdk-solana@1.1.4':
- resolution: {integrity: sha512-xLArIRzx5CwHuXHlvu/RyImpKyB3V3mXsb4chybfKyAXhYjiD9OOXIzLLXzpdkJFa8VQ0kRIMtUrFYA5i42g7A==}
+ resolution:
+ { integrity: sha512-xLArIRzx5CwHuXHlvu/RyImpKyB3V3mXsb4chybfKyAXhYjiD9OOXIzLLXzpdkJFa8VQ0kRIMtUrFYA5i42g7A== }
'@pancakeswap/token-lists@0.0.16':
- resolution: {integrity: sha512-Mf/Y7wm7HdHMBeOKrRcIbGBDjt3/xlerAolRXaRDAYtHbyn7sE8Q/azq9XhAR2OFIc5qJuLejlXFrWxnQFr9tw==}
+ resolution:
+ { integrity: sha512-Mf/Y7wm7HdHMBeOKrRcIbGBDjt3/xlerAolRXaRDAYtHbyn7sE8Q/azq9XhAR2OFIc5qJuLejlXFrWxnQFr9tw== }
peerDependencies:
'@reduxjs/toolkit': ^1.9.1
jotai: 2.12.5
@@ -1569,10 +1860,12 @@ packages:
optional: true
'@pancakeswap/tokens@0.7.8':
- resolution: {integrity: sha512-nOyWG1SSfx8Hk/P+iJkj/NU4pvz+gpRJ6V6l+CM6WsgjFrTdQKDm3yUrzeurwZspJfwwEvWep0mYGxDj85zXdA==}
+ resolution:
+ { integrity: sha512-nOyWG1SSfx8Hk/P+iJkj/NU4pvz+gpRJ6V6l+CM6WsgjFrTdQKDm3yUrzeurwZspJfwwEvWep0mYGxDj85zXdA== }
'@pancakeswap/universal-router-sdk@1.4.14':
- resolution: {integrity: sha512-NIjzWG0UXngXMOUPyT4KDcnrEtnuFoQc5H+6eTg1Af0WMEgnkrN4HRBrZECfGSb+vCg9aak0kPv5MQpXjRuLkg==}
+ resolution:
+ { integrity: sha512-NIjzWG0UXngXMOUPyT4KDcnrEtnuFoQc5H+6eTg1Af0WMEgnkrN4HRBrZECfGSb+vCg9aak0kPv5MQpXjRuLkg== }
peerDependencies:
abitype: '*'
lodash: '*'
@@ -1580,376 +1873,472 @@ packages:
viem: 2.31.3
'@pancakeswap/v2-sdk@1.1.1':
- resolution: {integrity: sha512-FlPEk9Jpq3YcLZ7DEkDXqx5g57+Vxk3sJAB2aSU2UypO3fKGwB/yt/zaeFT8mLzd9p6IlBJ912Mxo1nGRhENlA==}
+ resolution:
+ { integrity: sha512-FlPEk9Jpq3YcLZ7DEkDXqx5g57+Vxk3sJAB2aSU2UypO3fKGwB/yt/zaeFT8mLzd9p6IlBJ912Mxo1nGRhENlA== }
'@pancakeswap/v2-sdk@1.1.5':
- resolution: {integrity: sha512-IaO+r5pOxx4TyGZc+mUyZI76koeXzk7UU5MQtyMYPlngCoAIP8E5YqrUaEvuSYiFaJqSjawyenT4vHe9HmnJoQ==}
+ resolution:
+ { integrity: sha512-IaO+r5pOxx4TyGZc+mUyZI76koeXzk7UU5MQtyMYPlngCoAIP8E5YqrUaEvuSYiFaJqSjawyenT4vHe9HmnJoQ== }
'@pancakeswap/v3-core@1.0.2':
- resolution: {integrity: sha512-9aZU8I1J6SbZOSW7NcNxuyaAC17tGkOaZJM9aJgvl6MMUOExpq0i0EC/jc3HxWbpC8sbZL+8eG544NEJs8CS+w==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-9aZU8I1J6SbZOSW7NcNxuyaAC17tGkOaZJM9aJgvl6MMUOExpq0i0EC/jc3HxWbpC8sbZL+8eG544NEJs8CS+w== }
+ engines: { node: '>=10' }
'@pancakeswap/v3-periphery@1.0.2':
- resolution: {integrity: sha512-kWQhJsAG5Ij1cubKlX0JuJ3GEPFiPBR+NQt77SxHNjk62eallLyfbWJYk2NMnTO0crbjBFO5GKKQAXfp2n76vg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-kWQhJsAG5Ij1cubKlX0JuJ3GEPFiPBR+NQt77SxHNjk62eallLyfbWJYk2NMnTO0crbjBFO5GKKQAXfp2n76vg== }
+ engines: { node: '>=10' }
'@pancakeswap/v3-sdk@3.9.1':
- resolution: {integrity: sha512-rOTLn2kdB8RmkThU36TDX/QSpkVBRNyW17qOYNwhHgjdrKXah4iJZZu4dJzwN/1IywjpQ1UIcmI57WWQL5Nj3A==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-rOTLn2kdB8RmkThU36TDX/QSpkVBRNyW17qOYNwhHgjdrKXah4iJZZu4dJzwN/1IywjpQ1UIcmI57WWQL5Nj3A== }
+ engines: { node: '>=10' }
'@pancakeswap/v3-sdk@3.9.5':
- resolution: {integrity: sha512-rqtDADhS17mplAnr8VyTxOYGiL4SEw1g7NZdRMFwcvxH5wzskSzNEfg4cFsLWb+mD3FyX8BXXWrvADLsQqP2mg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-rqtDADhS17mplAnr8VyTxOYGiL4SEw1g7NZdRMFwcvxH5wzskSzNEfg4cFsLWb+mD3FyX8BXXWrvADLsQqP2mg== }
+ engines: { node: '>=10' }
'@pancakeswap/v4-sdk@0.1.8':
- resolution: {integrity: sha512-5n5cmtBMYo7bnhmxhuwfv4P/MSaeZbvNsqsUjl6UsNnI9ylPx4ttTvj/uxhytnjpSA2wwSZUvwLys/w3rHrWGw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-5n5cmtBMYo7bnhmxhuwfv4P/MSaeZbvNsqsUjl6UsNnI9ylPx4ttTvj/uxhytnjpSA2wwSZUvwLys/w3rHrWGw== }
+ engines: { node: '>=10' }
'@pkgjs/parseargs@0.11.0':
- resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== }
+ engines: { node: '>=14' }
'@pkgr/core@0.2.4':
- resolution: {integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==}
- engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== }
+ engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
'@randlabs/communication-bridge@1.0.1':
- resolution: {integrity: sha512-CzS0U8IFfXNK7QaJFE4pjbxDGfPjbXBEsEaCn9FN15F+ouSAEUQkva3Gl66hrkBZOGexKFEWMwUHIDKpZ2hfVg==}
+ resolution:
+ { integrity: sha512-CzS0U8IFfXNK7QaJFE4pjbxDGfPjbXBEsEaCn9FN15F+ouSAEUQkva3Gl66hrkBZOGexKFEWMwUHIDKpZ2hfVg== }
'@randlabs/myalgo-connect@1.4.2':
- resolution: {integrity: sha512-K9hEyUi7G8tqOp7kWIALJLVbGCByhilcy6123WfcorxWwiE1sbQupPyIU5f3YdQK6wMjBsyTWiLW52ZBMp7sXA==}
+ resolution:
+ { integrity: sha512-K9hEyUi7G8tqOp7kWIALJLVbGCByhilcy6123WfcorxWwiE1sbQupPyIU5f3YdQK6wMjBsyTWiLW52ZBMp7sXA== }
'@raydium-io/raydium-sdk-v2@0.1.141-alpha':
- resolution: {integrity: sha512-mBg+IWzAO19debQH6LnGOF8Ywy0l+W/J6tviFvywGYLJ6pw72Qe8quojtY48qxocqboAd3dv+Bbi3DVyyF+bzg==}
+ resolution:
+ { integrity: sha512-mBg+IWzAO19debQH6LnGOF8Ywy0l+W/J6tviFvywGYLJ6pw72Qe8quojtY48qxocqboAd3dv+Bbi3DVyyF+bzg== }
'@rtsao/scc@1.1.0':
- resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
+ resolution:
+ { integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== }
'@scure/base@1.1.9':
- resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==}
+ resolution:
+ { integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== }
'@scure/base@1.2.5':
- resolution: {integrity: sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==}
+ resolution:
+ { integrity: sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw== }
'@scure/bip32@1.1.5':
- resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==}
+ resolution:
+ { integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== }
'@scure/bip32@1.4.0':
- resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==}
+ resolution:
+ { integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== }
'@scure/bip32@1.7.0':
- resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==}
+ resolution:
+ { integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== }
'@scure/bip39@1.1.1':
- resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==}
+ resolution:
+ { integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== }
'@scure/bip39@1.3.0':
- resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==}
+ resolution:
+ { integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== }
'@scure/bip39@1.6.0':
- resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==}
+ resolution:
+ { integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== }
'@sentry/core@5.30.0':
- resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== }
+ engines: { node: '>=6' }
'@sentry/hub@5.30.0':
- resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== }
+ engines: { node: '>=6' }
'@sentry/minimal@5.30.0':
- resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== }
+ engines: { node: '>=6' }
'@sentry/node@5.30.0':
- resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== }
+ engines: { node: '>=6' }
'@sentry/tracing@5.30.0':
- resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== }
+ engines: { node: '>=6' }
'@sentry/types@5.30.0':
- resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== }
+ engines: { node: '>=6' }
'@sentry/utils@5.30.0':
- resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== }
+ engines: { node: '>=6' }
'@sideway/address@4.1.5':
- resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
+ resolution:
+ { integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== }
'@sideway/formula@3.0.1':
- resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
+ resolution:
+ { integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== }
'@sideway/pinpoint@2.0.0':
- resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
+ resolution:
+ { integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== }
'@sinclair/typebox@0.27.8':
- resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+ resolution:
+ { integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== }
'@sinclair/typebox@0.33.22':
- resolution: {integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==}
+ resolution:
+ { integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ== }
'@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+ resolution:
+ { integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== }
'@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+ resolution:
+ { integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== }
'@smithy/abort-controller@4.0.2':
- resolution: {integrity: sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw== }
+ engines: { node: '>=18.0.0' }
'@smithy/chunked-blob-reader-native@4.0.0':
- resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig== }
+ engines: { node: '>=18.0.0' }
'@smithy/chunked-blob-reader@5.0.0':
- resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw== }
+ engines: { node: '>=18.0.0' }
'@smithy/config-resolver@4.1.1':
- resolution: {integrity: sha512-FZUtpiDnPZQmuIl4lfbdO+u3foNLmRCKct/2w2nRwgB99Yvaq4SHcfxyzMfxkyBrBmgnF1kdXzhHNXN7ycDvWg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-FZUtpiDnPZQmuIl4lfbdO+u3foNLmRCKct/2w2nRwgB99Yvaq4SHcfxyzMfxkyBrBmgnF1kdXzhHNXN7ycDvWg== }
+ engines: { node: '>=18.0.0' }
'@smithy/core@3.3.1':
- resolution: {integrity: sha512-W7AppgQD3fP1aBmo8wWo0id5zeR2/aYRy067vZsDVaa6v/mdhkg6DxXwEVuSPjZl+ZnvWAQbUMCd5ckw38+tHQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-W7AppgQD3fP1aBmo8wWo0id5zeR2/aYRy067vZsDVaa6v/mdhkg6DxXwEVuSPjZl+ZnvWAQbUMCd5ckw38+tHQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/credential-provider-imds@4.0.3':
- resolution: {integrity: sha512-UdNvGjZnunS9+45gHYtVXDynoWH1X0tYY0pS368k1zUZum6Mm4ivU4Se0WhFJf8jNocD+p94khzTtrx4ha3OOQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-UdNvGjZnunS9+45gHYtVXDynoWH1X0tYY0pS368k1zUZum6Mm4ivU4Se0WhFJf8jNocD+p94khzTtrx4ha3OOQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/eventstream-codec@4.0.2':
- resolution: {integrity: sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/eventstream-serde-browser@4.0.2':
- resolution: {integrity: sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug== }
+ engines: { node: '>=18.0.0' }
'@smithy/eventstream-serde-config-resolver@4.1.0':
- resolution: {integrity: sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A== }
+ engines: { node: '>=18.0.0' }
'@smithy/eventstream-serde-node@4.0.2':
- resolution: {integrity: sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw== }
+ engines: { node: '>=18.0.0' }
'@smithy/eventstream-serde-universal@4.0.2':
- resolution: {integrity: sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng== }
+ engines: { node: '>=18.0.0' }
'@smithy/fetch-http-handler@5.0.2':
- resolution: {integrity: sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/hash-blob-browser@4.0.2':
- resolution: {integrity: sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g== }
+ engines: { node: '>=18.0.0' }
'@smithy/hash-node@4.0.2':
- resolution: {integrity: sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg== }
+ engines: { node: '>=18.0.0' }
'@smithy/hash-stream-node@4.0.2':
- resolution: {integrity: sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg== }
+ engines: { node: '>=18.0.0' }
'@smithy/invalid-dependency@4.0.2':
- resolution: {integrity: sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/is-array-buffer@2.2.0':
- resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== }
+ engines: { node: '>=14.0.0' }
'@smithy/is-array-buffer@4.0.0':
- resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw== }
+ engines: { node: '>=18.0.0' }
'@smithy/md5-js@4.0.2':
- resolution: {integrity: sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA== }
+ engines: { node: '>=18.0.0' }
'@smithy/middleware-content-length@4.0.2':
- resolution: {integrity: sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A== }
+ engines: { node: '>=18.0.0' }
'@smithy/middleware-endpoint@4.1.3':
- resolution: {integrity: sha512-w7fJjCSqdTVTs1o1O7SRZm+Umf6r/FzkdlO5OH6tboASeUeugnMgQAs7gnc2dXvJVJtEGrmrBgPZFPxq3wWyzw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-w7fJjCSqdTVTs1o1O7SRZm+Umf6r/FzkdlO5OH6tboASeUeugnMgQAs7gnc2dXvJVJtEGrmrBgPZFPxq3wWyzw== }
+ engines: { node: '>=18.0.0' }
'@smithy/middleware-retry@4.1.4':
- resolution: {integrity: sha512-QtWuD7bd7AAEFKvBmLQdOax25bXv4BACLQNWi3ddvpWwUUSAkAku9mzI+28jbjg48qw28lbzJ+YoYbbaXhLUjw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-QtWuD7bd7AAEFKvBmLQdOax25bXv4BACLQNWi3ddvpWwUUSAkAku9mzI+28jbjg48qw28lbzJ+YoYbbaXhLUjw== }
+ engines: { node: '>=18.0.0' }
'@smithy/middleware-serde@4.0.3':
- resolution: {integrity: sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A== }
+ engines: { node: '>=18.0.0' }
'@smithy/middleware-stack@4.0.2':
- resolution: {integrity: sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/node-config-provider@4.1.0':
- resolution: {integrity: sha512-gmPsv6L3ZRlBinv+vtSGUwfhTMh4+SgjbgGdX7bqYEs3Ys5RYVQtLuZ/WgZZdxn8QrDSUqLmTWunLM96WyM7UQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-gmPsv6L3ZRlBinv+vtSGUwfhTMh4+SgjbgGdX7bqYEs3Ys5RYVQtLuZ/WgZZdxn8QrDSUqLmTWunLM96WyM7UQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/node-http-handler@4.0.4':
- resolution: {integrity: sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g== }
+ engines: { node: '>=18.0.0' }
'@smithy/property-provider@4.0.2':
- resolution: {integrity: sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A== }
+ engines: { node: '>=18.0.0' }
'@smithy/protocol-http@5.1.0':
- resolution: {integrity: sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g== }
+ engines: { node: '>=18.0.0' }
'@smithy/querystring-builder@4.0.2':
- resolution: {integrity: sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q== }
+ engines: { node: '>=18.0.0' }
'@smithy/querystring-parser@4.0.2':
- resolution: {integrity: sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q== }
+ engines: { node: '>=18.0.0' }
'@smithy/service-error-classification@4.0.3':
- resolution: {integrity: sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q== }
+ engines: { node: '>=18.0.0' }
'@smithy/shared-ini-file-loader@4.0.2':
- resolution: {integrity: sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw== }
+ engines: { node: '>=18.0.0' }
'@smithy/signature-v4@5.1.0':
- resolution: {integrity: sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w== }
+ engines: { node: '>=18.0.0' }
'@smithy/smithy-client@4.2.3':
- resolution: {integrity: sha512-j/RRx6N007rJQ3qyjN4yuX9B0bxTn9ynDVxYQ43mcs7fluVJXmQGquy0TrWJfOPZcIikpY377GunZ2UK90GHYQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-j/RRx6N007rJQ3qyjN4yuX9B0bxTn9ynDVxYQ43mcs7fluVJXmQGquy0TrWJfOPZcIikpY377GunZ2UK90GHYQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/types@4.2.0':
- resolution: {integrity: sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg== }
+ engines: { node: '>=18.0.0' }
'@smithy/url-parser@4.0.2':
- resolution: {integrity: sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-base64@4.0.0':
- resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-body-length-browser@4.0.0':
- resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-body-length-node@4.0.0':
- resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-buffer-from@2.2.0':
- resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== }
+ engines: { node: '>=14.0.0' }
'@smithy/util-buffer-from@4.0.0':
- resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-config-provider@4.0.0':
- resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-defaults-mode-browser@4.0.11':
- resolution: {integrity: sha512-Z49QNUSKbEj7JVZqaSUZkTkexRciQBbmonJ8AMar4fA0S2kvVpgjeVyGXnZYWTFzkgEwStacjFq4cQKbaQ8AnQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Z49QNUSKbEj7JVZqaSUZkTkexRciQBbmonJ8AMar4fA0S2kvVpgjeVyGXnZYWTFzkgEwStacjFq4cQKbaQ8AnQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-defaults-mode-node@4.0.11':
- resolution: {integrity: sha512-y9UYcXjz4ry5sDPX40Vy6224Cw2/dch+wET6giaRoeXpyh56DCUVxW+Mgc/gO2uczAKktWd4ZWs2LWcW+PHz3Q==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-y9UYcXjz4ry5sDPX40Vy6224Cw2/dch+wET6giaRoeXpyh56DCUVxW+Mgc/gO2uczAKktWd4ZWs2LWcW+PHz3Q== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-endpoints@3.0.3':
- resolution: {integrity: sha512-284PZFhCMdudqq61/E67zJ3i10gCYrMBjXcMg3h048qI39gTXQCCeNZvtJhL4vrj9yMpJ/y9M+Ek7V0o5tak3w==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-284PZFhCMdudqq61/E67zJ3i10gCYrMBjXcMg3h048qI39gTXQCCeNZvtJhL4vrj9yMpJ/y9M+Ek7V0o5tak3w== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-hex-encoding@4.0.0':
- resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-middleware@4.0.2':
- resolution: {integrity: sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-retry@4.0.3':
- resolution: {integrity: sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-stream@4.2.0':
- resolution: {integrity: sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-uri-escape@4.0.0':
- resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-utf8@2.3.0':
- resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== }
+ engines: { node: '>=14.0.0' }
'@smithy/util-utf8@4.0.0':
- resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow== }
+ engines: { node: '>=18.0.0' }
'@smithy/util-waiter@4.0.3':
- resolution: {integrity: sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA== }
+ engines: { node: '>=18.0.0' }
'@solana-program/address-lookup-table@0.10.0':
- resolution: {integrity: sha512-lcp+IYwoFBODhg8vXsh5vpxweLxpSKqjAu8P1LyqQxgk2yqwYmJGA79YKa+lZvsQjP/c0rzIZYWIGxFMMes2zA==}
+ resolution:
+ { integrity: sha512-lcp+IYwoFBODhg8vXsh5vpxweLxpSKqjAu8P1LyqQxgk2yqwYmJGA79YKa+lZvsQjP/c0rzIZYWIGxFMMes2zA== }
peerDependencies:
'@solana/kit': ^5.0
'@solana-program/compute-budget@0.11.0':
- resolution: {integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==}
+ resolution:
+ { integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw== }
peerDependencies:
'@solana/kit': ^5.0
'@solana-program/memo@0.10.0':
- resolution: {integrity: sha512-1FvQFenL3lzl5SpxhWV4QJCOLU/nvAOXGXjKjS7dprvG+0u971xoanApN7bM/a4NFZolp6S+lP2xVl6vTVIxbg==}
+ resolution:
+ { integrity: sha512-1FvQFenL3lzl5SpxhWV4QJCOLU/nvAOXGXjKjS7dprvG+0u971xoanApN7bM/a4NFZolp6S+lP2xVl6vTVIxbg== }
peerDependencies:
'@solana/kit': ^5.0
'@solana-program/system@0.10.0':
- resolution: {integrity: sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g==}
+ resolution:
+ { integrity: sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g== }
peerDependencies:
'@solana/kit': ^5.0
'@solana-program/token-2022@0.6.1':
- resolution: {integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==}
+ resolution:
+ { integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA== }
peerDependencies:
'@solana/kit': ^5.0
'@solana/sysvars': ^5.0
'@solana-program/token@0.9.0':
- resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==}
+ resolution:
+ { integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA== }
peerDependencies:
'@solana/kit': ^5.0
'@solana/accounts@5.0.0':
- resolution: {integrity: sha512-0JzBdEobgp8NBdhhu+GgwNDh7e8KkHDsSTVZAnNQgvT3taOz0Mwv5E48MuEeDhW6DLFwWVAx/FO3pvibG/NGwA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-0JzBdEobgp8NBdhhu+GgwNDh7e8KkHDsSTVZAnNQgvT3taOz0Mwv5E48MuEeDhW6DLFwWVAx/FO3pvibG/NGwA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/accounts@5.5.1':
- resolution: {integrity: sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -1957,14 +2346,16 @@ packages:
optional: true
'@solana/addresses@5.0.0':
- resolution: {integrity: sha512-bVk+khc1ZZQHMri25csosM/ikuyPcB/CZidDM/ZMBX0CoJErpHJnmcID5mYOmv4/UHbqo2OANuEaGcFO0Q37sw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-bVk+khc1ZZQHMri25csosM/ikuyPcB/CZidDM/ZMBX0CoJErpHJnmcID5mYOmv4/UHbqo2OANuEaGcFO0Q37sw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/addresses@5.5.1':
- resolution: {integrity: sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -1972,14 +2363,16 @@ packages:
optional: true
'@solana/assertions@5.0.0':
- resolution: {integrity: sha512-2kIykk90kYciQW6bp+KaE6jRd1Y2CgHPeJxxlc5chQnjhoG6eiD8VXvocs6AvqPTht0p/SoEj9jH5tT4oG/bcg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-2kIykk90kYciQW6bp+KaE6jRd1Y2CgHPeJxxlc5chQnjhoG6eiD8VXvocs6AvqPTht0p/SoEj9jH5tT4oG/bcg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/assertions@5.5.1':
- resolution: {integrity: sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -1987,38 +2380,45 @@ packages:
optional: true
'@solana/buffer-layout-utils@0.2.0':
- resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==}
- engines: {node: '>= 10'}
+ resolution:
+ { integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== }
+ engines: { node: '>= 10' }
'@solana/buffer-layout@4.0.1':
- resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==}
- engines: {node: '>=5.10'}
+ resolution:
+ { integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== }
+ engines: { node: '>=5.10' }
'@solana/codecs-core@2.0.0-preview.4':
- resolution: {integrity: sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw==}
+ resolution:
+ { integrity: sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-core@2.0.0-rc.1':
- resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==}
+ resolution:
+ { integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-core@2.1.0':
- resolution: {integrity: sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5'
'@solana/codecs-core@5.0.0':
- resolution: {integrity: sha512-rCG2d8OaamVF2/J//YyCgDqNJpUytVVltw9C8mJtEz5c6Se/LR6BFuG8g4xeJswq/ab4RFk5/HFdgbvNjKgQjA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-rCG2d8OaamVF2/J//YyCgDqNJpUytVVltw9C8mJtEz5c6Se/LR6BFuG8g4xeJswq/ab4RFk5/HFdgbvNjKgQjA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/codecs-core@5.5.1':
- resolution: {integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2026,24 +2426,28 @@ packages:
optional: true
'@solana/codecs-data-structures@2.0.0-preview.4':
- resolution: {integrity: sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA==}
+ resolution:
+ { integrity: sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-data-structures@2.0.0-rc.1':
- resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==}
+ resolution:
+ { integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-data-structures@5.0.0':
- resolution: {integrity: sha512-y503Pqmv0LHcfcf0vQJGaxDvydQJbyCo8nK3nxn56EhFj5lBQ1NWb3WvTd83epigwuZurW2MhJARrpikfhQglQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-y503Pqmv0LHcfcf0vQJGaxDvydQJbyCo8nK3nxn56EhFj5lBQ1NWb3WvTd83epigwuZurW2MhJARrpikfhQglQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/codecs-data-structures@5.5.1':
- resolution: {integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2051,30 +2455,35 @@ packages:
optional: true
'@solana/codecs-numbers@2.0.0-preview.4':
- resolution: {integrity: sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ==}
+ resolution:
+ { integrity: sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-numbers@2.0.0-rc.1':
- resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==}
+ resolution:
+ { integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ== }
peerDependencies:
typescript: '>=5'
'@solana/codecs-numbers@2.1.0':
- resolution: {integrity: sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5'
'@solana/codecs-numbers@5.0.0':
- resolution: {integrity: sha512-a2+skRLuUK02f/XFe4L0e1+wHCyfK25PkyseFps1v1l4pvevukFwth/EhSyrs6w5CsTJRVoR7MuE3E00PM4egw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-a2+skRLuUK02f/XFe4L0e1+wHCyfK25PkyseFps1v1l4pvevukFwth/EhSyrs6w5CsTJRVoR7MuE3E00PM4egw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/codecs-numbers@5.5.1':
- resolution: {integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2082,27 +2491,31 @@ packages:
optional: true
'@solana/codecs-strings@2.0.0-preview.4':
- resolution: {integrity: sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw==}
+ resolution:
+ { integrity: sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw== }
peerDependencies:
fastestsmallesttextencoderdecoder: ^1.0.22
typescript: '>=5'
'@solana/codecs-strings@2.0.0-rc.1':
- resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==}
+ resolution:
+ { integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g== }
peerDependencies:
fastestsmallesttextencoderdecoder: ^1.0.22
typescript: '>=5'
'@solana/codecs-strings@5.0.0':
- resolution: {integrity: sha512-ALkRwpV8bGR6qjAYw0YXZwp2YI4wzvKOJGmx04Ut8gMdbaUx7qOcJkhEQKI6ZVC3lAWSIS1N1wGccUZDwvfKxw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-ALkRwpV8bGR6qjAYw0YXZwp2YI4wzvKOJGmx04Ut8gMdbaUx7qOcJkhEQKI6ZVC3lAWSIS1N1wGccUZDwvfKxw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
fastestsmallesttextencoderdecoder: ^1.0.22
typescript: '>=5.3.3'
'@solana/codecs-strings@5.5.1':
- resolution: {integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
fastestsmallesttextencoderdecoder: ^1.0.22
typescript: ^5.0.0
@@ -2113,24 +2526,28 @@ packages:
optional: true
'@solana/codecs@2.0.0-preview.4':
- resolution: {integrity: sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog==}
+ resolution:
+ { integrity: sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog== }
peerDependencies:
typescript: '>=5'
'@solana/codecs@2.0.0-rc.1':
- resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==}
+ resolution:
+ { integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ== }
peerDependencies:
typescript: '>=5'
'@solana/codecs@5.0.0':
- resolution: {integrity: sha512-KOw0gFUSBxIMDWLJ3AkVFkEci91dw0Rpx3C6y83Our7fSW+SEP8vRZklCElieYR85LHVB1QIEhoeHR7rc+Ifkw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-KOw0gFUSBxIMDWLJ3AkVFkEci91dw0Rpx3C6y83Our7fSW+SEP8vRZklCElieYR85LHVB1QIEhoeHR7rc+Ifkw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/codecs@5.5.1':
- resolution: {integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2138,34 +2555,39 @@ packages:
optional: true
'@solana/errors@2.0.0-preview.4':
- resolution: {integrity: sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA==}
+ resolution:
+ { integrity: sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA== }
hasBin: true
peerDependencies:
typescript: '>=5'
'@solana/errors@2.0.0-rc.1':
- resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==}
+ resolution:
+ { integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ== }
hasBin: true
peerDependencies:
typescript: '>=5'
'@solana/errors@2.1.0':
- resolution: {integrity: sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw== }
+ engines: { node: '>=20.18.0' }
hasBin: true
peerDependencies:
typescript: '>=5'
'@solana/errors@5.0.0':
- resolution: {integrity: sha512-gTuhzO6E+ydfAAzqmqdPcvFyJwAzFKKIrqtnZPpgAuomcPYu+HSo0tuwSM/cTX0djmHt+GoOsf/julph+nvs2w==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-gTuhzO6E+ydfAAzqmqdPcvFyJwAzFKKIrqtnZPpgAuomcPYu+HSo0tuwSM/cTX0djmHt+GoOsf/julph+nvs2w== }
+ engines: { node: '>=20.18.0' }
hasBin: true
peerDependencies:
typescript: '>=5.3.3'
'@solana/errors@5.5.1':
- resolution: {integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg== }
+ engines: { node: '>=20.18.0' }
hasBin: true
peerDependencies:
typescript: ^5.0.0
@@ -2174,50 +2596,58 @@ packages:
optional: true
'@solana/fast-stable-stringify@5.0.0':
- resolution: {integrity: sha512-sGTbu7a4/olL+8EIOOJ7IZjzqOOpCJcK1UaVJ6015sRgo9vwGf4jg9KtXEYv5LVhLCTYmAb50L4BaIUcBph/Ig==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-sGTbu7a4/olL+8EIOOJ7IZjzqOOpCJcK1UaVJ6015sRgo9vwGf4jg9KtXEYv5LVhLCTYmAb50L4BaIUcBph/Ig== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/functional@5.0.0':
- resolution: {integrity: sha512-UNBrpfzBL4dKD2iucjNnrkFbnjz5ZYDu2OvrIBAcCSQsxxgHMamUj1n3EDe6kl1us49YG1r05Ho8QLqNrbkVbw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-UNBrpfzBL4dKD2iucjNnrkFbnjz5ZYDu2OvrIBAcCSQsxxgHMamUj1n3EDe6kl1us49YG1r05Ho8QLqNrbkVbw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/instruction-plans@5.0.0':
- resolution: {integrity: sha512-n9oFOMFUPYKEhsXzrXT97QBQ2WvOTar+5SFEj/IOtRuCn4gl2kh0369cjXZpFwUdE3tmKr1zfYFNwbtiNx5pvg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-n9oFOMFUPYKEhsXzrXT97QBQ2WvOTar+5SFEj/IOtRuCn4gl2kh0369cjXZpFwUdE3tmKr1zfYFNwbtiNx5pvg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/instructions@5.0.0':
- resolution: {integrity: sha512-12dbrmwERT1o6NTr/Uvrjj/ZsiteSXoT5Gi+dnjIeRNHWg9H+gEFuFzJvTDVKlNg34CZ71xdvbVdbV0V8gKGvg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-12dbrmwERT1o6NTr/Uvrjj/ZsiteSXoT5Gi+dnjIeRNHWg9H+gEFuFzJvTDVKlNg34CZ71xdvbVdbV0V8gKGvg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/keys@5.0.0':
- resolution: {integrity: sha512-kWkR7NslpTttk5i1BhBNCDtVQDkEtgkdsM3Jp9TGPk0GFjBjBwrQStw3vvwLe8itEIvRFGFZU6JHEk8HLS0WLQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-kWkR7NslpTttk5i1BhBNCDtVQDkEtgkdsM3Jp9TGPk0GFjBjBwrQStw3vvwLe8itEIvRFGFZU6JHEk8HLS0WLQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/kit@5.0.0':
- resolution: {integrity: sha512-3ahtzmmMgU+1l2YMhQJSKKm14IdvCycOE/m4XNMu/4icBIptmBgZxrmgRpPHqBilBa+Krp/hBuTg4HWl9IAgWw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-3ahtzmmMgU+1l2YMhQJSKKm14IdvCycOE/m4XNMu/4icBIptmBgZxrmgRpPHqBilBa+Krp/hBuTg4HWl9IAgWw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/nominal-types@5.0.0':
- resolution: {integrity: sha512-Qn7xH4UG2rDAv+wAyheP4jWvX3oQmbZ/woxFZwug7PaRLvyjUswGr38Hil+SjiQyFDo+un1UqWM9N9yusUeeZQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-Qn7xH4UG2rDAv+wAyheP4jWvX3oQmbZ/woxFZwug7PaRLvyjUswGr38Hil+SjiQyFDo+un1UqWM9N9yusUeeZQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/nominal-types@5.5.1':
- resolution: {integrity: sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2225,24 +2655,28 @@ packages:
optional: true
'@solana/options@2.0.0-preview.4':
- resolution: {integrity: sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA==}
+ resolution:
+ { integrity: sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA== }
peerDependencies:
typescript: '>=5'
'@solana/options@2.0.0-rc.1':
- resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==}
+ resolution:
+ { integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA== }
peerDependencies:
typescript: '>=5'
'@solana/options@5.0.0':
- resolution: {integrity: sha512-ezHVBFb9FXVSn8LUVRD2tLb6fejU0x8KtGEYyCYh0J0pQuXSITV0IQCjcEopvu/ZxWdXOJyzjvmymnhz90on5A==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-ezHVBFb9FXVSn8LUVRD2tLb6fejU0x8KtGEYyCYh0J0pQuXSITV0IQCjcEopvu/ZxWdXOJyzjvmymnhz90on5A== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/options@5.5.1':
- resolution: {integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2250,38 +2684,44 @@ packages:
optional: true
'@solana/programs@5.0.0':
- resolution: {integrity: sha512-BKOfBDrSUCJGZ+qKk2aFLu0nU9/84o6z/VDCJkLjaNNuTv8nOlSYq5flNzo1eyJmnpyW372qNvqqRN3AS23+FQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-BKOfBDrSUCJGZ+qKk2aFLu0nU9/84o6z/VDCJkLjaNNuTv8nOlSYq5flNzo1eyJmnpyW372qNvqqRN3AS23+FQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/promises@5.0.0':
- resolution: {integrity: sha512-Qmg3UfYfWINEUvBQL3DkPOq34tTg5cfrkPlDtJmi8RVifsPqb6hksbKZGu7ASLZohxIDGmnYQY6oELI7Me+5yw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-Qmg3UfYfWINEUvBQL3DkPOq34tTg5cfrkPlDtJmi8RVifsPqb6hksbKZGu7ASLZohxIDGmnYQY6oELI7Me+5yw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-api@5.0.0':
- resolution: {integrity: sha512-IJbZZnX2B1ldXPok1NhneXTYq9ZvdJbE5Pryr03pZTlPJaWGqDcZuQ14nwR4s6PoUUgdT+p87QlLZqLb8MusoQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-IJbZZnX2B1ldXPok1NhneXTYq9ZvdJbE5Pryr03pZTlPJaWGqDcZuQ14nwR4s6PoUUgdT+p87QlLZqLb8MusoQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-parsed-types@5.0.0':
- resolution: {integrity: sha512-fU9uqlOYAaBqgk2qCl+ntenBm7wuSFBRbIO/rVjeBPd/qPCvNZU+qFET+ERLK6wbCTSz0MmdHqPn1V8KCMOvZQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-fU9uqlOYAaBqgk2qCl+ntenBm7wuSFBRbIO/rVjeBPd/qPCvNZU+qFET+ERLK6wbCTSz0MmdHqPn1V8KCMOvZQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-spec-types@5.0.0':
- resolution: {integrity: sha512-B0P/ylXVaCG5oSIV+kB88s2qoW996D8iKhc7RyF0C/AyYvklF6kCwv0N9ZVrWp0ibjlQ8St290WbBHJyo7QZkA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-B0P/ylXVaCG5oSIV+kB88s2qoW996D8iKhc7RyF0C/AyYvklF6kCwv0N9ZVrWp0ibjlQ8St290WbBHJyo7QZkA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-spec-types@5.5.1':
- resolution: {integrity: sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2289,14 +2729,16 @@ packages:
optional: true
'@solana/rpc-spec@5.0.0':
- resolution: {integrity: sha512-1LD2SYEQ5bYhiBumznAPzymtxSX4nYLZd6u+FA0bAxNBVzHDvUUQzVSXHAoWROhlGrCyvtALTs9u0DIDlgZHCA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-1LD2SYEQ5bYhiBumznAPzymtxSX4nYLZd6u+FA0bAxNBVzHDvUUQzVSXHAoWROhlGrCyvtALTs9u0DIDlgZHCA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-spec@5.5.1':
- resolution: {integrity: sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2304,51 +2746,59 @@ packages:
optional: true
'@solana/rpc-subscriptions-api@5.0.0':
- resolution: {integrity: sha512-DGUn3C12swV2FConOlLFN14npIrCtnxehtMLjszMC7g6p/P6WNIz5uAgF7YcIkLBDV8uTeWhM0azmK+V8Qqhvg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-DGUn3C12swV2FConOlLFN14npIrCtnxehtMLjszMC7g6p/P6WNIz5uAgF7YcIkLBDV8uTeWhM0azmK+V8Qqhvg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-subscriptions-channel-websocket@5.0.0':
- resolution: {integrity: sha512-vsYXyjVX/kExfpr91zfMKTmWKKFCM+dkhXQDAz5aEE7kAF3KSZDiOGeYvN8Rc85lbIt9QK6BLAT+NBMv4/N9Qg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-vsYXyjVX/kExfpr91zfMKTmWKKFCM+dkhXQDAz5aEE7kAF3KSZDiOGeYvN8Rc85lbIt9QK6BLAT+NBMv4/N9Qg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
ws: ^8.18.0
'@solana/rpc-subscriptions-spec@5.0.0':
- resolution: {integrity: sha512-erRLvZMncwnciJP6I1SlAk0CyRGIgt83PyHWOVCRXENP9Q5dZbZ9pm4lar2yIp8EjIMnodGHsQWIlKc1hlCQlQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-erRLvZMncwnciJP6I1SlAk0CyRGIgt83PyHWOVCRXENP9Q5dZbZ9pm4lar2yIp8EjIMnodGHsQWIlKc1hlCQlQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-subscriptions@5.0.0':
- resolution: {integrity: sha512-cziOSzom/bwFZXViR9J+MxDsdLMcfvrXGw5Icng7dYODFKuVqfsDrQoG8uekJc4fREnbPEM2U+u9YnYSYbFbww==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-cziOSzom/bwFZXViR9J+MxDsdLMcfvrXGw5Icng7dYODFKuVqfsDrQoG8uekJc4fREnbPEM2U+u9YnYSYbFbww== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-transformers@5.0.0':
- resolution: {integrity: sha512-EMHhSgfF6/T4FfHbLaBP08SIj1ZAjxJr6WPNZMHLV7Cup8UfiB9TNV+bPQkum7JbVQNhUKzkKEEmyYqPfQoV9w==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-EMHhSgfF6/T4FfHbLaBP08SIj1ZAjxJr6WPNZMHLV7Cup8UfiB9TNV+bPQkum7JbVQNhUKzkKEEmyYqPfQoV9w== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-transport-http@5.0.0':
- resolution: {integrity: sha512-RoIEvWp7yc7rIRzNkOyjLs2UQF0odIEMWj87dbD4Ir4hwTCGo/TSTfQF/8KDV2etdke3Fa1K+W1NkpG2POqWFg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-RoIEvWp7yc7rIRzNkOyjLs2UQF0odIEMWj87dbD4Ir4hwTCGo/TSTfQF/8KDV2etdke3Fa1K+W1NkpG2POqWFg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-types@5.0.0':
- resolution: {integrity: sha512-JMbhwnV6nX4ezJv/KmaElOR0r/MZTKzKpaz6cv7FopLNuPrYCBrRCZKuM2XQh6gUbt9Mey08/KBOmOGmzTbL/g==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-JMbhwnV6nX4ezJv/KmaElOR0r/MZTKzKpaz6cv7FopLNuPrYCBrRCZKuM2XQh6gUbt9Mey08/KBOmOGmzTbL/g== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/rpc-types@5.5.1':
- resolution: {integrity: sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2356,80 +2806,94 @@ packages:
optional: true
'@solana/rpc@5.0.0':
- resolution: {integrity: sha512-Myx/ZBmMHkgh9Di3tLzc+vd30f+6YC1JXr9+YmIHKEeqN/+iTHkDJU2E/hGRLy8vTOBOU7+2466A+dLnSVuGkg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-Myx/ZBmMHkgh9Di3tLzc+vd30f+6YC1JXr9+YmIHKEeqN/+iTHkDJU2E/hGRLy8vTOBOU7+2466A+dLnSVuGkg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/signers@5.0.0':
- resolution: {integrity: sha512-9Hw6HekSEzj5O7UBBFPrxk96W5e8tMI3n7KbW7/QiKBDpuvYw9WtnjOsWUE7LqQoc1P0JjGEsrmxE9raQBLvuQ==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-9Hw6HekSEzj5O7UBBFPrxk96W5e8tMI3n7KbW7/QiKBDpuvYw9WtnjOsWUE7LqQoc1P0JjGEsrmxE9raQBLvuQ== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/spl-token-group@0.0.5':
- resolution: {integrity: sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.94.0
'@solana/spl-token-group@0.0.7':
- resolution: {integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.95.3
'@solana/spl-token-metadata@0.1.6':
- resolution: {integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.95.3
'@solana/spl-token-registry@0.2.4574':
- resolution: {integrity: sha512-JzlfZmke8Rxug20VT/VpI2XsXlsqMlcORIUivF+Yucj7tFi7A0dXG7h+2UnD0WaZJw8BrUz2ABNkUnv89vbv1A==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-JzlfZmke8Rxug20VT/VpI2XsXlsqMlcORIUivF+Yucj7tFi7A0dXG7h+2UnD0WaZJw8BrUz2ABNkUnv89vbv1A== }
+ engines: { node: '>=10' }
'@solana/spl-token@0.2.0':
- resolution: {integrity: sha512-RWcn31OXtdqIxmkzQfB2R+WpsJOVS6rKuvpxJFjvik2LyODd+WN58ZP3Rpjpro03fscGAkzlFuP3r42doRJgyQ==}
- engines: {node: '>= 14'}
+ resolution:
+ { integrity: sha512-RWcn31OXtdqIxmkzQfB2R+WpsJOVS6rKuvpxJFjvik2LyODd+WN58ZP3Rpjpro03fscGAkzlFuP3r42doRJgyQ== }
+ engines: { node: '>= 14' }
'@solana/spl-token@0.3.11':
- resolution: {integrity: sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.88.0
'@solana/spl-token@0.4.14':
- resolution: {integrity: sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.95.5
'@solana/spl-token@0.4.8':
- resolution: {integrity: sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA== }
+ engines: { node: '>=16' }
peerDependencies:
'@solana/web3.js': ^1.94.0
'@solana/spl-type-length-value@0.1.0':
- resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== }
+ engines: { node: '>=16' }
'@solana/subscribable@5.0.0':
- resolution: {integrity: sha512-C2TydIRRd5XUJ8asbARi67Sj/3DRLubWalnNoafBhDsrb88jsRVylntvwXgBw/+lwJdEPEsUnxvcdgdm+3lFlw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-C2TydIRRd5XUJ8asbARi67Sj/3DRLubWalnNoafBhDsrb88jsRVylntvwXgBw/+lwJdEPEsUnxvcdgdm+3lFlw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/sysvars@5.0.0':
- resolution: {integrity: sha512-F/GEb2rS8mrgDd79lDPyu8za9jGE6cRlS4jHNeKCkvOCJxdKQbX34JIzx4kwzjtvk7O8/yrDHfGdpA8nBg/l4w==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-F/GEb2rS8mrgDd79lDPyu8za9jGE6cRlS4jHNeKCkvOCJxdKQbX34JIzx4kwzjtvk7O8/yrDHfGdpA8nBg/l4w== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/sysvars@5.5.1':
- resolution: {integrity: sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: ^5.0.0
peerDependenciesMeta:
@@ -2437,226 +2901,294 @@ packages:
optional: true
'@solana/transaction-confirmation@5.0.0':
- resolution: {integrity: sha512-LpusTopYIuQC8hBCloExkTr4Z5/zdp5f4IIbzD5XFeW3xXPZytS3H1IDMGk4bmLdZi9zQNA4lnNHKra5IncRbw==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-LpusTopYIuQC8hBCloExkTr4Z5/zdp5f4IIbzD5XFeW3xXPZytS3H1IDMGk4bmLdZi9zQNA4lnNHKra5IncRbw== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/transaction-messages@5.0.0':
- resolution: {integrity: sha512-rJLe1wUGW5DovQFV0gjXHXnriPxTBgZ3TvGWnjCu2OIBU8mcQkQVJ7zzVZY2IAYlmJ6OSF9nvzhSt/ncPbkJPg==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-rJLe1wUGW5DovQFV0gjXHXnriPxTBgZ3TvGWnjCu2OIBU8mcQkQVJ7zzVZY2IAYlmJ6OSF9nvzhSt/ncPbkJPg== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/transactions@5.0.0':
- resolution: {integrity: sha512-4TcsqH7JtgRKGGBIRRGz0n+tXu4h5TPPC49kkV0ygIndQaHW7FOZUYTwQ0epq0A5h9KYi+ClNbzF9xiuDbAD5Q==}
- engines: {node: '>=20.18.0'}
+ resolution:
+ { integrity: sha512-4TcsqH7JtgRKGGBIRRGz0n+tXu4h5TPPC49kkV0ygIndQaHW7FOZUYTwQ0epq0A5h9KYi+ClNbzF9xiuDbAD5Q== }
+ engines: { node: '>=20.18.0' }
peerDependencies:
typescript: '>=5.3.3'
'@solana/wallet-adapter-base@0.9.26':
- resolution: {integrity: sha512-1RcmfesJ8bTT+zfg4w+Z+wisj11HR+vWwl/pS6v/zwQPe0LSzWDpkXRv9JuDSCuTcmlglEfjEqFAW+5EubK/Jg==}
- engines: {node: '>=20'}
+ resolution:
+ { integrity: sha512-1RcmfesJ8bTT+zfg4w+Z+wisj11HR+vWwl/pS6v/zwQPe0LSzWDpkXRv9JuDSCuTcmlglEfjEqFAW+5EubK/Jg== }
+ engines: { node: '>=20' }
peerDependencies:
'@solana/web3.js': ^1.98.0
'@solana/wallet-standard-features@1.3.0':
- resolution: {integrity: sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg== }
+ engines: { node: '>=16' }
'@solana/web3.js@1.95.8':
- resolution: {integrity: sha512-sBHzNh7dHMrmNS5xPD1d0Xa2QffW/RXaxu/OysRXBfwTp+LYqGGmMtCYYwrHPrN5rjAmJCsQRNAwv4FM0t3B6g==}
+ resolution:
+ { integrity: sha512-sBHzNh7dHMrmNS5xPD1d0Xa2QffW/RXaxu/OysRXBfwTp+LYqGGmMtCYYwrHPrN5rjAmJCsQRNAwv4FM0t3B6g== }
'@solana/web3.js@1.98.2':
- resolution: {integrity: sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A==}
+ resolution:
+ { integrity: sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A== }
'@solflare-wallet/utl-sdk@1.4.0':
- resolution: {integrity: sha512-0E3s+fXs5XMGBNrXGB4XSH4+sPgLanbBEVyz227KJyxSIgiRdQMcM2Yv/KdnMHNmhYoR/aPpH6TH115SIJqM0A==}
+ resolution:
+ { integrity: sha512-0E3s+fXs5XMGBNrXGB4XSH4+sPgLanbBEVyz227KJyxSIgiRdQMcM2Yv/KdnMHNmhYoR/aPpH6TH115SIJqM0A== }
peerDependencies:
'@solana/web3.js': '*'
'@supercharge/promise-pool@2.4.0':
- resolution: {integrity: sha512-O9CMipBlq5OObdt1uKJGIzm9cdjpPWfj+a+Zw9EgWKxaMNHKC7EU7X9taj3H0EGQNLOSq2jAcOa3EzxlfHsD6w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-O9CMipBlq5OObdt1uKJGIzm9cdjpPWfj+a+Zw9EgWKxaMNHKC7EU7X9taj3H0EGQNLOSq2jAcOa3EzxlfHsD6w== }
+ engines: { node: '>=8' }
'@swc/helpers@0.5.17':
- resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
+ resolution:
+ { integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== }
'@tsconfig/node10@1.0.11':
- resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
+ resolution:
+ { integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== }
'@tsconfig/node12@1.0.11':
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+ resolution:
+ { integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== }
'@tsconfig/node14@1.0.3':
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+ resolution:
+ { integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== }
'@tsconfig/node16@1.0.4':
- resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+ resolution:
+ { integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== }
'@tybys/wasm-util@0.9.0':
- resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+ resolution:
+ { integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== }
'@types/abstract-leveldown@7.2.5':
- resolution: {integrity: sha512-/2B0nQF4UdupuxeKTJA2+Rj1D+uDemo6P4kMwKCpbfpnzeVaWSELTsAw4Lxn3VJD6APtRrZOCuYo+4nHUQfTfg==}
+ resolution:
+ { integrity: sha512-/2B0nQF4UdupuxeKTJA2+Rj1D+uDemo6P4kMwKCpbfpnzeVaWSELTsAw4Lxn3VJD6APtRrZOCuYo+4nHUQfTfg== }
'@types/app-root-path@1.2.8':
- resolution: {integrity: sha512-l12miuN6JXAi3yuADZNhRKbyN7IIyaUP9hFVZ/BbHhWYpBkHLbOaX2WkQoXGJyAgMcP9iZ0S9+tz/FN40VrwWQ==}
+ resolution:
+ { integrity: sha512-l12miuN6JXAi3yuADZNhRKbyN7IIyaUP9hFVZ/BbHhWYpBkHLbOaX2WkQoXGJyAgMcP9iZ0S9+tz/FN40VrwWQ== }
'@types/babel__core@7.20.5':
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+ resolution:
+ { integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== }
'@types/babel__generator@7.27.0':
- resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+ resolution:
+ { integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== }
'@types/babel__template@7.4.4':
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+ resolution:
+ { integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== }
'@types/babel__traverse@7.20.7':
- resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}
+ resolution:
+ { integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng== }
'@types/bn.js@5.1.6':
- resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==}
+ resolution:
+ { integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w== }
'@types/body-parser@1.19.5':
- resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+ resolution:
+ { integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== }
'@types/brotli@1.3.4':
- resolution: {integrity: sha512-cKYjgaS2DMdCKF7R0F5cgx1nfBYObN2ihIuPGQ4/dlIY6RpV7OWNwe9L8V4tTVKL2eZqOkNM9FM/rgTvLf4oXw==}
+ resolution:
+ { integrity: sha512-cKYjgaS2DMdCKF7R0F5cgx1nfBYObN2ihIuPGQ4/dlIY6RpV7OWNwe9L8V4tTVKL2eZqOkNM9FM/rgTvLf4oXw== }
'@types/bs58@4.0.4':
- resolution: {integrity: sha512-0IEpMFXXQi2zXaXl9GJ3sRwQo0uEkD+yFOv+FnAU5lkPtcu6h61xb7jc2CFPEZ5BUOaiP13ThuGc9HD4R8lR5g==}
+ resolution:
+ { integrity: sha512-0IEpMFXXQi2zXaXl9GJ3sRwQo0uEkD+yFOv+FnAU5lkPtcu6h61xb7jc2CFPEZ5BUOaiP13ThuGc9HD4R8lR5g== }
'@types/connect@3.4.38':
- resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+ resolution:
+ { integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== }
'@types/encoding-down@5.0.5':
- resolution: {integrity: sha512-HXlcVUJm2ITDgH34S1BjLMJhpfkXvEOEv+HS9KZweRl0LKlWNzVwFAj+N6pGExsRGsofhgqZP4ArQZJlWvBFDQ==}
+ resolution:
+ { integrity: sha512-HXlcVUJm2ITDgH34S1BjLMJhpfkXvEOEv+HS9KZweRl0LKlWNzVwFAj+N6pGExsRGsofhgqZP4ArQZJlWvBFDQ== }
'@types/express-serve-static-core@4.19.6':
- resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==}
+ resolution:
+ { integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== }
'@types/express@4.17.21':
- resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+ resolution:
+ { integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== }
'@types/fs-extra@9.0.13':
- resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
+ resolution:
+ { integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== }
'@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
+ resolution:
+ { integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== }
'@types/http-errors@2.0.4':
- resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+ resolution:
+ { integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== }
'@types/istanbul-lib-coverage@2.0.6':
- resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+ resolution:
+ { integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== }
'@types/istanbul-lib-report@3.0.3':
- resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+ resolution:
+ { integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== }
'@types/istanbul-reports@1.1.2':
- resolution: {integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==}
+ resolution:
+ { integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== }
'@types/istanbul-reports@3.0.4':
- resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+ resolution:
+ { integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== }
'@types/jest@29.5.14':
- resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+ resolution:
+ { integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== }
'@types/js-yaml@4.0.9':
- resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==}
+ resolution:
+ { integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== }
'@types/json5@0.0.29':
- resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+ resolution:
+ { integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== }
'@types/level-codec@9.0.4':
- resolution: {integrity: sha512-N6v5EhpvF00Wv+1ixzqca9YD2wdK76JceSnUoiKfQh/vex+VFG852wzqohnlYf67nzKQoXeRzYd8W57fIkYCvg==}
+ resolution:
+ { integrity: sha512-N6v5EhpvF00Wv+1ixzqca9YD2wdK76JceSnUoiKfQh/vex+VFG852wzqohnlYf67nzKQoXeRzYd8W57fIkYCvg== }
'@types/level-errors@3.0.2':
- resolution: {integrity: sha512-gyZHbcQ2X5hNXf/9KS2qGEmgDe9EN2WDM3rJ5Ele467C0nA1sLhtmv1bZiPMDYfAYCfPWft0uQIaTvXbASSTRA==}
+ resolution:
+ { integrity: sha512-gyZHbcQ2X5hNXf/9KS2qGEmgDe9EN2WDM3rJ5Ele467C0nA1sLhtmv1bZiPMDYfAYCfPWft0uQIaTvXbASSTRA== }
'@types/level@6.0.3':
- resolution: {integrity: sha512-Wl95qkwvCZGwODK+AGALTJjeotfejR/hTNeErNmonmKCl/1moL/ZNVxHsPNIxXAUh9tIk6zEwBwx9erNVdUQOg==}
+ resolution:
+ { integrity: sha512-Wl95qkwvCZGwODK+AGALTJjeotfejR/hTNeErNmonmKCl/1moL/ZNVxHsPNIxXAUh9tIk6zEwBwx9erNVdUQOg== }
'@types/levelup@5.1.5':
- resolution: {integrity: sha512-Sm0jSj+LoncQ8BuZZJBjYitY5r9/V/Xd//vRjfgbQLWcQg2/iCm0HQqIOZ1KBE7QdNyAqMIG97mE3+t1GR0TIw==}
+ resolution:
+ { integrity: sha512-Sm0jSj+LoncQ8BuZZJBjYitY5r9/V/Xd//vRjfgbQLWcQg2/iCm0HQqIOZ1KBE7QdNyAqMIG97mE3+t1GR0TIw== }
'@types/lru-cache@5.1.1':
- resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==}
+ resolution:
+ { integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== }
'@types/mathjs@9.4.2':
- resolution: {integrity: sha512-GF5g1vJmvKdWIWsE53XX7EDAyCaZ9p6gaYm1xhlXn5JjrY/NJrOfJN3fBxS3wyZpVh3QqKoMkS2WjFwxWMHOTw==}
+ resolution:
+ { integrity: sha512-GF5g1vJmvKdWIWsE53XX7EDAyCaZ9p6gaYm1xhlXn5JjrY/NJrOfJN3fBxS3wyZpVh3QqKoMkS2WjFwxWMHOTw== }
deprecated: This is a stub types definition. mathjs provides its own type definitions, so you do not need this installed.
'@types/mime@1.3.5':
- resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+ resolution:
+ { integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== }
'@types/minimist@1.2.5':
- resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
+ resolution:
+ { integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== }
'@types/node-fetch@2.6.12':
- resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
+ resolution:
+ { integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== }
'@types/node@11.11.6':
- resolution: {integrity: sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==}
+ resolution:
+ { integrity: sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== }
'@types/node@12.20.55':
- resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
+ resolution:
+ { integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== }
'@types/node@15.14.9':
- resolution: {integrity: sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==}
+ resolution:
+ { integrity: sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== }
'@types/pbkdf2@3.1.2':
- resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==}
+ resolution:
+ { integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== }
'@types/qs@6.9.18':
- resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==}
+ resolution:
+ { integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA== }
'@types/range-parser@1.2.7':
- resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+ resolution:
+ { integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== }
'@types/secp256k1@4.0.6':
- resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==}
+ resolution:
+ { integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== }
'@types/send@0.17.4':
- resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+ resolution:
+ { integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== }
'@types/serve-static@1.15.7':
- resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
+ resolution:
+ { integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== }
'@types/stack-utils@1.0.1':
- resolution: {integrity: sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==}
+ resolution:
+ { integrity: sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== }
'@types/stack-utils@2.0.3':
- resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+ resolution:
+ { integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== }
'@types/triple-beam@1.3.5':
- resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
+ resolution:
+ { integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== }
'@types/uuid@8.3.4':
- resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==}
+ resolution:
+ { integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== }
'@types/w3c-web-usb@1.0.10':
- resolution: {integrity: sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ==}
+ resolution:
+ { integrity: sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ== }
'@types/ws@7.4.7':
- resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==}
+ resolution:
+ { integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== }
'@types/ws@8.18.1':
- resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+ resolution:
+ { integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== }
'@types/yargs-parser@21.0.3':
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+ resolution:
+ { integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== }
'@types/yargs@13.0.12':
- resolution: {integrity: sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==}
+ resolution:
+ { integrity: sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== }
'@types/yargs@17.0.33':
- resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+ resolution:
+ { integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== }
'@typescript-eslint/eslint-plugin@7.18.0':
- resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
peerDependencies:
'@typescript-eslint/parser': ^7.0.0
eslint: ^8.56.0
@@ -2666,8 +3198,9 @@ packages:
optional: true
'@typescript-eslint/parser@7.18.0':
- resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
peerDependencies:
eslint: ^8.56.0
typescript: '*'
@@ -2676,12 +3209,14 @@ packages:
optional: true
'@typescript-eslint/scope-manager@7.18.0':
- resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
'@typescript-eslint/type-utils@7.18.0':
- resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
peerDependencies:
eslint: ^8.56.0
typescript: '*'
@@ -2690,12 +3225,14 @@ packages:
optional: true
'@typescript-eslint/types@7.18.0':
- resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
'@typescript-eslint/typescript-estree@7.18.0':
- resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -2703,40 +3240,49 @@ packages:
optional: true
'@typescript-eslint/utils@7.18.0':
- resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
peerDependencies:
eslint: ^8.56.0
'@typescript-eslint/visitor-keys@7.18.0':
- resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== }
+ engines: { node: ^18.18.0 || >=20.0.0 }
'@ungap/structured-clone@1.3.0':
- resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+ resolution:
+ { integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== }
deprecated: Potential CWE-502 - Update to 1.3.1 or higher
'@uniswap/default-token-list@11.19.0':
- resolution: {integrity: sha512-H/YLpxeZUrzT4Ki8mi4k5UiadREiLHg7WUqCv0Qt/VkOjX2mIBhrxCj1Wh61/J7lK0XqOjksfpm6RG1+YErPoQ==}
+ resolution:
+ { integrity: sha512-H/YLpxeZUrzT4Ki8mi4k5UiadREiLHg7WUqCv0Qt/VkOjX2mIBhrxCj1Wh61/J7lK0XqOjksfpm6RG1+YErPoQ== }
'@uniswap/lib@4.0.1-alpha':
- resolution: {integrity: sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== }
+ engines: { node: '>=10' }
'@uniswap/permit2-sdk@1.4.0':
- resolution: {integrity: sha512-l/aGhfhB93M76vXs4eB8QNwhELE6bs66kh7F1cyobaPtINaVpMmlJv+j3KmHeHwAZIsh7QXyYzhDxs07u0Pe4Q==}
+ resolution:
+ { integrity: sha512-l/aGhfhB93M76vXs4eB8QNwhELE6bs66kh7F1cyobaPtINaVpMmlJv+j3KmHeHwAZIsh7QXyYzhDxs07u0Pe4Q== }
'@uniswap/router-sdk@2.11.0':
- resolution: {integrity: sha512-DGx04vX+BbomBbeBwV8mHOxVG4sUmXZjQHZZYcCYCom00jt5ab6j+GRqiiLYf5TgaZHUk2DK+1CWuWuL3gLfoA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-DGx04vX+BbomBbeBwV8mHOxVG4sUmXZjQHZZYcCYCom00jt5ab6j+GRqiiLYf5TgaZHUk2DK+1CWuWuL3gLfoA== }
+ engines: { node: '>=18' }
'@uniswap/sdk-core@7.18.0':
- resolution: {integrity: sha512-Fy/U/yEweEYbGZi1cOpFBRTE0rwrueBesG8MPRlfhVXwutLn5OXZe5TjFSdIrjp7vqrNqgdmKIHIwg9k6MMSLQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-Fy/U/yEweEYbGZi1cOpFBRTE0rwrueBesG8MPRlfhVXwutLn5OXZe5TjFSdIrjp7vqrNqgdmKIHIwg9k6MMSLQ== }
+ engines: { node: '>=18' }
'@uniswap/sdk@3.0.3':
- resolution: {integrity: sha512-t4s8bvzaCFSiqD2qfXIm3rWhbdnXp+QjD3/mRaeVDHK7zWevs6RGEb1ohMiNgOCTZANvBayb4j8p+XFdnMBadQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-t4s8bvzaCFSiqD2qfXIm3rWhbdnXp+QjD3/mRaeVDHK7zWevs6RGEb1ohMiNgOCTZANvBayb4j8p+XFdnMBadQ== }
+ engines: { node: '>=10' }
peerDependencies:
'@ethersproject/address': ^5.0.0-beta
'@ethersproject/contracts': ^5.0.0-beta
@@ -2745,182 +3291,221 @@ packages:
'@ethersproject/solidity': ^5.0.0-beta
'@uniswap/smart-order-router@4.31.10':
- resolution: {integrity: sha512-Bmg46KXDSfE1AAf1tPg+vDzMngVoGfzdohekhjJ1hIQG13tXcjEykqapQy+CrJUqXLL3lQvZj2uVEKfzCNH74Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Bmg46KXDSfE1AAf1tPg+vDzMngVoGfzdohekhjJ1hIQG13tXcjEykqapQy+CrJUqXLL3lQvZj2uVEKfzCNH74Q== }
+ engines: { node: '>=10' }
peerDependencies:
jsbi: ^3.2.0
'@uniswap/swap-router-contracts@1.3.1':
- resolution: {integrity: sha512-mh/YNbwKb7Mut96VuEtL+Z5bRe0xVIbjjiryn+iMMrK2sFKhR4duk/86mEz0UO5gSx4pQIw9G5276P5heY/7Rg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-mh/YNbwKb7Mut96VuEtL+Z5bRe0xVIbjjiryn+iMMrK2sFKhR4duk/86mEz0UO5gSx4pQIw9G5276P5heY/7Rg== }
+ engines: { node: '>=10' }
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
'@uniswap/token-lists@1.0.0-beta.34':
- resolution: {integrity: sha512-Hc3TfrFaupg0M84e/Zv7BoF+fmMWDV15mZ5s8ZQt2qZxUcNw2GQW+L6L/2k74who31G+p1m3GRYbJpAo7d1pqA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Hc3TfrFaupg0M84e/Zv7BoF+fmMWDV15mZ5s8ZQt2qZxUcNw2GQW+L6L/2k74who31G+p1m3GRYbJpAo7d1pqA== }
+ engines: { node: '>=10' }
'@uniswap/universal-router-sdk@4.30.0':
- resolution: {integrity: sha512-yO34+VMtqGScCxym0x9C3nTCk5sLef/dkOj5dvnLEs21fXp7k3Y54ih6zCWh2BqJnWcD8/tQdME1jTTy9RsZYA==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-yO34+VMtqGScCxym0x9C3nTCk5sLef/dkOj5dvnLEs21fXp7k3Y54ih6zCWh2BqJnWcD8/tQdME1jTTy9RsZYA== }
+ engines: { node: '>=14' }
'@uniswap/universal-router-sdk@5.10.0':
- resolution: {integrity: sha512-09ISYFJGfehv+FwJjLboLTGKEPlTmkLnBTR6uUhLpkevi8ah4iyfcnDxjNLwW8heJT2VKxE3fSHxb1fwf+uSMg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-09ISYFJGfehv+FwJjLboLTGKEPlTmkLnBTR6uUhLpkevi8ah4iyfcnDxjNLwW8heJT2VKxE3fSHxb1fwf+uSMg== }
+ engines: { node: '>=18' }
'@uniswap/universal-router@1.6.0':
- resolution: {integrity: sha512-Gt0b0rtMV1vSrgXY3vz5R1RCZENB+rOkbOidY9GvcXrK1MstSrQSOAc+FCr8FSgsDhmRAdft0lk5YUxtM9i9Lg==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-Gt0b0rtMV1vSrgXY3vz5R1RCZENB+rOkbOidY9GvcXrK1MstSrQSOAc+FCr8FSgsDhmRAdft0lk5YUxtM9i9Lg== }
+ engines: { node: '>=14' }
'@uniswap/universal-router@2.1.0':
- resolution: {integrity: sha512-rt18RUsZd9xDfyVfIONJo+TEQ8w+olOYxu9+A1g4Thil1R7IMa+8mnyVQjdLPK2REhejScDwjYbOGpeaAce0hg==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-rt18RUsZd9xDfyVfIONJo+TEQ8w+olOYxu9+A1g4Thil1R7IMa+8mnyVQjdLPK2REhejScDwjYbOGpeaAce0hg== }
+ engines: { node: '>=14' }
'@uniswap/v2-core@1.0.1':
- resolution: {integrity: sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== }
+ engines: { node: '>=10' }
'@uniswap/v2-sdk@4.21.0':
- resolution: {integrity: sha512-enr8SZRwrSgc/TYGJv4YS5f9oV049HwZJUF/xy1ZS4Vf55ie282SwkPZNMjA7IV+cYPtl6HKermaebXlneDEbg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-enr8SZRwrSgc/TYGJv4YS5f9oV049HwZJUF/xy1ZS4Vf55ie282SwkPZNMjA7IV+cYPtl6HKermaebXlneDEbg== }
+ engines: { node: '>=18' }
'@uniswap/v3-core@1.0.0':
- resolution: {integrity: sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== }
+ engines: { node: '>=10' }
'@uniswap/v3-core@1.0.1':
- resolution: {integrity: sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ== }
+ engines: { node: '>=10' }
'@uniswap/v3-periphery@1.4.4':
- resolution: {integrity: sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw== }
+ engines: { node: '>=10' }
'@uniswap/v3-sdk@3.27.0':
- resolution: {integrity: sha512-BRgb9nWuxptXJmuQrax9XyqcuOMEuWsUjDSyus0UvOavzijbOu8jh3DWptg/15D7oL67Xmz5zvQaSPbLIL1cpA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-BRgb9nWuxptXJmuQrax9XyqcuOMEuWsUjDSyus0UvOavzijbOu8jh3DWptg/15D7oL67Xmz5zvQaSPbLIL1cpA== }
+ engines: { node: '>=10' }
'@uniswap/v3-sdk@3.31.0':
- resolution: {integrity: sha512-7M9LXSO+XhB/Y+9SwONHaiJqYSTlHMqOSqeWGpSNAQOZZd5P7z/FXyWmvL1OogVsghW0mMAwvNc+YHQvrI7ksg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-7M9LXSO+XhB/Y+9SwONHaiJqYSTlHMqOSqeWGpSNAQOZZd5P7z/FXyWmvL1OogVsghW0mMAwvNc+YHQvrI7ksg== }
+ engines: { node: '>=18' }
'@uniswap/v3-staker@1.0.0':
- resolution: {integrity: sha512-JV0Qc46Px5alvg6YWd+UIaGH9lDuYG/Js7ngxPit1SPaIP30AlVer1UYB7BRYeUVVxE+byUyIeN5jeQ7LLDjIw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-JV0Qc46Px5alvg6YWd+UIaGH9lDuYG/Js7ngxPit1SPaIP30AlVer1UYB7BRYeUVVxE+byUyIeN5jeQ7LLDjIw== }
+ engines: { node: '>=10' }
deprecated: Please upgrade to 1.0.1
'@uniswap/v4-sdk@1.27.0':
- resolution: {integrity: sha512-htQFiON12RR4BipyVdzr4XklYjy756bqruBLA8b4n9Wn7QAWemYrDGbnCvmk1xvzvtc4t9WggDlbRjZ5ON34+g==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-htQFiON12RR4BipyVdzr4XklYjy756bqruBLA8b4n9Wn7QAWemYrDGbnCvmk1xvzvtc4t9WggDlbRjZ5ON34+g== }
+ engines: { node: '>=14' }
'@uniswap/v4-sdk@2.3.0':
- resolution: {integrity: sha512-aMsDxVFjnwxjWeX8lXJy+4SRPgllfEU05SJ6CRsiPOeqBMd9RHxvb0RXF4q42wNG/iKoUVg9O2q6s5uoRDXPrQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-aMsDxVFjnwxjWeX8lXJy+4SRPgllfEU05SJ6CRsiPOeqBMd9RHxvb0RXF4q42wNG/iKoUVg9O2q6s5uoRDXPrQ== }
+ engines: { node: '>=18' }
'@unrs/resolver-binding-android-arm-eabi@1.9.2':
- resolution: {integrity: sha512-tS+lqTU3N0kkthU+rYp0spAYq15DU8ld9kXkaKg9sbQqJNF+WPMuNHZQGCgdxrUOEO0j22RKMwRVhF1HTl+X8A==}
+ resolution:
+ { integrity: sha512-tS+lqTU3N0kkthU+rYp0spAYq15DU8ld9kXkaKg9sbQqJNF+WPMuNHZQGCgdxrUOEO0j22RKMwRVhF1HTl+X8A== }
cpu: [arm]
os: [android]
'@unrs/resolver-binding-android-arm64@1.9.2':
- resolution: {integrity: sha512-MffGiZULa/KmkNjHeuuflLVqfhqLv1vZLm8lWIyeADvlElJ/GLSOkoUX+5jf4/EGtfwrNFcEaB8BRas03KT0/Q==}
+ resolution:
+ { integrity: sha512-MffGiZULa/KmkNjHeuuflLVqfhqLv1vZLm8lWIyeADvlElJ/GLSOkoUX+5jf4/EGtfwrNFcEaB8BRas03KT0/Q== }
cpu: [arm64]
os: [android]
'@unrs/resolver-binding-darwin-arm64@1.9.2':
- resolution: {integrity: sha512-dzJYK5rohS1sYl1DHdJ3mwfwClJj5BClQnQSyAgEfggbUwA9RlROQSSbKBLqrGfsiC/VyrDPtbO8hh56fnkbsQ==}
+ resolution:
+ { integrity: sha512-dzJYK5rohS1sYl1DHdJ3mwfwClJj5BClQnQSyAgEfggbUwA9RlROQSSbKBLqrGfsiC/VyrDPtbO8hh56fnkbsQ== }
cpu: [arm64]
os: [darwin]
'@unrs/resolver-binding-darwin-x64@1.9.2':
- resolution: {integrity: sha512-gaIMWK+CWtXcg9gUyznkdV54LzQ90S3X3dn8zlh+QR5Xy7Y+Efqw4Rs4im61K1juy4YNb67vmJsCDAGOnIeffQ==}
+ resolution:
+ { integrity: sha512-gaIMWK+CWtXcg9gUyznkdV54LzQ90S3X3dn8zlh+QR5Xy7Y+Efqw4Rs4im61K1juy4YNb67vmJsCDAGOnIeffQ== }
cpu: [x64]
os: [darwin]
'@unrs/resolver-binding-freebsd-x64@1.9.2':
- resolution: {integrity: sha512-S7QpkMbVoVJb0xwHFwujnwCAEDe/596xqY603rpi/ioTn9VDgBHnCCxh+UFrr5yxuMH+dliHfjwCZJXOPJGPnw==}
+ resolution:
+ { integrity: sha512-S7QpkMbVoVJb0xwHFwujnwCAEDe/596xqY603rpi/ioTn9VDgBHnCCxh+UFrr5yxuMH+dliHfjwCZJXOPJGPnw== }
cpu: [x64]
os: [freebsd]
'@unrs/resolver-binding-linux-arm-gnueabihf@1.9.2':
- resolution: {integrity: sha512-+XPUMCuCCI80I46nCDFbGum0ZODP5NWGiwS3Pj8fOgsG5/ctz+/zzuBlq/WmGa+EjWZdue6CF0aWWNv84sE1uw==}
+ resolution:
+ { integrity: sha512-+XPUMCuCCI80I46nCDFbGum0ZODP5NWGiwS3Pj8fOgsG5/ctz+/zzuBlq/WmGa+EjWZdue6CF0aWWNv84sE1uw== }
cpu: [arm]
os: [linux]
'@unrs/resolver-binding-linux-arm-musleabihf@1.9.2':
- resolution: {integrity: sha512-sqvUyAd1JUpwbz33Ce2tuTLJKM+ucSsYpPGl2vuFwZnEIg0CmdxiZ01MHQ3j6ExuRqEDUCy8yvkDKvjYFPb8Zg==}
+ resolution:
+ { integrity: sha512-sqvUyAd1JUpwbz33Ce2tuTLJKM+ucSsYpPGl2vuFwZnEIg0CmdxiZ01MHQ3j6ExuRqEDUCy8yvkDKvjYFPb8Zg== }
cpu: [arm]
os: [linux]
'@unrs/resolver-binding-linux-arm64-gnu@1.9.2':
- resolution: {integrity: sha512-UYA0MA8ajkEDCFRQdng/FVx3F6szBvk3EPnkTTQuuO9lV1kPGuTB+V9TmbDxy5ikaEgyWKxa4CI3ySjklZ9lFA==}
+ resolution:
+ { integrity: sha512-UYA0MA8ajkEDCFRQdng/FVx3F6szBvk3EPnkTTQuuO9lV1kPGuTB+V9TmbDxy5ikaEgyWKxa4CI3ySjklZ9lFA== }
cpu: [arm64]
os: [linux]
'@unrs/resolver-binding-linux-arm64-musl@1.9.2':
- resolution: {integrity: sha512-P/CO3ODU9YJIHFqAkHbquKtFst0COxdphc8TKGL5yCX75GOiVpGqd1d15ahpqu8xXVsqP4MGFP2C3LRZnnL5MA==}
+ resolution:
+ { integrity: sha512-P/CO3ODU9YJIHFqAkHbquKtFst0COxdphc8TKGL5yCX75GOiVpGqd1d15ahpqu8xXVsqP4MGFP2C3LRZnnL5MA== }
cpu: [arm64]
os: [linux]
'@unrs/resolver-binding-linux-ppc64-gnu@1.9.2':
- resolution: {integrity: sha512-uKStFlOELBxBum2s1hODPtgJhY4NxYJE9pAeyBgNEzHgTqTiVBPjfTlPFJkfxyTjQEuxZbbJlJnMCrRgD7ubzw==}
+ resolution:
+ { integrity: sha512-uKStFlOELBxBum2s1hODPtgJhY4NxYJE9pAeyBgNEzHgTqTiVBPjfTlPFJkfxyTjQEuxZbbJlJnMCrRgD7ubzw== }
cpu: [ppc64]
os: [linux]
'@unrs/resolver-binding-linux-riscv64-gnu@1.9.2':
- resolution: {integrity: sha512-LkbNnZlhINfY9gK30AHs26IIVEZ9PEl9qOScYdmY2o81imJYI4IMnJiW0vJVtXaDHvBvxeAgEy5CflwJFIl3tQ==}
+ resolution:
+ { integrity: sha512-LkbNnZlhINfY9gK30AHs26IIVEZ9PEl9qOScYdmY2o81imJYI4IMnJiW0vJVtXaDHvBvxeAgEy5CflwJFIl3tQ== }
cpu: [riscv64]
os: [linux]
'@unrs/resolver-binding-linux-riscv64-musl@1.9.2':
- resolution: {integrity: sha512-vI+e6FzLyZHSLFNomPi+nT+qUWN4YSj8pFtQZSFTtmgFoxqB6NyjxSjAxEC1m93qn6hUXhIsh8WMp+fGgxCoRg==}
+ resolution:
+ { integrity: sha512-vI+e6FzLyZHSLFNomPi+nT+qUWN4YSj8pFtQZSFTtmgFoxqB6NyjxSjAxEC1m93qn6hUXhIsh8WMp+fGgxCoRg== }
cpu: [riscv64]
os: [linux]
'@unrs/resolver-binding-linux-s390x-gnu@1.9.2':
- resolution: {integrity: sha512-sSO4AlAYhSM2RAzBsRpahcJB1msc6uYLAtP6pesPbZtptF8OU/CbCPhSRW6cnYOGuVmEmWVW5xVboAqCnWTeHQ==}
+ resolution:
+ { integrity: sha512-sSO4AlAYhSM2RAzBsRpahcJB1msc6uYLAtP6pesPbZtptF8OU/CbCPhSRW6cnYOGuVmEmWVW5xVboAqCnWTeHQ== }
cpu: [s390x]
os: [linux]
'@unrs/resolver-binding-linux-x64-gnu@1.9.2':
- resolution: {integrity: sha512-jkSkwch0uPFva20Mdu8orbQjv2A3G88NExTN2oPTI1AJ+7mZfYW3cDCTyoH6OnctBKbBVeJCEqh0U02lTkqD5w==}
+ resolution:
+ { integrity: sha512-jkSkwch0uPFva20Mdu8orbQjv2A3G88NExTN2oPTI1AJ+7mZfYW3cDCTyoH6OnctBKbBVeJCEqh0U02lTkqD5w== }
cpu: [x64]
os: [linux]
'@unrs/resolver-binding-linux-x64-musl@1.9.2':
- resolution: {integrity: sha512-Uk64NoiTpQbkpl+bXsbeyOPRpUoMdcUqa+hDC1KhMW7aN1lfW8PBlBH4mJ3n3Y47dYE8qi0XTxy1mBACruYBaw==}
+ resolution:
+ { integrity: sha512-Uk64NoiTpQbkpl+bXsbeyOPRpUoMdcUqa+hDC1KhMW7aN1lfW8PBlBH4mJ3n3Y47dYE8qi0XTxy1mBACruYBaw== }
cpu: [x64]
os: [linux]
'@unrs/resolver-binding-wasm32-wasi@1.9.2':
- resolution: {integrity: sha512-EpBGwkcjDicjR/ybC0g8wO5adPNdVuMrNalVgYcWi+gYtC1XYNuxe3rufcO7dA76OHGeVabcO6cSkPJKVcbCXQ==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-EpBGwkcjDicjR/ybC0g8wO5adPNdVuMrNalVgYcWi+gYtC1XYNuxe3rufcO7dA76OHGeVabcO6cSkPJKVcbCXQ== }
+ engines: { node: '>=14.0.0' }
cpu: [wasm32]
'@unrs/resolver-binding-win32-arm64-msvc@1.9.2':
- resolution: {integrity: sha512-EdFbGn7o1SxGmN6aZw9wAkehZJetFPao0VGZ9OMBwKx6TkvDuj6cNeLimF/Psi6ts9lMOe+Dt6z19fZQ9Ye2fw==}
+ resolution:
+ { integrity: sha512-EdFbGn7o1SxGmN6aZw9wAkehZJetFPao0VGZ9OMBwKx6TkvDuj6cNeLimF/Psi6ts9lMOe+Dt6z19fZQ9Ye2fw== }
cpu: [arm64]
os: [win32]
'@unrs/resolver-binding-win32-ia32-msvc@1.9.2':
- resolution: {integrity: sha512-JY9hi1p7AG+5c/dMU8o2kWemM8I6VZxfGwn1GCtf3c5i+IKcMo2NQ8OjZ4Z3/itvY/Si3K10jOBQn7qsD/whUA==}
+ resolution:
+ { integrity: sha512-JY9hi1p7AG+5c/dMU8o2kWemM8I6VZxfGwn1GCtf3c5i+IKcMo2NQ8OjZ4Z3/itvY/Si3K10jOBQn7qsD/whUA== }
cpu: [ia32]
os: [win32]
'@unrs/resolver-binding-win32-x64-msvc@1.9.2':
- resolution: {integrity: sha512-ryoo+EB19lMxAd80ln9BVf8pdOAxLb97amrQ3SFN9OCRn/5M5wvwDgAe4i8ZjhpbiHoDeP8yavcTEnpKBo7lZg==}
+ resolution:
+ { integrity: sha512-ryoo+EB19lMxAd80ln9BVf8pdOAxLb97amrQ3SFN9OCRn/5M5wvwDgAe4i8ZjhpbiHoDeP8yavcTEnpKBo7lZg== }
cpu: [x64]
os: [win32]
'@wallet-standard/base@1.1.0':
- resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ== }
+ engines: { node: '>=16' }
'@wallet-standard/features@1.1.0':
- resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg== }
+ engines: { node: '>=16' }
abitype@1.0.8:
- resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==}
+ resolution:
+ { integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== }
peerDependencies:
typescript: '>=5.0.4'
zod: ^3 >=3.22.0
@@ -2931,7 +3516,8 @@ packages:
optional: true
abitype@1.0.9:
- resolution: {integrity: sha512-oN0S++TQmlwWuB+rkA6aiEefLv3SP+2l/tC5mux/TLj6qdA6rF15Vbpex4fHovLsMkwLwTIRj8/Q8vXCS3GfOg==}
+ resolution:
+ { integrity: sha512-oN0S++TQmlwWuB+rkA6aiEefLv3SP+2l/tC5mux/TLj6qdA6rF15Vbpex4fHovLsMkwLwTIRj8/Q8vXCS3GfOg== }
peerDependencies:
typescript: '>=5.0.4'
zod: ^3 >=3.22.0
@@ -2942,55 +3528,68 @@ packages:
optional: true
abort-controller@3.0.0:
- resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
- engines: {node: '>=6.5'}
+ resolution:
+ { integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== }
+ engines: { node: '>=6.5' }
abstract-level@1.0.4:
- resolution: {integrity: sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg== }
+ engines: { node: '>=12' }
abstract-logging@2.0.1:
- resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
+ resolution:
+ { integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== }
accepts@1.3.8:
- resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== }
+ engines: { node: '>= 0.6' }
acorn-jsx@5.3.2:
- resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ resolution:
+ { integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== }
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn-walk@8.3.4:
- resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
- engines: {node: '>=0.4.0'}
+ resolution:
+ { integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== }
+ engines: { node: '>=0.4.0' }
acorn@8.14.1:
- resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
- engines: {node: '>=0.4.0'}
+ resolution:
+ { integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== }
+ engines: { node: '>=0.4.0' }
hasBin: true
adm-zip@0.4.16:
- resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==}
- engines: {node: '>=0.3.0'}
+ resolution:
+ { integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== }
+ engines: { node: '>=0.3.0' }
aes-js@3.0.0:
- resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==}
+ resolution:
+ { integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== }
agent-base@6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
+ resolution:
+ { integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== }
+ engines: { node: '>= 6.0.0' }
agentkeepalive@4.6.0:
- resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
- engines: {node: '>= 8.0.0'}
+ resolution:
+ { integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== }
+ engines: { node: '>= 8.0.0' }
aggregate-error@3.1.0:
- resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== }
+ engines: { node: '>=8' }
ajv-formats@2.1.1:
- resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
+ resolution:
+ { integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== }
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta:
@@ -2998,7 +3597,8 @@ packages:
optional: true
ajv-formats@3.0.1:
- resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ resolution:
+ { integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== }
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta:
@@ -3006,755 +3606,962 @@ packages:
optional: true
ajv@6.12.6:
- resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ resolution:
+ { integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== }
ajv@8.17.1:
- resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
+ resolution:
+ { integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== }
algo-msgpack-with-bigint@2.1.1:
- resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==}
- engines: {node: '>= 10'}
+ resolution:
+ { integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ== }
+ engines: { node: '>= 10' }
algosdk@1.24.1:
- resolution: {integrity: sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww== }
+ engines: { node: '>=14.0.0' }
ansi-align@3.0.1:
- resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+ resolution:
+ { integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== }
ansi-colors@4.1.3:
- resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== }
+ engines: { node: '>=6' }
ansi-escapes@4.3.2:
- resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== }
+ engines: { node: '>=8' }
ansi-escapes@7.0.0:
- resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== }
+ engines: { node: '>=18' }
ansi-regex@3.0.1:
- resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== }
+ engines: { node: '>=4' }
ansi-regex@4.1.1:
- resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== }
+ engines: { node: '>=6' }
ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== }
+ engines: { node: '>=8' }
ansi-regex@6.1.0:
- resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== }
+ engines: { node: '>=12' }
ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== }
+ engines: { node: '>=4' }
ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== }
+ engines: { node: '>=8' }
ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== }
+ engines: { node: '>=10' }
ansi-styles@6.2.1:
- resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== }
+ engines: { node: '>=12' }
ansicolors@0.3.2:
- resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==}
+ resolution:
+ { integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== }
anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== }
+ engines: { node: '>= 8' }
app-root-path@3.1.0:
- resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==}
- engines: {node: '>= 6.0.0'}
+ resolution:
+ { integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== }
+ engines: { node: '>= 6.0.0' }
arbundles@0.6.23:
- resolution: {integrity: sha512-+gr93F3fivN+6dhiImT6BQNaXz4oECPn2GYjCZjS2yEoq7hM78FRvVp6kQyjEdhnuBFQr/q4oS/nkjnQlHdj9Q==}
+ resolution:
+ { integrity: sha512-+gr93F3fivN+6dhiImT6BQNaXz4oECPn2GYjCZjS2yEoq7hM78FRvVp6kQyjEdhnuBFQr/q4oS/nkjnQlHdj9Q== }
arconnect@0.4.2:
- resolution: {integrity: sha512-Jkpd4QL3TVqnd3U683gzXmZUVqBUy17DdJDuL/3D9rkysLgX6ymJ2e+sR+xyZF5Rh42CBqDXWNMmCjBXeP7Gbw==}
+ resolution:
+ { integrity: sha512-Jkpd4QL3TVqnd3U683gzXmZUVqBUy17DdJDuL/3D9rkysLgX6ymJ2e+sR+xyZF5Rh42CBqDXWNMmCjBXeP7Gbw== }
arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+ resolution:
+ { integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== }
arg@5.0.2:
- resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ resolution:
+ { integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== }
argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ resolution:
+ { integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== }
argparse@2.0.1:
- resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ resolution:
+ { integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== }
arr-diff@4.0.0:
- resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== }
+ engines: { node: '>=0.10.0' }
arr-flatten@1.1.0:
- resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== }
+ engines: { node: '>=0.10.0' }
arr-union@3.1.0:
- resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== }
+ engines: { node: '>=0.10.0' }
array-buffer-byte-length@1.0.2:
- resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== }
+ engines: { node: '>= 0.4' }
array-flatten@1.1.1:
- resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+ resolution:
+ { integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== }
array-includes@3.1.8:
- resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== }
+ engines: { node: '>= 0.4' }
array-union@2.1.0:
- resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== }
+ engines: { node: '>=8' }
array-unique@0.3.2:
- resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== }
+ engines: { node: '>=0.10.0' }
array.prototype.findlastindex@1.2.6:
- resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== }
+ engines: { node: '>= 0.4' }
array.prototype.flat@1.3.3:
- resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== }
+ engines: { node: '>= 0.4' }
array.prototype.flatmap@1.3.3:
- resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== }
+ engines: { node: '>= 0.4' }
arraybuffer.prototype.slice@1.0.4:
- resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== }
+ engines: { node: '>= 0.4' }
arweave-stream-tx@1.2.2:
- resolution: {integrity: sha512-bNt9rj0hbAEzoUZEF2s6WJbIz8nasZlZpxIw03Xm8fzb9gRiiZlZGW3lxQLjfc9Z0VRUWDzwtqoYeEoB/JDToQ==}
+ resolution:
+ { integrity: sha512-bNt9rj0hbAEzoUZEF2s6WJbIz8nasZlZpxIw03Xm8fzb9gRiiZlZGW3lxQLjfc9Z0VRUWDzwtqoYeEoB/JDToQ== }
peerDependencies:
arweave: ^1.10.0
arweave@1.15.7:
- resolution: {integrity: sha512-F+Y4iWU1qea9IsKQ/YNmLsY4DHQVsaJBuhEbFxQn9cfGHOmtXE+bwo14oY8xqymsqSNf/e1PeIfLk7G7qN/hVA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-F+Y4iWU1qea9IsKQ/YNmLsY4DHQVsaJBuhEbFxQn9cfGHOmtXE+bwo14oY8xqymsqSNf/e1PeIfLk7G7qN/hVA== }
+ engines: { node: '>=18' }
asn1.js@5.4.1:
- resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
+ resolution:
+ { integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== }
assert@2.1.0:
- resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
+ resolution:
+ { integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== }
assertion-error@1.1.0:
- resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ resolution:
+ { integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== }
assign-symbols@1.0.0:
- resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== }
+ engines: { node: '>=0.10.0' }
astral-regex@2.0.0:
- resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== }
+ engines: { node: '>=8' }
async-function@1.0.0:
- resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== }
+ engines: { node: '>= 0.4' }
async-retry@1.3.3:
- resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
+ resolution:
+ { integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== }
async@3.2.6:
- resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+ resolution:
+ { integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== }
asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ resolution:
+ { integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== }
atob@2.1.2:
- resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
- engines: {node: '>= 4.5.0'}
+ resolution:
+ { integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== }
+ engines: { node: '>= 4.5.0' }
hasBin: true
atomic-sleep@1.0.0:
- resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ { integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== }
+ engines: { node: '>=8.0.0' }
available-typed-arrays@1.0.7:
- resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== }
+ engines: { node: '>= 0.4' }
avsc@https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef:
- resolution: {tarball: https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef}
+ resolution: { tarball: https://codeload.github.com/Irys-xyz/avsc/tar.gz/a730cc8018b79e114b6a3381bbb57760a24c6cef }
version: 5.4.7
- engines: {node: '>=0.11'}
+ engines: { node: '>=0.11' }
avvio@8.4.0:
- resolution: {integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==}
+ resolution:
+ { integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA== }
await-timeout@1.1.1:
- resolution: {integrity: sha512-gsDXAS6XVc4Jt+7S92MPX6Noq69bdeXUPEaXd8dk3+yVr629LTDLxNt4j1ycBbrU+AStK2PhKIyNIM+xzWMVOQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-gsDXAS6XVc4Jt+7S92MPX6Noq69bdeXUPEaXd8dk3+yVr629LTDLxNt4j1ycBbrU+AStK2PhKIyNIM+xzWMVOQ== }
+ engines: { node: '>=6' }
axios@1.12.0:
- resolution: {integrity: sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==}
+ resolution:
+ { integrity: sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg== }
babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
peerDependencies:
'@babel/core': ^7.8.0
babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== }
+ engines: { node: '>=8' }
babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
babel-preset-current-node-syntax@1.1.0:
- resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}
+ resolution:
+ { integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== }
peerDependencies:
'@babel/core': ^7.0.0
babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
peerDependencies:
'@babel/core': ^7.0.0
balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ resolution:
+ { integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== }
base-x@3.0.11:
- resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==}
+ resolution:
+ { integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== }
base-x@4.0.1:
- resolution: {integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==}
+ resolution:
+ { integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw== }
base64-js@1.5.1:
- resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ resolution:
+ { integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== }
base64-sol@1.0.1:
- resolution: {integrity: sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg==}
+ resolution:
+ { integrity: sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== }
base64url@3.0.1:
- resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== }
+ engines: { node: '>=6.0.0' }
base@0.11.2:
- resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== }
+ engines: { node: '>=0.10.0' }
bech32@1.1.4:
- resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==}
+ resolution:
+ { integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== }
big.js@5.2.2:
- resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
+ resolution:
+ { integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== }
big.js@6.2.2:
- resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==}
+ resolution:
+ { integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ== }
bigint-buffer@1.1.5:
- resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==}
- engines: {node: '>= 10.0.0'}
+ resolution:
+ { integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== }
+ engines: { node: '>= 10.0.0' }
bignumber.js@9.3.0:
- resolution: {integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==}
+ resolution:
+ { integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA== }
binary-extensions@2.3.0:
- resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== }
+ engines: { node: '>=8' }
bindings@1.5.0:
- resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
+ resolution:
+ { integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== }
bip32-path@0.4.2:
- resolution: {integrity: sha512-ZBMCELjJfcNMkz5bDuJ1WrYvjlhEF5k6mQ8vUr4N7MbVRsXei7ZOg8VhhwMfNiW68NWmLkgkc6WvTickrLGprQ==}
+ resolution:
+ { integrity: sha512-ZBMCELjJfcNMkz5bDuJ1WrYvjlhEF5k6mQ8vUr4N7MbVRsXei7ZOg8VhhwMfNiW68NWmLkgkc6WvTickrLGprQ== }
bip39-light@1.0.7:
- resolution: {integrity: sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==}
+ resolution:
+ { integrity: sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q== }
bip39@3.0.2:
- resolution: {integrity: sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==}
+ resolution:
+ { integrity: sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ== }
bl@4.1.0:
- resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ resolution:
+ { integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== }
blakejs@1.2.1:
- resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==}
+ resolution:
+ { integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== }
bluebird@3.7.2:
- resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+ resolution:
+ { integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== }
bn.js@5.2.1:
- resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==}
+ resolution:
+ { integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== }
body-parser@1.20.3:
- resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ resolution:
+ { integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== }
+ engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 }
borsh@0.6.0:
- resolution: {integrity: sha512-sl5k89ViqsThXQpYa9XDtz1sBl3l1lI313cFUY1HKr+wvMILnb+58xpkqTNrYbelh99dY7K8usxoCusQmqix9Q==}
+ resolution:
+ { integrity: sha512-sl5k89ViqsThXQpYa9XDtz1sBl3l1lI313cFUY1HKr+wvMILnb+58xpkqTNrYbelh99dY7K8usxoCusQmqix9Q== }
borsh@0.7.0:
- resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==}
+ resolution:
+ { integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== }
bowser@2.11.0:
- resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
+ resolution:
+ { integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== }
boxen@5.1.2:
- resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== }
+ engines: { node: '>=10' }
brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ resolution:
+ { integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== }
brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ resolution:
+ { integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== }
braces@2.3.2:
- resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== }
+ engines: { node: '>=0.10.0' }
braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== }
+ engines: { node: '>=8' }
brorand@1.1.0:
- resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
+ resolution:
+ { integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== }
brotli@1.3.2:
- resolution: {integrity: sha512-K0HNa0RRpUpcF8yS4yNSd6vmkrvA+wRd+symIcwhfqGLAi7YgGlKfO4oDYVgiahiLGNviO9uY7Zlb1MCPeTmSA==}
+ resolution:
+ { integrity: sha512-K0HNa0RRpUpcF8yS4yNSd6vmkrvA+wRd+symIcwhfqGLAi7YgGlKfO4oDYVgiahiLGNviO9uY7Zlb1MCPeTmSA== }
browser-level@1.0.1:
- resolution: {integrity: sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==}
+ resolution:
+ { integrity: sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== }
browser-stdout@1.3.1:
- resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==}
+ resolution:
+ { integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== }
browserify-aes@1.2.0:
- resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==}
+ resolution:
+ { integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== }
browserslist@4.24.5:
- resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ resolution:
+ { integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== }
+ engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
hasBin: true
bs-logger@0.2.6:
- resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== }
+ engines: { node: '>= 6' }
bs58@4.0.1:
- resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==}
+ resolution:
+ { integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== }
bs58@5.0.0:
- resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==}
+ resolution:
+ { integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== }
bs58check@2.1.2:
- resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==}
+ resolution:
+ { integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== }
bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+ resolution:
+ { integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== }
buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ resolution:
+ { integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== }
buffer-layout@1.2.2:
- resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==}
- engines: {node: '>=4.5'}
+ resolution:
+ { integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== }
+ engines: { node: '>=4.5' }
buffer-reverse@1.0.1:
- resolution: {integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==}
+ resolution:
+ { integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== }
buffer-xor@1.0.3:
- resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==}
+ resolution:
+ { integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== }
buffer@5.7.1:
- resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ resolution:
+ { integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== }
buffer@6.0.3:
- resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+ resolution:
+ { integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== }
bufferutil@4.0.9:
- resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==}
- engines: {node: '>=6.14.2'}
+ resolution:
+ { integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== }
+ engines: { node: '>=6.14.2' }
bufio@1.2.3:
- resolution: {integrity: sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ { integrity: sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA== }
+ engines: { node: '>=8.0.0' }
builtin-modules@3.3.0:
- resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== }
+ engines: { node: '>=6' }
builtins@5.1.0:
- resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==}
+ resolution:
+ { integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg== }
bunyan-blackhole@1.1.1:
- resolution: {integrity: sha512-UwzNPhbbSqbzeJhCbygqjlAY7p0ZUdv1ADXPQvDh3CA7VW3C/rCc1gaQO/8j9QL4vsKQCQZQSQIEwX+lxioPAQ==}
+ resolution:
+ { integrity: sha512-UwzNPhbbSqbzeJhCbygqjlAY7p0ZUdv1ADXPQvDh3CA7VW3C/rCc1gaQO/8j9QL4vsKQCQZQSQIEwX+lxioPAQ== }
peerDependencies:
bunyan: ~1.x.x
bunyan@1.8.15:
- resolution: {integrity: sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==}
- engines: {'0': node >=0.10.0}
+ resolution:
+ { integrity: sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig== }
+ engines: { '0': node >=0.10.0 }
hasBin: true
bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== }
+ engines: { node: '>= 0.8' }
cache-base@1.0.1:
- resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== }
+ engines: { node: '>=0.10.0' }
call-bind-apply-helpers@1.0.2:
- resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== }
+ engines: { node: '>= 0.4' }
call-bind@1.0.8:
- resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== }
+ engines: { node: '>= 0.4' }
call-bound@1.0.4:
- resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== }
+ engines: { node: '>= 0.4' }
callsites@3.1.0:
- resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== }
+ engines: { node: '>=6' }
camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== }
+ engines: { node: '>=6' }
camelcase@6.3.0:
- resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== }
+ engines: { node: '>=10' }
caniuse-lite@1.0.30001717:
- resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==}
+ resolution:
+ { integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw== }
capability@0.2.5:
- resolution: {integrity: sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==}
+ resolution:
+ { integrity: sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg== }
catering@2.1.1:
- resolution: {integrity: sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== }
+ engines: { node: '>=6' }
chai@4.5.0:
- resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== }
+ engines: { node: '>=4' }
chain@0.4.2:
- resolution: {integrity: sha512-GtM+TlN398yBhtSp1D2dBLQomKM3Umbji3h2/NdCqAWSMKhWbjlz33j0e55rStsEZD+8OLRHuz7kWd0U3xKMDg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-GtM+TlN398yBhtSp1D2dBLQomKM3Umbji3h2/NdCqAWSMKhWbjlz33j0e55rStsEZD+8OLRHuz7kWd0U3xKMDg== }
+ engines: { node: '>=18' }
chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== }
+ engines: { node: '>=4' }
chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== }
+ engines: { node: '>=10' }
chalk@5.6.0:
- resolution: {integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ resolution:
+ { integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ== }
+ engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
chalk@5.6.2:
- resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+ resolution:
+ { integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== }
+ engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== }
+ engines: { node: '>=10' }
chardet@0.7.0:
- resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
+ resolution:
+ { integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== }
check-error@1.0.3:
- resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+ resolution:
+ { integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== }
check-more-types@2.24.0:
- resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== }
+ engines: { node: '>= 0.8.0' }
chokidar@3.6.0:
- resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
- engines: {node: '>= 8.10.0'}
+ resolution:
+ { integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== }
+ engines: { node: '>= 8.10.0' }
chokidar@4.0.3:
- resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
- engines: {node: '>= 14.16.0'}
+ resolution:
+ { integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== }
+ engines: { node: '>= 14.16.0' }
chownr@1.1.4:
- resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ resolution:
+ { integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== }
ci-info@2.0.0:
- resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
+ resolution:
+ { integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== }
ci-info@3.9.0:
- resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== }
+ engines: { node: '>=8' }
cipher-base@1.0.6:
- resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==}
- engines: {node: '>= 0.10'}
+ resolution:
+ { integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== }
+ engines: { node: '>= 0.10' }
cjs-module-lexer@1.4.3:
- resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
+ resolution:
+ { integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== }
class-utils@0.3.6:
- resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== }
+ engines: { node: '>=0.10.0' }
classic-level@1.4.1:
- resolution: {integrity: sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ== }
+ engines: { node: '>=12' }
clean-stack@2.2.0:
- resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== }
+ engines: { node: '>=6' }
cli-boxes@2.2.1:
- resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== }
+ engines: { node: '>=6' }
cli-cursor@3.1.0:
- resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== }
+ engines: { node: '>=8' }
cli-cursor@5.0.0:
- resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== }
+ engines: { node: '>=18' }
cli-spinners@2.9.2:
- resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== }
+ engines: { node: '>=6' }
cli-truncate@4.0.0:
- resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== }
+ engines: { node: '>=18' }
cli-width@3.0.0:
- resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
- engines: {node: '>= 10'}
+ resolution:
+ { integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== }
+ engines: { node: '>= 10' }
cliui@7.0.4:
- resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+ resolution:
+ { integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== }
cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== }
+ engines: { node: '>=12' }
clone@1.0.4:
- resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
- engines: {node: '>=0.8'}
+ resolution:
+ { integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== }
+ engines: { node: '>=0.8' }
clone@2.1.2:
- resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
- engines: {node: '>=0.8'}
+ resolution:
+ { integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== }
+ engines: { node: '>=0.8' }
co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
+ resolution:
+ { integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== }
+ engines: { iojs: '>= 1.0.0', node: '>= 0.12.0' }
collect-v8-coverage@1.0.2:
- resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
+ resolution:
+ { integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== }
collection-visit@1.0.0:
- resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== }
+ engines: { node: '>=0.10.0' }
color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ resolution:
+ { integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== }
color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
+ resolution:
+ { integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== }
+ engines: { node: '>=7.0.0' }
color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+ resolution:
+ { integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== }
color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ resolution:
+ { integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== }
color-string@1.9.1:
- resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+ resolution:
+ { integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== }
color@3.2.1:
- resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
+ resolution:
+ { integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== }
colorette@2.0.20:
- resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+ resolution:
+ { integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== }
colorspace@1.1.4:
- resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
+ resolution:
+ { integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== }
combined-stream@1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== }
+ engines: { node: '>= 0.8' }
command-exists@1.2.9:
- resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==}
+ resolution:
+ { integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== }
commander@12.1.0:
- resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== }
+ engines: { node: '>=18' }
commander@13.1.0:
- resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== }
+ engines: { node: '>=18' }
commander@14.0.0:
- resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
- engines: {node: '>=20'}
+ resolution:
+ { integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA== }
+ engines: { node: '>=20' }
commander@14.0.1:
- resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==}
- engines: {node: '>=20'}
+ resolution:
+ { integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A== }
+ engines: { node: '>=20' }
commander@14.0.2:
- resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==}
- engines: {node: '>=20'}
+ resolution:
+ { integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== }
+ engines: { node: '>=20' }
commander@2.20.3:
- resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+ resolution:
+ { integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== }
commander@8.3.0:
- resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
- engines: {node: '>= 12'}
+ resolution:
+ { integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== }
+ engines: { node: '>= 12' }
commander@9.5.0:
- resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
- engines: {node: ^12.20.0 || >=14}
+ resolution:
+ { integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== }
+ engines: { node: ^12.20.0 || >=14 }
complex.js@2.4.2:
- resolution: {integrity: sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==}
+ resolution:
+ { integrity: sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g== }
component-emitter@1.3.1:
- resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
+ resolution:
+ { integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== }
concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ resolution:
+ { integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== }
content-disposition@0.5.4:
- resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== }
+ engines: { node: '>= 0.6' }
content-type@1.0.5:
- resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== }
+ engines: { node: '>= 0.6' }
convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ resolution:
+ { integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== }
cookie-signature@1.0.6:
- resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+ resolution:
+ { integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== }
cookie@0.4.2:
- resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== }
+ engines: { node: '>= 0.6' }
cookie@0.7.1:
- resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== }
+ engines: { node: '>= 0.6' }
cookie@0.7.2:
- resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== }
+ engines: { node: '>= 0.6' }
copy-descriptor@0.1.1:
- resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== }
+ engines: { node: '>=0.10.0' }
copyfiles@2.4.1:
- resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==}
+ resolution:
+ { integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== }
hasBin: true
core-util-is@1.0.3:
- resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ resolution:
+ { integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== }
create-hash@1.1.3:
- resolution: {integrity: sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==}
+ resolution:
+ { integrity: sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA== }
create-hash@1.2.0:
- resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==}
+ resolution:
+ { integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== }
create-hmac@1.1.7:
- resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==}
+ resolution:
+ { integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== }
create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
hasBin: true
create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+ resolution:
+ { integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== }
cross-fetch@3.0.6:
- resolution: {integrity: sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==}
+ resolution:
+ { integrity: sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== }
cross-fetch@3.2.0:
- resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==}
+ resolution:
+ { integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q== }
cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== }
+ engines: { node: '>= 8' }
crypto-hash@1.3.0:
- resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== }
+ engines: { node: '>=8' }
crypto-js@4.2.0:
- resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+ resolution:
+ { integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== }
csv-generate@4.4.2:
- resolution: {integrity: sha512-W6nVsf+rz0J3yo9FOjeer7tmzBJKaTTxf7K0uw6GZgRocZYPVpuSWWa5/aoWWrjQZj4/oNIKTYapOM7hiNjVMA==}
+ resolution:
+ { integrity: sha512-W6nVsf+rz0J3yo9FOjeer7tmzBJKaTTxf7K0uw6GZgRocZYPVpuSWWa5/aoWWrjQZj4/oNIKTYapOM7hiNjVMA== }
csv-parse@5.6.0:
- resolution: {integrity: sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==}
+ resolution:
+ { integrity: sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q== }
csv-stringify@6.5.2:
- resolution: {integrity: sha512-RFPahj0sXcmUyjrObAK+DOWtMvMIFV328n4qZJhgX3x2RqkQgOTU2mCUmiFR0CzM6AzChlRSUErjiJeEt8BaQA==}
+ resolution:
+ { integrity: sha512-RFPahj0sXcmUyjrObAK+DOWtMvMIFV328n4qZJhgX3x2RqkQgOTU2mCUmiFR0CzM6AzChlRSUErjiJeEt8BaQA== }
csv@6.3.11:
- resolution: {integrity: sha512-a8bhT76Q546jOElHcTrkzWY7Py925mfLO/jqquseH61ThOebYwOjLbWHBqdRB4K1VpU36sTyIei6Jwj7QdEZ7g==}
- engines: {node: '>= 0.1.90'}
+ resolution:
+ { integrity: sha512-a8bhT76Q546jOElHcTrkzWY7Py925mfLO/jqquseH61ThOebYwOjLbWHBqdRB4K1VpU36sTyIei6Jwj7QdEZ7g== }
+ engines: { node: '>= 0.1.90' }
data-view-buffer@1.0.2:
- resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== }
+ engines: { node: '>= 0.4' }
data-view-byte-length@1.0.2:
- resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== }
+ engines: { node: '>= 0.4' }
data-view-byte-offset@1.0.1:
- resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== }
+ engines: { node: '>= 0.4' }
dateformat@4.6.3:
- resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
+ resolution:
+ { integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== }
dayjs@1.11.13:
- resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+ resolution:
+ { integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== }
debug@2.6.9:
- resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ resolution:
+ { integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -3762,7 +4569,8 @@ packages:
optional: true
debug@3.2.7:
- resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ resolution:
+ { integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -3770,8 +4578,9 @@ packages:
optional: true
debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
+ resolution:
+ { integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== }
+ engines: { node: '>=6.0' }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -3779,8 +4588,9 @@ packages:
optional: true
debug@4.4.0:
- resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
- engines: {node: '>=6.0'}
+ resolution:
+ { integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== }
+ engines: { node: '>=6.0' }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -3788,8 +4598,9 @@ packages:
optional: true
debug@4.4.1:
- resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
- engines: {node: '>=6.0'}
+ resolution:
+ { integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== }
+ engines: { node: '>=6.0' }
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
@@ -3797,25 +4608,31 @@ packages:
optional: true
decamelize@4.0.0:
- resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== }
+ engines: { node: '>=10' }
decimal.js-light@2.5.1:
- resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
+ resolution:
+ { integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== }
decimal.js@10.5.0:
- resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
+ resolution:
+ { integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== }
decode-uri-component@0.2.2:
- resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
- engines: {node: '>=0.10'}
+ resolution:
+ { integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== }
+ engines: { node: '>=0.10' }
decompress-response@6.0.0:
- resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== }
+ engines: { node: '>=10' }
dedent@1.6.0:
- resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==}
+ resolution:
+ { integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== }
peerDependencies:
babel-plugin-macros: ^3.1.0
peerDependenciesMeta:
@@ -3823,265 +4640,334 @@ packages:
optional: true
deep-eql@4.1.4:
- resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== }
+ engines: { node: '>=6' }
deep-extend@0.6.0:
- resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
- engines: {node: '>=4.0.0'}
+ resolution:
+ { integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== }
+ engines: { node: '>=4.0.0' }
deep-is@0.1.4:
- resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ resolution:
+ { integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== }
deepmerge@4.3.1:
- resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== }
+ engines: { node: '>=0.10.0' }
defaults@1.0.4:
- resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+ resolution:
+ { integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== }
define-data-property@1.1.4:
- resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== }
+ engines: { node: '>= 0.4' }
define-properties@1.2.1:
- resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== }
+ engines: { node: '>= 0.4' }
define-property@0.2.5:
- resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== }
+ engines: { node: '>=0.10.0' }
define-property@1.0.0:
- resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== }
+ engines: { node: '>=0.10.0' }
define-property@2.0.2:
- resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== }
+ engines: { node: '>=0.10.0' }
delay@5.0.0:
- resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== }
+ engines: { node: '>=10' }
delayed-stream@1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
+ resolution:
+ { integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== }
+ engines: { node: '>=0.4.0' }
depd@1.1.2:
- resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== }
+ engines: { node: '>= 0.6' }
depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== }
+ engines: { node: '>= 0.8' }
destroy@1.2.0:
- resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ resolution:
+ { integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== }
+ engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 }
detect-libc@2.0.4:
- resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== }
+ engines: { node: '>=8' }
detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== }
+ engines: { node: '>=8' }
diff-sequences@24.9.0:
- resolution: {integrity: sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== }
+ engines: { node: '>= 6' }
diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
+ resolution:
+ { integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== }
+ engines: { node: '>=0.3.1' }
diff@5.2.0:
- resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
- engines: {node: '>=0.3.1'}
+ resolution:
+ { integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== }
+ engines: { node: '>=0.3.1' }
dir-glob@3.0.1:
- resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== }
+ engines: { node: '>=8' }
doctrine@2.1.0:
- resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== }
+ engines: { node: '>=0.10.0' }
doctrine@3.0.0:
- resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== }
+ engines: { node: '>=6.0.0' }
dot-case@3.0.4:
- resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+ resolution:
+ { integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== }
dotenv@14.3.2:
- resolution: {integrity: sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ== }
+ engines: { node: '>=12' }
dotenv@16.5.0:
- resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg== }
+ engines: { node: '>=12' }
dtrace-provider@0.8.8:
- resolution: {integrity: sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==}
- engines: {node: '>=0.10'}
+ resolution:
+ { integrity: sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg== }
+ engines: { node: '>=0.10' }
dunder-proto@1.0.1:
- resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== }
+ engines: { node: '>= 0.4' }
duplexer@0.1.2:
- resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+ resolution:
+ { integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== }
eastasianwidth@0.2.0:
- resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+ resolution:
+ { integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== }
ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+ resolution:
+ { integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== }
eip55@2.1.1:
- resolution: {integrity: sha512-WcagVAmNu2Ww2cDUfzuWVntYwFxbvZ5MvIyLZpMjTTkjD6sCvkGOiS86jTppzu9/gWsc8isLHAeMBWK02OnZmA==}
+ resolution:
+ { integrity: sha512-WcagVAmNu2Ww2cDUfzuWVntYwFxbvZ5MvIyLZpMjTTkjD6sCvkGOiS86jTppzu9/gWsc8isLHAeMBWK02OnZmA== }
ejs@3.1.10:
- resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== }
+ engines: { node: '>=0.10.0' }
hasBin: true
electron-to-chromium@1.5.151:
- resolution: {integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA==}
+ resolution:
+ { integrity: sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA== }
elliptic@6.6.1:
- resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==}
+ resolution:
+ { integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== }
emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== }
+ engines: { node: '>=12' }
emoji-regex@10.4.0:
- resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
+ resolution:
+ { integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== }
emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ resolution:
+ { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== }
emoji-regex@9.2.2:
- resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ resolution:
+ { integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== }
enabled@2.0.0:
- resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
+ resolution:
+ { integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== }
encodeurl@1.0.2:
- resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== }
+ engines: { node: '>= 0.8' }
encodeurl@2.0.0:
- resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== }
+ engines: { node: '>= 0.8' }
encoding@0.1.13:
- resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
+ resolution:
+ { integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== }
end-of-stream@1.4.4:
- resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+ resolution:
+ { integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== }
enquirer@2.4.1:
- resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
- engines: {node: '>=8.6'}
+ resolution:
+ { integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== }
+ engines: { node: '>=8.6' }
env-paths@2.2.1:
- resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== }
+ engines: { node: '>=6' }
environment@1.1.0:
- resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== }
+ engines: { node: '>=18' }
error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ resolution:
+ { integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== }
error-polyfill@0.1.3:
- resolution: {integrity: sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==}
+ resolution:
+ { integrity: sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg== }
es-abstract@1.23.9:
- resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== }
+ engines: { node: '>= 0.4' }
es-define-property@1.0.1:
- resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== }
+ engines: { node: '>= 0.4' }
es-errors@1.3.0:
- resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== }
+ engines: { node: '>= 0.4' }
es-object-atoms@1.1.1:
- resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== }
+ engines: { node: '>= 0.4' }
es-set-tostringtag@2.1.0:
- resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== }
+ engines: { node: '>= 0.4' }
es-shim-unscopables@1.1.0:
- resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== }
+ engines: { node: '>= 0.4' }
es-to-primitive@1.3.0:
- resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== }
+ engines: { node: '>= 0.4' }
es6-promise@4.2.8:
- resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
+ resolution:
+ { integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== }
es6-promisify@5.0.0:
- resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==}
+ resolution:
+ { integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== }
esbuild@0.25.5:
- resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ== }
+ engines: { node: '>=18' }
hasBin: true
escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== }
+ engines: { node: '>=6' }
escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+ resolution:
+ { integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== }
escape-latex@1.2.0:
- resolution: {integrity: sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==}
+ resolution:
+ { integrity: sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw== }
escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
+ resolution:
+ { integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== }
+ engines: { node: '>=0.8.0' }
escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== }
+ engines: { node: '>=8' }
escape-string-regexp@4.0.0:
- resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== }
+ engines: { node: '>=10' }
eslint-compat-utils@0.5.1:
- resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q== }
+ engines: { node: '>=12' }
peerDependencies:
eslint: '>=6.0.0'
eslint-config-prettier@9.1.0:
- resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
+ resolution:
+ { integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== }
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
eslint-config-standard@17.1.0:
- resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== }
+ engines: { node: '>=12.0.0' }
peerDependencies:
eslint: ^8.0.1
eslint-plugin-import: ^2.25.2
@@ -4089,12 +4975,14 @@ packages:
eslint-plugin-promise: ^6.0.0
eslint-formatter-table@7.32.1:
- resolution: {integrity: sha512-JYC49hAJMNjLfbgXVeQHU6ngP0M8ThgXCHLGrncYB+R/RHEhRPnLxHjolTJdb7RdQ8zcCt2F7Mrt6Ou3PwMOHw==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ resolution:
+ { integrity: sha512-JYC49hAJMNjLfbgXVeQHU6ngP0M8ThgXCHLGrncYB+R/RHEhRPnLxHjolTJdb7RdQ8zcCt2F7Mrt6Ou3PwMOHw== }
+ engines: { node: ^10.12.0 || >=12.0.0 }
eslint-import-context@0.1.9:
- resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==}
- engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg== }
+ engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
peerDependencies:
unrs-resolver: ^1.0.0
peerDependenciesMeta:
@@ -4102,11 +4990,13 @@ packages:
optional: true
eslint-import-resolver-node@0.3.9:
- resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+ resolution:
+ { integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== }
eslint-import-resolver-typescript@4.4.3:
- resolution: {integrity: sha512-elVDn1eWKFrWlzxlWl9xMt8LltjKl161Ix50JFC50tHXI5/TRP32SNEqlJ/bo/HV+g7Rou/tlPQU2AcRtIhrOg==}
- engines: {node: ^16.17.0 || >=18.6.0}
+ resolution:
+ { integrity: sha512-elVDn1eWKFrWlzxlWl9xMt8LltjKl161Ix50JFC50tHXI5/TRP32SNEqlJ/bo/HV+g7Rou/tlPQU2AcRtIhrOg== }
+ engines: { node: ^16.17.0 || >=18.6.0 }
peerDependencies:
eslint: '*'
eslint-plugin-import: '*'
@@ -4118,8 +5008,9 @@ packages:
optional: true
eslint-module-utils@2.12.0:
- resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== }
+ engines: { node: '>=4' }
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
@@ -4139,14 +5030,16 @@ packages:
optional: true
eslint-plugin-es-x@7.8.0:
- resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ== }
+ engines: { node: ^14.18.0 || >=16.0.0 }
peerDependencies:
eslint: '>=8'
eslint-plugin-import@2.31.0:
- resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== }
+ engines: { node: '>=4' }
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9
@@ -4155,14 +5048,16 @@ packages:
optional: true
eslint-plugin-n@16.6.2:
- resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==}
- engines: {node: '>=16.0.0'}
+ resolution:
+ { integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== }
+ engines: { node: '>=16.0.0' }
peerDependencies:
eslint: '>=7.0.0'
eslint-plugin-prettier@5.4.0:
- resolution: {integrity: sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA== }
+ engines: { node: ^14.18.0 || >=16.0.0 }
peerDependencies:
'@types/eslint': '>=8.0.0'
eslint: '>=8.0.0'
@@ -4175,232 +5070,295 @@ packages:
optional: true
eslint-plugin-promise@6.6.0:
- resolution: {integrity: sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
eslint-plugin-security@2.1.1:
- resolution: {integrity: sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==}
+ resolution:
+ { integrity: sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w== }
eslint-scope@7.2.2:
- resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
eslint-visitor-keys@3.4.3:
- resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
eslint@8.57.1:
- resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== }
+ 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
espree@9.6.1:
- resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== }
+ engines: { node: '>=4' }
hasBin: true
esquery@1.6.0:
- resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
- engines: {node: '>=0.10'}
+ resolution:
+ { integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== }
+ engines: { node: '>=0.10' }
esrecurse@4.3.0:
- resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
- engines: {node: '>=4.0'}
+ resolution:
+ { integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== }
+ engines: { node: '>=4.0' }
estraverse@5.3.0:
- resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
- engines: {node: '>=4.0'}
+ resolution:
+ { integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== }
+ engines: { node: '>=4.0' }
esutils@2.0.3:
- resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== }
+ engines: { node: '>=0.10.0' }
etag@1.8.1:
- resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== }
+ engines: { node: '>= 0.6' }
ethereum-bloom-filters@1.2.0:
- resolution: {integrity: sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==}
+ resolution:
+ { integrity: sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== }
ethereum-cryptography@0.1.3:
- resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==}
+ resolution:
+ { integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== }
ethereum-cryptography@1.2.0:
- resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==}
+ resolution:
+ { integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== }
ethereum-cryptography@2.2.1:
- resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==}
+ resolution:
+ { integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== }
ethereumjs-util@7.1.5:
- resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== }
+ engines: { node: '>=10.0.0' }
ethers@5.8.0:
- resolution: {integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==}
+ resolution:
+ { integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg== }
ethjs-unit@0.1.6:
- resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==}
- engines: {node: '>=6.5.0', npm: '>=3'}
+ resolution:
+ { integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== }
+ engines: { node: '>=6.5.0', npm: '>=3' }
event-stream@3.3.4:
- resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
+ resolution:
+ { integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== }
event-target-shim@5.0.1:
- resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== }
+ engines: { node: '>=6' }
eventemitter3@4.0.7:
- resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ resolution:
+ { integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== }
eventemitter3@5.0.1:
- resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ resolution:
+ { integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== }
events@3.3.0:
- resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
- engines: {node: '>=0.8.x'}
+ resolution:
+ { integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== }
+ engines: { node: '>=0.8.x' }
evp_bytestokey@1.0.3:
- resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==}
+ resolution:
+ { integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== }
execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== }
+ engines: { node: '>=10' }
exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== }
+ engines: { node: '>= 0.8.0' }
expand-brackets@2.1.4:
- resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== }
+ engines: { node: '>=0.10.0' }
expand-template@2.0.3:
- resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== }
+ engines: { node: '>=6' }
expect@24.9.0:
- resolution: {integrity: sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== }
+ engines: { node: '>= 6' }
expect@29.7.0:
- resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
exponential-backoff@3.1.2:
- resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==}
+ resolution:
+ { integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA== }
express@4.21.2:
- resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
- engines: {node: '>= 0.10.0'}
+ resolution:
+ { integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== }
+ engines: { node: '>= 0.10.0' }
extend-shallow@2.0.1:
- resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== }
+ engines: { node: '>=0.10.0' }
extend-shallow@3.0.2:
- resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== }
+ engines: { node: '>=0.10.0' }
external-editor@3.1.0:
- resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== }
+ engines: { node: '>=4' }
extglob@2.0.4:
- resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== }
+ engines: { node: '>=0.10.0' }
extract-files@9.0.0:
- resolution: {integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==}
- engines: {node: ^10.17.0 || ^12.0.0 || >= 13.7.0}
+ resolution:
+ { integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== }
+ engines: { node: ^10.17.0 || ^12.0.0 || >= 13.7.0 }
eyes@0.1.8:
- resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==}
- engines: {node: '> 0.1.90'}
+ resolution:
+ { integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== }
+ engines: { node: '> 0.1.90' }
fast-content-type-parse@1.1.0:
- resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
+ resolution:
+ { integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ== }
fast-copy@3.0.2:
- resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
+ resolution:
+ { integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ== }
fast-decode-uri-component@1.0.1:
- resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
+ resolution:
+ { integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== }
fast-deep-equal@3.1.3:
- resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ resolution:
+ { integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== }
fast-diff@1.3.0:
- resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+ resolution:
+ { integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== }
fast-glob@3.3.3:
- resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
- engines: {node: '>=8.6.0'}
+ resolution:
+ { integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== }
+ engines: { node: '>=8.6.0' }
fast-json-stable-stringify@2.1.0:
- resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ resolution:
+ { integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== }
fast-json-stringify@5.16.1:
- resolution: {integrity: sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==}
+ resolution:
+ { integrity: sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g== }
fast-levenshtein@2.0.6:
- resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ resolution:
+ { integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== }
fast-querystring@1.1.2:
- resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
+ resolution:
+ { integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== }
fast-redact@3.5.0:
- resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== }
+ engines: { node: '>=6' }
fast-safe-stringify@2.1.1:
- resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ resolution:
+ { integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== }
fast-stable-stringify@1.0.0:
- resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==}
+ resolution:
+ { integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== }
fast-uri@2.4.0:
- resolution: {integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==}
+ resolution:
+ { integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA== }
fast-uri@3.0.6:
- resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
+ resolution:
+ { integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== }
fast-xml-parser@4.4.1:
- resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==}
+ resolution:
+ { integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw== }
hasBin: true
fastestsmallesttextencoderdecoder@1.0.22:
- resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==}
+ resolution:
+ { integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== }
fastify-plugin@3.0.1:
- resolution: {integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==}
+ resolution:
+ { integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA== }
fastify-plugin@4.5.1:
- resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==}
+ resolution:
+ { integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ== }
fastify-type-provider-zod@2.1.0:
- resolution: {integrity: sha512-p0plQyrxVR1IxJaOVbKRkduYh74HAS6Pm2szhFrc/vFdfIEu8UWo/cPFZCrcKyeo8ICjWbHH1zkx8lWw/ivpqg==}
+ resolution:
+ { integrity: sha512-p0plQyrxVR1IxJaOVbKRkduYh74HAS6Pm2szhFrc/vFdfIEu8UWo/cPFZCrcKyeo8ICjWbHH1zkx8lWw/ivpqg== }
peerDependencies:
fastify: ^4.0.0
zod: ^3.14.2
fastify@4.29.1:
- resolution: {integrity: sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==}
+ resolution:
+ { integrity: sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ== }
fastq@1.19.1:
- resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+ resolution:
+ { integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== }
fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+ resolution:
+ { integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== }
fdir@6.4.4:
- resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
+ resolution:
+ { integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg== }
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
@@ -4408,66 +5366,83 @@ packages:
optional: true
fecha@4.2.3:
- resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
+ resolution:
+ { integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== }
figures@3.2.0:
- resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== }
+ engines: { node: '>=8' }
file-entry-cache@6.0.1:
- resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ resolution:
+ { integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== }
+ engines: { node: ^10.12.0 || >=12.0.0 }
file-stream-rotator@0.6.1:
- resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==}
+ resolution:
+ { integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ== }
file-uri-to-path@1.0.0:
- resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+ resolution:
+ { integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== }
filelist@1.0.4:
- resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+ resolution:
+ { integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== }
fill-range@4.0.0:
- resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== }
+ engines: { node: '>=0.10.0' }
fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== }
+ engines: { node: '>=8' }
finalhandler@1.3.1:
- resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== }
+ engines: { node: '>= 0.8' }
find-my-way@8.2.2:
- resolution: {integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA== }
+ engines: { node: '>=14' }
find-up@4.1.0:
- resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== }
+ engines: { node: '>=8' }
find-up@5.0.0:
- resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== }
+ engines: { node: '>=10' }
flat-cache@3.2.0:
- resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ resolution:
+ { integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== }
+ engines: { node: ^10.12.0 || >=12.0.0 }
flat@5.0.2:
- resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
+ resolution:
+ { integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== }
hasBin: true
flatted@3.3.3:
- resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ resolution:
+ { integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== }
fn.name@1.1.0:
- resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
+ resolution:
+ { integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== }
follow-redirects@1.15.9:
- resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
- engines: {node: '>=4.0'}
+ resolution:
+ { integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== }
+ engines: { node: '>=4.0' }
peerDependencies:
debug: '*'
peerDependenciesMeta:
@@ -4475,208 +5450,261 @@ packages:
optional: true
for-each@0.3.5:
- resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== }
+ engines: { node: '>= 0.4' }
for-in@1.0.2:
- resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== }
+ engines: { node: '>=0.10.0' }
foreground-child@3.3.1:
- resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== }
+ engines: { node: '>=14' }
form-data@3.0.3:
- resolution: {integrity: sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w== }
+ engines: { node: '>= 6' }
form-data@4.0.2:
- resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== }
+ engines: { node: '>= 6' }
form-data@4.0.5:
- resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== }
+ engines: { node: '>= 6' }
forwarded@0.2.0:
- resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== }
+ engines: { node: '>= 0.6' }
fp-ts@1.19.3:
- resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==}
+ resolution:
+ { integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== }
fraction.js@4.3.7:
- resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+ resolution:
+ { integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== }
fragment-cache@0.2.1:
- resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== }
+ engines: { node: '>=0.10.0' }
fresh@0.5.2:
- resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== }
+ engines: { node: '>= 0.6' }
from@0.1.7:
- resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
+ resolution:
+ { integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== }
fs-constants@1.0.0:
- resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+ resolution:
+ { integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== }
fs-extra@10.1.0:
- resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== }
+ engines: { node: '>=12' }
fs-extra@7.0.1:
- resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
- engines: {node: '>=6 <7 || >=8'}
+ resolution:
+ { integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== }
+ engines: { node: '>=6 <7 || >=8' }
fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ resolution:
+ { integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== }
fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ resolution:
+ { integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== }
+ engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
os: [darwin]
function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ resolution:
+ { integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== }
function.prototype.name@1.1.8:
- resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== }
+ engines: { node: '>= 0.4' }
functions-have-names@1.2.3:
- resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ resolution:
+ { integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== }
gaussian@1.3.0:
- resolution: {integrity: sha512-rYQ0ESfB+z0t7G95nHH80Zh7Pgg9A0FUYoZqV0yPec5WJZWKIHV2MPYpiJNy8oZAeVqyKwC10WXKSCnUQ5iDVg==}
- engines: {node: '>= 0.6.0'}
+ resolution:
+ { integrity: sha512-rYQ0ESfB+z0t7G95nHH80Zh7Pgg9A0FUYoZqV0yPec5WJZWKIHV2MPYpiJNy8oZAeVqyKwC10WXKSCnUQ5iDVg== }
+ engines: { node: '>= 0.6.0' }
gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
+ resolution:
+ { integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== }
+ engines: { node: '>=6.9.0' }
get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
+ resolution:
+ { integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== }
+ engines: { node: 6.* || 8.* || >= 10.* }
get-east-asian-width@1.3.0:
- resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== }
+ engines: { node: '>=18' }
get-func-name@2.0.2:
- resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+ resolution:
+ { integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== }
get-intrinsic@1.3.0:
- resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== }
+ engines: { node: '>= 0.4' }
get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ { integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== }
+ engines: { node: '>=8.0.0' }
get-proto@1.0.1:
- resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== }
+ engines: { node: '>= 0.4' }
get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== }
+ engines: { node: '>=10' }
get-symbol-description@1.1.0:
- resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== }
+ engines: { node: '>= 0.4' }
get-tsconfig@4.10.0:
- resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
+ resolution:
+ { integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A== }
get-tsconfig@4.10.1:
- resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
+ resolution:
+ { integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ== }
get-value@2.0.6:
- resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== }
+ engines: { node: '>=0.10.0' }
github-from-package@0.0.0:
- resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+ resolution:
+ { integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== }
glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== }
+ engines: { node: '>= 6' }
glob-parent@6.0.2:
- resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
- engines: {node: '>=10.13.0'}
+ resolution:
+ { integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== }
+ engines: { node: '>=10.13.0' }
glob@10.4.5:
- resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ resolution:
+ { integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== }
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
glob@6.0.4:
- resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==}
+ resolution:
+ { integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A== }
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ resolution:
+ { integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== }
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
glob@8.1.0:
- resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== }
+ engines: { node: '>=12' }
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== }
+ engines: { node: '>=4' }
globals@13.24.0:
- resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== }
+ engines: { node: '>=8' }
globalthis@1.0.4:
- resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== }
+ engines: { node: '>= 0.4' }
globby@11.1.0:
- resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== }
+ engines: { node: '>=10' }
gopd@1.2.0:
- resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== }
+ engines: { node: '>= 0.4' }
graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ resolution:
+ { integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== }
graphemer@1.4.0:
- resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ resolution:
+ { integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== }
graphql-request@3.7.0:
- resolution: {integrity: sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ==}
+ resolution:
+ { integrity: sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ== }
peerDependencies:
graphql: 14 - 16
graphql-request@5.0.0:
- resolution: {integrity: sha512-SpVEnIo2J5k2+Zf76cUkdvIRaq5FMZvGQYnA4lUWYbc99m+fHh4CZYRRO/Ff4tCLQ613fzCm3SiDT64ubW5Gyw==}
+ resolution:
+ { integrity: sha512-SpVEnIo2J5k2+Zf76cUkdvIRaq5FMZvGQYnA4lUWYbc99m+fHh4CZYRRO/Ff4tCLQ613fzCm3SiDT64ubW5Gyw== }
peerDependencies:
graphql: 14 - 16
graphql@15.10.1:
- resolution: {integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==}
- engines: {node: '>= 10.x'}
+ resolution:
+ { integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg== }
+ engines: { node: '>= 10.x' }
graphql@16.11.0:
- resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==}
- engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
+ resolution:
+ { integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw== }
+ engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 }
hardhat-watcher@2.5.0:
- resolution: {integrity: sha512-Su2qcSMIo2YO2PrmJ0/tdkf+6pSt8zf9+4URR5edMVti6+ShI8T3xhPrwugdyTOFuyj8lKHrcTZNKUFYowYiyA==}
+ resolution:
+ { integrity: sha512-Su2qcSMIo2YO2PrmJ0/tdkf+6pSt8zf9+4URR5edMVti6+ShI8T3xhPrwugdyTOFuyj8lKHrcTZNKUFYowYiyA== }
peerDependencies:
hardhat: ^2.0.0
hardhat@2.24.0:
- resolution: {integrity: sha512-wDkD5GPmttYv21MR7tGDkyQ22tO2V86OEV8pA7NcXWYUpibe8XZ2EanXCeRHO61vwEx0f7/M+NqrhJwasaNMJg==}
+ resolution:
+ { integrity: sha512-wDkD5GPmttYv21MR7tGDkyQ22tO2V86OEV8pA7NcXWYUpibe8XZ2EanXCeRHO61vwEx0f7/M+NqrhJwasaNMJg== }
hasBin: true
peerDependencies:
ts-node: '*'
@@ -4688,453 +5716,570 @@ packages:
optional: true
has-bigints@1.1.0:
- resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== }
+ engines: { node: '>= 0.4' }
has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== }
+ engines: { node: '>=4' }
has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== }
+ engines: { node: '>=8' }
has-property-descriptors@1.0.2:
- resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+ resolution:
+ { integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== }
has-proto@1.2.0:
- resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== }
+ engines: { node: '>= 0.4' }
has-symbols@1.1.0:
- resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== }
+ engines: { node: '>= 0.4' }
has-tostringtag@1.0.2:
- resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== }
+ engines: { node: '>= 0.4' }
has-value@0.3.1:
- resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== }
+ engines: { node: '>=0.10.0' }
has-value@1.0.0:
- resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== }
+ engines: { node: '>=0.10.0' }
has-values@0.1.4:
- resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== }
+ engines: { node: '>=0.10.0' }
has-values@1.0.0:
- resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== }
+ engines: { node: '>=0.10.0' }
hash-base@2.0.2:
- resolution: {integrity: sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==}
+ resolution:
+ { integrity: sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw== }
hash-base@3.1.0:
- resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== }
+ engines: { node: '>=4' }
hash.js@1.1.7:
- resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==}
+ resolution:
+ { integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== }
hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== }
+ engines: { node: '>= 0.4' }
he@1.2.0:
- resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ resolution:
+ { integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== }
hasBin: true
help-me@5.0.0:
- resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
+ resolution:
+ { integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== }
hi-base32@0.5.1:
- resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==}
+ resolution:
+ { integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== }
hmac-drbg@1.0.1:
- resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==}
+ resolution:
+ { integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== }
html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ resolution:
+ { integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== }
http-errors@1.8.1:
- resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== }
+ engines: { node: '>= 0.6' }
http-errors@2.0.0:
- resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== }
+ engines: { node: '>= 0.8' }
https-proxy-agent@5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== }
+ engines: { node: '>= 6' }
human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
+ resolution:
+ { integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== }
+ engines: { node: '>=10.17.0' }
humanize-ms@1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
+ resolution:
+ { integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== }
husky@9.1.7:
- resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== }
+ engines: { node: '>=18' }
hasBin: true
iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== }
+ engines: { node: '>=0.10.0' }
iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== }
+ engines: { node: '>=0.10.0' }
ieee754@1.2.1:
- resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ resolution:
+ { integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== }
ignore@5.3.2:
- resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
- engines: {node: '>= 4'}
+ resolution:
+ { integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== }
+ engines: { node: '>= 4' }
immutable@4.3.7:
- resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
+ resolution:
+ { integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== }
import-fresh@3.3.1:
- resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== }
+ engines: { node: '>=6' }
import-local@3.2.0:
- resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== }
+ engines: { node: '>=8' }
hasBin: true
imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
+ resolution:
+ { integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== }
+ engines: { node: '>=0.8.19' }
indent-string@4.0.0:
- resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== }
+ engines: { node: '>=8' }
inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ resolution:
+ { integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== }
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ resolution:
+ { integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== }
ini@1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+ resolution:
+ { integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== }
inquirer@8.2.6:
- resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg== }
+ engines: { node: '>=12.0.0' }
internal-slot@1.1.0:
- resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== }
+ engines: { node: '>= 0.4' }
invariant@2.2.4:
- resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+ resolution:
+ { integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== }
io-ts@1.10.4:
- resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==}
+ resolution:
+ { integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== }
ipaddr.js@1.9.1:
- resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
- engines: {node: '>= 0.10'}
+ resolution:
+ { integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== }
+ engines: { node: '>= 0.10' }
is-accessor-descriptor@1.0.1:
- resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==}
- engines: {node: '>= 0.10'}
+ resolution:
+ { integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== }
+ engines: { node: '>= 0.10' }
is-arguments@1.2.0:
- resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== }
+ engines: { node: '>= 0.4' }
is-array-buffer@3.0.5:
- resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== }
+ engines: { node: '>= 0.4' }
is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ resolution:
+ { integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== }
is-arrayish@0.3.2:
- resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+ resolution:
+ { integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== }
is-async-function@2.1.1:
- resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== }
+ engines: { node: '>= 0.4' }
is-bigint@1.1.0:
- resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== }
+ engines: { node: '>= 0.4' }
is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== }
+ engines: { node: '>=8' }
is-boolean-object@1.2.2:
- resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== }
+ engines: { node: '>= 0.4' }
is-buffer@1.1.6:
- resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+ resolution:
+ { integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== }
is-buffer@2.0.5:
- resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== }
+ engines: { node: '>=4' }
is-builtin-module@3.2.1:
- resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== }
+ engines: { node: '>=6' }
is-bun-module@2.0.0:
- resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
+ resolution:
+ { integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== }
is-callable@1.2.7:
- resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== }
+ engines: { node: '>= 0.4' }
is-core-module@2.16.1:
- resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== }
+ engines: { node: '>= 0.4' }
is-data-descriptor@1.0.1:
- resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== }
+ engines: { node: '>= 0.4' }
is-data-view@1.0.2:
- resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== }
+ engines: { node: '>= 0.4' }
is-date-object@1.1.0:
- resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== }
+ engines: { node: '>= 0.4' }
is-descriptor@0.1.7:
- resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg== }
+ engines: { node: '>= 0.4' }
is-descriptor@1.0.3:
- resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== }
+ engines: { node: '>= 0.4' }
is-extendable@0.1.1:
- resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== }
+ engines: { node: '>=0.10.0' }
is-extendable@1.0.1:
- resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== }
+ engines: { node: '>=0.10.0' }
is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== }
+ engines: { node: '>=0.10.0' }
is-finalizationregistry@1.1.1:
- resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== }
+ engines: { node: '>= 0.4' }
is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== }
+ engines: { node: '>=8' }
is-fullwidth-code-point@4.0.0:
- resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== }
+ engines: { node: '>=12' }
is-fullwidth-code-point@5.0.0:
- resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== }
+ engines: { node: '>=18' }
is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== }
+ engines: { node: '>=6' }
is-generator-function@1.1.0:
- resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== }
+ engines: { node: '>= 0.4' }
is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== }
+ engines: { node: '>=0.10.0' }
is-hex-prefixed@1.0.0:
- resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==}
- engines: {node: '>=6.5.0', npm: '>=3'}
+ resolution:
+ { integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== }
+ engines: { node: '>=6.5.0', npm: '>=3' }
is-interactive@1.0.0:
- resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== }
+ engines: { node: '>=8' }
is-map@2.0.3:
- resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== }
+ engines: { node: '>= 0.4' }
is-nan@1.3.2:
- resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== }
+ engines: { node: '>= 0.4' }
is-number-object@1.1.1:
- resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== }
+ engines: { node: '>= 0.4' }
is-number@3.0.0:
- resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== }
+ engines: { node: '>=0.10.0' }
is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
+ resolution:
+ { integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== }
+ engines: { node: '>=0.12.0' }
is-path-inside@3.0.3:
- resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== }
+ engines: { node: '>=8' }
is-plain-obj@2.1.0:
- resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== }
+ engines: { node: '>=8' }
is-plain-object@2.0.4:
- resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== }
+ engines: { node: '>=0.10.0' }
is-regex@1.2.1:
- resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== }
+ engines: { node: '>= 0.4' }
is-set@2.0.3:
- resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== }
+ engines: { node: '>= 0.4' }
is-shared-array-buffer@1.0.4:
- resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== }
+ engines: { node: '>= 0.4' }
is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== }
+ engines: { node: '>=8' }
is-string@1.1.1:
- resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== }
+ engines: { node: '>= 0.4' }
is-symbol@1.1.1:
- resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== }
+ engines: { node: '>= 0.4' }
is-typed-array@1.1.15:
- resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== }
+ engines: { node: '>= 0.4' }
is-unicode-supported@0.1.0:
- resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== }
+ engines: { node: '>=10' }
is-weakmap@2.0.2:
- resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== }
+ engines: { node: '>= 0.4' }
is-weakref@1.1.1:
- resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== }
+ engines: { node: '>= 0.4' }
is-weakset@2.0.4:
- resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== }
+ engines: { node: '>= 0.4' }
is-windows@1.0.2:
- resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== }
+ engines: { node: '>=0.10.0' }
isarray@0.0.1:
- resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
+ resolution:
+ { integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== }
isarray@1.0.0:
- resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+ resolution:
+ { integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== }
isarray@2.0.5:
- resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ resolution:
+ { integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== }
isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ resolution:
+ { integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== }
isnumber@1.0.0:
- resolution: {integrity: sha512-JLiSz/zsZcGFXPrB4I/AGBvtStkt+8QmksyZBZnVXnnK9XdTEyz0tX8CRYljtwYDuIuZzih6DpHQdi+3Q6zHPw==}
+ resolution:
+ { integrity: sha512-JLiSz/zsZcGFXPrB4I/AGBvtStkt+8QmksyZBZnVXnnK9XdTEyz0tX8CRYljtwYDuIuZzih6DpHQdi+3Q6zHPw== }
isobject@2.1.0:
- resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== }
+ engines: { node: '>=0.10.0' }
isobject@3.0.1:
- resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== }
+ engines: { node: '>=0.10.0' }
isomorphic-ws@4.0.1:
- resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==}
+ resolution:
+ { integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== }
peerDependencies:
ws: '*'
isows@1.0.7:
- resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==}
+ resolution:
+ { integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== }
peerDependencies:
ws: '*'
istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== }
+ engines: { node: '>=8' }
istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== }
+ engines: { node: '>=8' }
istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== }
+ engines: { node: '>=10' }
istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== }
+ engines: { node: '>=10' }
istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== }
+ engines: { node: '>=10' }
istanbul-reports@3.1.7:
- resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== }
+ engines: { node: '>=8' }
jackspeak@3.4.3:
- resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+ resolution:
+ { integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== }
jake@10.9.2:
- resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== }
+ engines: { node: '>=10' }
hasBin: true
javascript-natural-sort@0.7.1:
- resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
+ resolution:
+ { integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw== }
jayson@4.2.0:
- resolution: {integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg== }
+ engines: { node: '>=8' }
hasBin: true
jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
@@ -5143,8 +6288,9 @@ packages:
optional: true
jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
peerDependencies:
'@types/node': '*'
ts-node: '>=9.0.0'
@@ -5155,73 +6301,91 @@ packages:
optional: true
jest-diff@24.9.0:
- resolution: {integrity: sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== }
+ engines: { node: '>= 6' }
jest-diff@29.7.0:
- resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-extended@0.11.5:
- resolution: {integrity: sha512-3RsdFpLWKScpsLD6hJuyr/tV5iFOrw7v6YjA3tPdda9sJwoHwcMROws5gwiIZfcwhHlJRwFJB2OUvGmF3evV/Q==}
+ resolution:
+ { integrity: sha512-3RsdFpLWKScpsLD6hJuyr/tV5iFOrw7v6YjA3tPdda9sJwoHwcMROws5gwiIZfcwhHlJRwFJB2OUvGmF3evV/Q== }
jest-get-type@22.4.3:
- resolution: {integrity: sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==}
+ resolution:
+ { integrity: sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== }
jest-get-type@24.9.0:
- resolution: {integrity: sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== }
+ engines: { node: '>= 6' }
jest-get-type@29.6.3:
- resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-matcher-utils@22.4.3:
- resolution: {integrity: sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA==}
+ resolution:
+ { integrity: sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA== }
jest-matcher-utils@24.9.0:
- resolution: {integrity: sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== }
+ engines: { node: '>= 6' }
jest-matcher-utils@29.7.0:
- resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-message-util@24.9.0:
- resolution: {integrity: sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== }
+ engines: { node: '>= 6' }
jest-message-util@29.7.0:
- resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== }
+ engines: { node: '>=6' }
peerDependencies:
jest-resolve: '*'
peerDependenciesMeta:
@@ -5229,52 +6393,64 @@ packages:
optional: true
jest-regex-util@24.9.0:
- resolution: {integrity: sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== }
+ engines: { node: '>= 6' }
jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-util@29.7.0:
- resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
@@ -5283,467 +6459,596 @@ packages:
optional: true
joi@17.13.3:
- resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
+ resolution:
+ { integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== }
joycon@3.1.1:
- resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== }
+ engines: { node: '>=10' }
js-sha256@0.9.0:
- resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==}
+ resolution:
+ { integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== }
js-sha3@0.8.0:
- resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
+ resolution:
+ { integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== }
js-sha512@0.8.0:
- resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==}
+ resolution:
+ { integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ== }
js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ resolution:
+ { integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== }
js-yaml@3.14.1:
- resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ resolution:
+ { integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== }
hasBin: true
js-yaml@4.1.1:
- resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ resolution:
+ { integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== }
hasBin: true
jsbi@3.2.5:
- resolution: {integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==}
+ resolution:
+ { integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== }
jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== }
+ engines: { node: '>=6' }
hasBin: true
json-bigint@1.0.0:
- resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
+ resolution:
+ { integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== }
json-buffer@3.0.1:
- resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ resolution:
+ { integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== }
json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ resolution:
+ { integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== }
json-schema-ref-resolver@1.0.1:
- resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==}
+ resolution:
+ { integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw== }
json-schema-resolver@2.0.0:
- resolution: {integrity: sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg== }
+ engines: { node: '>=10' }
json-schema-traverse@0.4.1:
- resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ resolution:
+ { integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== }
json-schema-traverse@1.0.0:
- resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+ resolution:
+ { integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== }
json-stable-stringify-without-jsonify@1.0.1:
- resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ resolution:
+ { integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== }
json-stream-stringify@3.1.6:
- resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==}
- engines: {node: '>=7.10.1'}
+ resolution:
+ { integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog== }
+ engines: { node: '>=7.10.1' }
json-stringify-safe@5.0.1:
- resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+ resolution:
+ { integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== }
json5@1.0.2:
- resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ resolution:
+ { integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== }
hasBin: true
json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== }
+ engines: { node: '>=6' }
hasBin: true
jsonfile@4.0.0:
- resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+ resolution:
+ { integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== }
jsonfile@6.1.0:
- resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ resolution:
+ { integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== }
keccak@3.0.4:
- resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== }
+ engines: { node: '>=10.0.0' }
keyv@4.5.4:
- resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ resolution:
+ { integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== }
kind-of@3.2.2:
- resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== }
+ engines: { node: '>=0.10.0' }
kind-of@4.0.0:
- resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== }
+ engines: { node: '>=0.10.0' }
kind-of@6.0.3:
- resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== }
+ engines: { node: '>=0.10.0' }
kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== }
+ engines: { node: '>=6' }
kuler@2.0.0:
- resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
+ resolution:
+ { integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== }
lazy-ass@1.6.0:
- resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
- engines: {node: '> 0.8'}
+ resolution:
+ { integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== }
+ engines: { node: '> 0.8' }
level-supports@4.0.1:
- resolution: {integrity: sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== }
+ engines: { node: '>=12' }
level-transcoder@1.0.1:
- resolution: {integrity: sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== }
+ engines: { node: '>=12' }
level@8.0.1:
- resolution: {integrity: sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ== }
+ engines: { node: '>=12' }
leven@3.1.0:
- resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== }
+ engines: { node: '>=6' }
levn@0.4.1:
- resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== }
+ engines: { node: '>= 0.8.0' }
light-my-request@5.14.0:
- resolution: {integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==}
+ resolution:
+ { integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA== }
lilconfig@3.1.3:
- resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== }
+ engines: { node: '>=14' }
lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ resolution:
+ { integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== }
lint-staged@16.1.2:
- resolution: {integrity: sha512-sQKw2Si2g9KUZNY3XNvRuDq4UJqpHwF0/FQzZR2M7I5MvtpWvibikCjUVJzZdGE0ByurEl3KQNvsGetd1ty1/Q==}
- engines: {node: '>=20.17'}
+ resolution:
+ { integrity: sha512-sQKw2Si2g9KUZNY3XNvRuDq4UJqpHwF0/FQzZR2M7I5MvtpWvibikCjUVJzZdGE0ByurEl3KQNvsGetd1ty1/Q== }
+ engines: { node: '>=20.17' }
hasBin: true
listr2@8.3.3:
- resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ== }
+ engines: { node: '>=18.0.0' }
locate-path@5.0.0:
- resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== }
+ engines: { node: '>=8' }
locate-path@6.0.0:
- resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== }
+ engines: { node: '>=10' }
lodash.clonedeep@4.5.0:
- resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
+ resolution:
+ { integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== }
lodash.memoize@4.1.2:
- resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+ resolution:
+ { integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== }
lodash.merge@4.6.2:
- resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ resolution:
+ { integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== }
lodash.truncate@4.4.2:
- resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
+ resolution:
+ { integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== }
lodash@4.17.21:
- resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ resolution:
+ { integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== }
log-symbols@4.1.0:
- resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== }
+ engines: { node: '>=10' }
log-update@6.1.0:
- resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== }
+ engines: { node: '>=18' }
logform@2.7.0:
- resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
- engines: {node: '>= 12.0.0'}
+ resolution:
+ { integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ== }
+ engines: { node: '>= 12.0.0' }
loose-envify@1.4.0:
- resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ resolution:
+ { integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== }
hasBin: true
loupe@2.3.7:
- resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ resolution:
+ { integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== }
lower-case@2.0.2:
- resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
+ resolution:
+ { integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== }
lru-cache@10.4.3:
- resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+ resolution:
+ { integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== }
lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ resolution:
+ { integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== }
lru_map@0.3.3:
- resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==}
+ resolution:
+ { integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== }
make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== }
+ engines: { node: '>=10' }
make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+ resolution:
+ { integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== }
makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ resolution:
+ { integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== }
map-cache@0.2.2:
- resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== }
+ engines: { node: '>=0.10.0' }
map-stream@0.1.0:
- resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
+ resolution:
+ { integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== }
map-visit@1.0.0:
- resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== }
+ engines: { node: '>=0.10.0' }
math-intrinsics@1.1.0:
- resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== }
+ engines: { node: '>= 0.4' }
mathjs@10.6.4:
- resolution: {integrity: sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA==}
- engines: {node: '>= 14'}
+ resolution:
+ { integrity: sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA== }
+ engines: { node: '>= 14' }
hasBin: true
md5.js@1.3.5:
- resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
+ resolution:
+ { integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== }
media-typer@0.3.0:
- resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== }
+ engines: { node: '>= 0.6' }
memorystream@0.3.1:
- resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
- engines: {node: '>= 0.10.0'}
+ resolution:
+ { integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== }
+ engines: { node: '>= 0.10.0' }
merge-descriptors@1.0.3:
- resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
+ resolution:
+ { integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== }
merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ resolution:
+ { integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== }
merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== }
+ engines: { node: '>= 8' }
merkletreejs@0.3.11:
- resolution: {integrity: sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ==}
- engines: {node: '>= 7.6.0'}
+ resolution:
+ { integrity: sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ== }
+ engines: { node: '>= 7.6.0' }
methods@1.1.2:
- resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== }
+ engines: { node: '>= 0.6' }
micro-eth-signer@0.14.0:
- resolution: {integrity: sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==}
+ resolution:
+ { integrity: sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw== }
micro-packed@0.7.3:
- resolution: {integrity: sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==}
+ resolution:
+ { integrity: sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg== }
micromatch@3.1.10:
- resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== }
+ engines: { node: '>=0.10.0' }
micromatch@4.0.8:
- resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
- engines: {node: '>=8.6'}
+ resolution:
+ { integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== }
+ engines: { node: '>=8.6' }
mime-db@1.52.0:
- resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== }
+ engines: { node: '>= 0.6' }
mime-types@2.1.35:
- resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== }
+ engines: { node: '>= 0.6' }
mime@1.6.0:
- resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== }
+ engines: { node: '>=4' }
hasBin: true
mime@3.0.0:
- resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== }
+ engines: { node: '>=10.0.0' }
hasBin: true
mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== }
+ engines: { node: '>=6' }
mimic-function@5.0.1:
- resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== }
+ engines: { node: '>=18' }
mimic-response@3.1.0:
- resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== }
+ engines: { node: '>=10' }
minimalistic-assert@1.0.1:
- resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
+ resolution:
+ { integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== }
minimalistic-crypto-utils@1.0.1:
- resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==}
+ resolution:
+ { integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== }
minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ resolution:
+ { integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== }
minimatch@5.1.6:
- resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== }
+ engines: { node: '>=10' }
minimatch@9.0.5:
- resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ { integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== }
+ engines: { node: '>=16 || 14 >=14.17' }
minimist@0.2.4:
- resolution: {integrity: sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ==}
+ resolution:
+ { integrity: sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ== }
minipass@7.1.2:
- resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
- engines: {node: '>=16 || 14 >=14.17'}
+ resolution:
+ { integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== }
+ engines: { node: '>=16 || 14 >=14.17' }
mixin-deep@1.3.2:
- resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== }
+ engines: { node: '>=0.10.0' }
mkdirp-classic@0.5.3:
- resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ resolution:
+ { integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== }
mkdirp@1.0.4:
- resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== }
+ engines: { node: '>=10' }
hasBin: true
mnemonist@0.38.5:
- resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==}
+ resolution:
+ { integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== }
mocha@10.8.2:
- resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==}
- engines: {node: '>= 14.0.0'}
+ resolution:
+ { integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== }
+ engines: { node: '>= 14.0.0' }
hasBin: true
module-error@1.0.2:
- resolution: {integrity: sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== }
+ engines: { node: '>=10' }
moment@2.30.1:
- resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
+ resolution:
+ { integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== }
ms@2.0.0:
- resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+ resolution:
+ { integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== }
ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ resolution:
+ { integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== }
ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ resolution:
+ { integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== }
multistream@4.1.0:
- resolution: {integrity: sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==}
+ resolution:
+ { integrity: sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw== }
mustache@4.2.0:
- resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
+ resolution:
+ { integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== }
hasBin: true
mute-stream@0.0.8:
- resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
+ resolution:
+ { integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== }
mv@2.1.1:
- resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==}
- engines: {node: '>=0.8.0'}
+ resolution:
+ { integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg== }
+ engines: { node: '>=0.8.0' }
mylas@2.1.13:
- resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg== }
+ engines: { node: '>=12.0.0' }
nan@2.22.2:
- resolution: {integrity: sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==}
+ resolution:
+ { integrity: sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ== }
nano-spawn@1.0.2:
- resolution: {integrity: sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==}
- engines: {node: '>=20.17'}
+ resolution:
+ { integrity: sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg== }
+ engines: { node: '>=20.17' }
nanomatch@1.2.13:
- resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== }
+ engines: { node: '>=0.10.0' }
napi-build-utils@2.0.0:
- resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
+ resolution:
+ { integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== }
napi-macros@2.2.2:
- resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==}
+ resolution:
+ { integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== }
napi-postinstall@0.2.5:
- resolution: {integrity: sha512-kmsgUvCRIJohHjbZ3V8avP0I1Pekw329MVAMDzVxsrkjgdnqiwvMX5XwR+hWV66vsAtZ+iM+fVnq8RTQawUmCQ==}
- engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-kmsgUvCRIJohHjbZ3V8avP0I1Pekw329MVAMDzVxsrkjgdnqiwvMX5XwR+hWV66vsAtZ+iM+fVnq8RTQawUmCQ== }
+ engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
hasBin: true
natural-compare@1.4.0:
- resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ resolution:
+ { integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== }
ncp@2.0.0:
- resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==}
+ resolution:
+ { integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA== }
hasBin: true
near-api-js@0.44.2:
- resolution: {integrity: sha512-eMnc4V+geggapEUa3nU2p8HSHn/njtloI4P2mceHQWO8vDE1NGpnAw8FuTBrLmXSgIv9m6oocgFc9t3VNf5zwg==}
+ resolution:
+ { integrity: sha512-eMnc4V+geggapEUa3nU2p8HSHn/njtloI4P2mceHQWO8vDE1NGpnAw8FuTBrLmXSgIv9m6oocgFc9t3VNf5zwg== }
near-hd-key@1.2.1:
- resolution: {integrity: sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==}
+ resolution:
+ { integrity: sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg== }
near-seed-phrase@0.2.1:
- resolution: {integrity: sha512-feMuums+kVL3LSuPcP4ld07xHCb2mu6z48SGfP3W+8tl1Qm5xIcjiQzY2IDPBvFgajRDxWSb8GzsRHoInazByw==}
+ resolution:
+ { integrity: sha512-feMuums+kVL3LSuPcP4ld07xHCb2mu6z48SGfP3W+8tl1Qm5xIcjiQzY2IDPBvFgajRDxWSb8GzsRHoInazByw== }
negotiator@0.6.3:
- resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== }
+ engines: { node: '>= 0.6' }
no-case@3.0.4:
- resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+ resolution:
+ { integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== }
no-case@4.0.0:
- resolution: {integrity: sha512-WmS3EUGw+vXHlTgiUPi3NzbZNwH6+uGX0QLGgqG+aFSJ5rkX/Ee0nuwHBJfZTfQwwR8lGO819NEIwQ7CGhkdEQ==}
+ resolution:
+ { integrity: sha512-WmS3EUGw+vXHlTgiUPi3NzbZNwH6+uGX0QLGgqG+aFSJ5rkX/Ee0nuwHBJfZTfQwwR8lGO819NEIwQ7CGhkdEQ== }
deprecated: Use `change-case`
node-abi@3.75.0:
- resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg== }
+ engines: { node: '>=10' }
node-addon-api@2.0.2:
- resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==}
+ resolution:
+ { integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== }
node-addon-api@3.2.1:
- resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
+ resolution:
+ { integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== }
node-addon-api@5.1.0:
- resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
+ resolution:
+ { integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== }
node-addon-api@6.1.0:
- resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
+ resolution:
+ { integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== }
node-cache@5.1.2:
- resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==}
- engines: {node: '>= 8.0.0'}
+ resolution:
+ { integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== }
+ engines: { node: '>= 8.0.0' }
node-fetch@2.6.1:
- resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==}
- engines: {node: 4.x || >=6.0.0}
+ resolution:
+ { integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== }
+ engines: { node: 4.x || >=6.0.0 }
node-fetch@2.7.0:
- resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
- engines: {node: 4.x || >=6.0.0}
+ resolution:
+ { integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== }
+ engines: { node: 4.x || >=6.0.0 }
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
@@ -5751,128 +7056,161 @@ packages:
optional: true
node-gyp-build@4.8.4:
- resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
+ resolution:
+ { integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== }
hasBin: true
node-hid@2.1.2:
- resolution: {integrity: sha512-qhCyQqrPpP93F/6Wc/xUR7L8mAJW0Z6R7HMQV8jCHHksAxNDe/4z4Un/H9CpLOT+5K39OPyt9tIQlavxWES3lg==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-qhCyQqrPpP93F/6Wc/xUR7L8mAJW0Z6R7HMQV8jCHHksAxNDe/4z4Un/H9CpLOT+5K39OPyt9tIQlavxWES3lg== }
+ engines: { node: '>=10' }
hasBin: true
node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+ resolution:
+ { integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== }
node-releases@2.0.19:
- resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+ resolution:
+ { integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== }
noms@0.0.0:
- resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==}
+ resolution:
+ { integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== }
normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== }
+ engines: { node: '>=0.10.0' }
npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== }
+ engines: { node: '>=8' }
number-to-bn@1.7.0:
- resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==}
- engines: {node: '>=6.5.0', npm: '>=3'}
+ resolution:
+ { integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== }
+ engines: { node: '>=6.5.0', npm: '>=3' }
o3@1.0.3:
- resolution: {integrity: sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==}
+ resolution:
+ { integrity: sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ== }
object-copy@0.1.0:
- resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== }
+ engines: { node: '>=0.10.0' }
object-hash@2.2.0:
- resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== }
+ engines: { node: '>= 6' }
object-inspect@1.13.4:
- resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== }
+ engines: { node: '>= 0.4' }
object-is@1.1.6:
- resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== }
+ engines: { node: '>= 0.4' }
object-keys@1.1.1:
- resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== }
+ engines: { node: '>= 0.4' }
object-visit@1.0.1:
- resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== }
+ engines: { node: '>=0.10.0' }
object.assign@4.1.7:
- resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== }
+ engines: { node: '>= 0.4' }
object.fromentries@2.0.8:
- resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== }
+ engines: { node: '>= 0.4' }
object.groupby@1.0.3:
- resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== }
+ engines: { node: '>= 0.4' }
object.pick@1.3.0:
- resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== }
+ engines: { node: '>=0.10.0' }
object.values@1.2.1:
- resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== }
+ engines: { node: '>= 0.4' }
obliterator@2.0.5:
- resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==}
+ resolution:
+ { integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw== }
on-exit-leak-free@2.1.2:
- resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== }
+ engines: { node: '>=14.0.0' }
on-finished@2.4.1:
- resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== }
+ engines: { node: '>= 0.8' }
once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ resolution:
+ { integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== }
one-time@1.0.0:
- resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
+ resolution:
+ { integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== }
onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== }
+ engines: { node: '>=6' }
onetime@7.0.0:
- resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== }
+ engines: { node: '>=18' }
openapi-types@12.1.3:
- resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
+ resolution:
+ { integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== }
optionator@0.9.4:
- resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== }
+ engines: { node: '>= 0.8.0' }
ora@5.4.1:
- resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== }
+ engines: { node: '>=10' }
os-tmpdir@1.0.2:
- resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== }
+ engines: { node: '>=0.10.0' }
own-keys@1.0.1:
- resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== }
+ engines: { node: '>= 0.4' }
ox@0.8.1:
- resolution: {integrity: sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A==}
+ resolution:
+ { integrity: sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A== }
peerDependencies:
typescript: '>=5.4.0'
peerDependenciesMeta:
@@ -5880,7 +7218,8 @@ packages:
optional: true
ox@0.9.3:
- resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==}
+ resolution:
+ { integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg== }
peerDependencies:
typescript: '>=5.4.0'
peerDependenciesMeta:
@@ -5888,915 +7227,1160 @@ packages:
optional: true
p-limit@2.3.0:
- resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== }
+ engines: { node: '>=6' }
p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== }
+ engines: { node: '>=10' }
p-locate@4.1.0:
- resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== }
+ engines: { node: '>=8' }
p-locate@5.0.0:
- resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== }
+ engines: { node: '>=10' }
p-map@4.0.0:
- resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== }
+ engines: { node: '>=10' }
p-try@2.2.0:
- resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== }
+ engines: { node: '>=6' }
package-json-from-dist@1.0.1:
- resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+ resolution:
+ { integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== }
pako@2.1.0:
- resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
+ resolution:
+ { integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== }
parent-module@1.0.1:
- resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== }
+ engines: { node: '>=6' }
parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== }
+ engines: { node: '>=8' }
parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== }
+ engines: { node: '>= 0.8' }
pascalcase@0.1.1:
- resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== }
+ engines: { node: '>=0.10.0' }
path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== }
+ engines: { node: '>=8' }
path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== }
+ engines: { node: '>=0.10.0' }
path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== }
+ engines: { node: '>=8' }
path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ resolution:
+ { integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== }
path-scurry@1.11.1:
- resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
- engines: {node: '>=16 || 14 >=14.18'}
+ resolution:
+ { integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== }
+ engines: { node: '>=16 || 14 >=14.18' }
path-to-regexp@0.1.12:
- resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
+ resolution:
+ { integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== }
path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== }
+ engines: { node: '>=8' }
pathval@1.1.1:
- resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ resolution:
+ { integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== }
pause-stream@0.0.11:
- resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
+ resolution:
+ { integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== }
pbkdf2@3.1.3:
- resolution: {integrity: sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==}
- engines: {node: '>=0.12'}
+ resolution:
+ { integrity: sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA== }
+ engines: { node: '>=0.12' }
picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ resolution:
+ { integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== }
picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
+ resolution:
+ { integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== }
+ engines: { node: '>=8.6' }
picomatch@4.0.2:
- resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== }
+ engines: { node: '>=12' }
pidtree@0.6.0:
- resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
- engines: {node: '>=0.10'}
+ resolution:
+ { integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== }
+ engines: { node: '>=0.10' }
hasBin: true
pino-abstract-transport@2.0.0:
- resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==}
+ resolution:
+ { integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw== }
pino-pretty@11.3.0:
- resolution: {integrity: sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==}
+ resolution:
+ { integrity: sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA== }
hasBin: true
pino-std-serializers@7.0.0:
- resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==}
+ resolution:
+ { integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== }
pino@9.6.0:
- resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==}
+ resolution:
+ { integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg== }
hasBin: true
pirates@4.0.7:
- resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== }
+ engines: { node: '>= 6' }
pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== }
+ engines: { node: '>=8' }
plimit-lit@1.6.1:
- resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA== }
+ engines: { node: '>=12' }
pnpm@10.10.0:
- resolution: {integrity: sha512-1hXbJG/nDyXc/qbY1z3ueCziPiJF48T2+Igkn7VoFJMYY33Kc8LFyO8qTKDVZX+5VnGIv6tH9WbR7mzph4FcOQ==}
- engines: {node: '>=18.12'}
+ resolution:
+ { integrity: sha512-1hXbJG/nDyXc/qbY1z3ueCziPiJF48T2+Igkn7VoFJMYY33Kc8LFyO8qTKDVZX+5VnGIv6tH9WbR7mzph4FcOQ== }
+ engines: { node: '>=18.12' }
hasBin: true
posix-character-classes@0.1.1:
- resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== }
+ engines: { node: '>=0.10.0' }
possible-typed-array-names@1.1.0:
- resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== }
+ engines: { node: '>= 0.4' }
prebuild-install@7.1.3:
- resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug== }
+ engines: { node: '>=10' }
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
hasBin: true
prelude-ls@1.2.1:
- resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== }
+ engines: { node: '>= 0.8.0' }
prettier-linter-helpers@1.0.0:
- resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
- engines: {node: '>=6.0.0'}
+ resolution:
+ { integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== }
+ engines: { node: '>=6.0.0' }
prettier@3.5.3:
- resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== }
+ engines: { node: '>=14' }
hasBin: true
pretty-format@22.4.3:
- resolution: {integrity: sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==}
+ resolution:
+ { integrity: sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ== }
pretty-format@24.9.0:
- resolution: {integrity: sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== }
+ engines: { node: '>= 6' }
pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ resolution:
+ { integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== }
+ engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
process-nextick-args@2.0.1:
- resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ resolution:
+ { integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== }
process-warning@3.0.0:
- resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==}
+ resolution:
+ { integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ== }
process-warning@4.0.1:
- resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
+ resolution:
+ { integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q== }
process@0.11.10:
- resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
- engines: {node: '>= 0.6.0'}
+ resolution:
+ { integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== }
+ engines: { node: '>= 0.6.0' }
prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== }
+ engines: { node: '>= 6' }
proxy-addr@2.0.7:
- resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
- engines: {node: '>= 0.10'}
+ resolution:
+ { integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== }
+ engines: { node: '>= 0.10' }
proxy-from-env@1.1.0:
- resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ resolution:
+ { integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== }
ps-tree@1.2.0:
- resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
- engines: {node: '>= 0.10'}
+ resolution:
+ { integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== }
+ engines: { node: '>= 0.10' }
hasBin: true
pump@3.0.2:
- resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
+ resolution:
+ { integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== }
punycode@2.3.1:
- resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== }
+ engines: { node: '>=6' }
pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+ resolution:
+ { integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== }
qs@6.13.0:
- resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
- engines: {node: '>=0.6'}
+ resolution:
+ { integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== }
+ engines: { node: '>=0.6' }
queue-lit@1.5.2:
- resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw== }
+ engines: { node: '>=12' }
queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ resolution:
+ { integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== }
quick-format-unescaped@4.0.4:
- resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+ resolution:
+ { integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== }
randombytes@2.1.0:
- resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ resolution:
+ { integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== }
range-parser@1.2.1:
- resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== }
+ engines: { node: '>= 0.6' }
raw-body@2.5.2:
- resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== }
+ engines: { node: '>= 0.8' }
rc@1.2.8:
- resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
+ resolution:
+ { integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== }
hasBin: true
react-dom@18.3.1:
- resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+ resolution:
+ { integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== }
peerDependencies:
react: ^18.3.1
react-is@16.13.1:
- resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ resolution:
+ { integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== }
react-is@18.3.1:
- resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ resolution:
+ { integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== }
react@18.3.1:
- resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== }
+ engines: { node: '>=0.10.0' }
readable-stream@1.0.34:
- resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==}
+ resolution:
+ { integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== }
readable-stream@2.3.8:
- resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+ resolution:
+ { integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== }
readable-stream@3.6.2:
- resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
- engines: {node: '>= 6'}
+ resolution:
+ { integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== }
+ engines: { node: '>= 6' }
readable-stream@4.7.0:
- resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg== }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
+ resolution:
+ { integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== }
+ engines: { node: '>=8.10.0' }
readdirp@4.1.2:
- resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
- engines: {node: '>= 14.18.0'}
+ resolution:
+ { integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== }
+ engines: { node: '>= 14.18.0' }
real-require@0.2.0:
- resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
- engines: {node: '>= 12.13.0'}
+ resolution:
+ { integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== }
+ engines: { node: '>= 12.13.0' }
reflect.getprototypeof@1.0.10:
- resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== }
+ engines: { node: '>= 0.4' }
regex-not@1.0.2:
- resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== }
+ engines: { node: '>=0.10.0' }
regexp-tree@0.1.27:
- resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
+ resolution:
+ { integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== }
hasBin: true
regexp.prototype.flags@1.5.4:
- resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== }
+ engines: { node: '>= 0.4' }
repeat-element@1.1.4:
- resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== }
+ engines: { node: '>=0.10.0' }
repeat-string@1.6.1:
- resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
- engines: {node: '>=0.10'}
+ 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'}
+ resolution:
+ { integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== }
+ engines: { node: '>=0.10.0' }
require-from-string@2.0.2:
- resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== }
+ engines: { node: '>=0.10.0' }
resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== }
+ engines: { node: '>=8' }
resolve-from@4.0.0:
- resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== }
+ engines: { node: '>=4' }
resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== }
+ engines: { node: '>=8' }
resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ resolution:
+ { integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== }
resolve-url@0.2.1:
- resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
+ resolution:
+ { integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== }
deprecated: https://github.com/lydell/resolve-url#deprecated
resolve.exports@2.0.3:
- resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== }
+ engines: { node: '>=10' }
resolve@1.17.0:
- resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==}
+ resolution:
+ { integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== }
resolve@1.22.10:
- resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== }
+ engines: { node: '>= 0.4' }
hasBin: true
restore-cursor@3.1.0:
- resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== }
+ engines: { node: '>=8' }
restore-cursor@5.1.0:
- resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== }
+ engines: { node: '>=18' }
ret@0.1.15:
- resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
- engines: {node: '>=0.12'}
+ resolution:
+ { integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== }
+ engines: { node: '>=0.12' }
ret@0.4.3:
- resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ== }
+ engines: { node: '>=10' }
retry@0.13.1:
- resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
- engines: {node: '>= 4'}
+ resolution:
+ { integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== }
+ engines: { node: '>= 4' }
reusify@1.1.0:
- resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== }
+ engines: { iojs: '>=1.0.0', node: '>=0.10.0' }
rfdc@1.4.1:
- resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+ resolution:
+ { integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== }
rimraf@2.4.5:
- resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==}
+ resolution:
+ { integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ== }
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@3.0.2:
- resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ resolution:
+ { integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== }
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
ripemd160@2.0.1:
- resolution: {integrity: sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==}
+ resolution:
+ { integrity: sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w== }
ripemd160@2.0.2:
- resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==}
+ resolution:
+ { integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== }
rlp@2.2.7:
- resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==}
+ resolution:
+ { integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== }
hasBin: true
rpc-websockets@9.1.1:
- resolution: {integrity: sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA==}
+ resolution:
+ { integrity: sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA== }
run-async@2.4.1:
- resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
- engines: {node: '>=0.12.0'}
+ resolution:
+ { integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== }
+ engines: { node: '>=0.12.0' }
run-parallel-limit@1.1.0:
- resolution: {integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==}
+ resolution:
+ { integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== }
run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ resolution:
+ { integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== }
rxjs@7.8.2:
- resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
+ resolution:
+ { integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== }
safe-array-concat@1.1.3:
- resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
- engines: {node: '>=0.4'}
+ resolution:
+ { integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== }
+ engines: { node: '>=0.4' }
safe-buffer@5.1.2:
- resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ resolution:
+ { integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== }
safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ resolution:
+ { integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== }
safe-json-stringify@1.2.0:
- resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==}
+ resolution:
+ { integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg== }
safe-push-apply@1.0.0:
- resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== }
+ engines: { node: '>= 0.4' }
safe-regex-test@1.1.0:
- resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== }
+ engines: { node: '>= 0.4' }
safe-regex2@3.1.0:
- resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==}
+ resolution:
+ { integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug== }
safe-regex@1.1.0:
- resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==}
+ resolution:
+ { integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== }
safe-regex@2.1.1:
- resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==}
+ resolution:
+ { integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== }
safe-stable-stringify@2.5.0:
- resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== }
+ engines: { node: '>=10' }
safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ resolution:
+ { integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== }
scheduler@0.23.2:
- resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+ resolution:
+ { integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== }
scrypt-js@3.0.1:
- resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==}
+ resolution:
+ { integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== }
secp256k1@4.0.4:
- resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== }
+ engines: { node: '>=18.0.0' }
secure-json-parse@2.7.0:
- resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
+ resolution:
+ { integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== }
seedrandom@3.0.5:
- resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
+ resolution:
+ { integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== }
semver@5.7.2:
- resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+ resolution:
+ { integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== }
hasBin: true
semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ resolution:
+ { integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== }
hasBin: true
semver@7.7.1:
- resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== }
+ engines: { node: '>=10' }
hasBin: true
send@0.19.0:
- resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== }
+ engines: { node: '>= 0.8.0' }
serialize-javascript@6.0.2:
- resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
+ resolution:
+ { integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== }
serve-static@1.16.2:
- resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== }
+ engines: { node: '>= 0.8.0' }
set-cookie-parser@2.7.1:
- resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
+ resolution:
+ { integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== }
set-function-length@1.2.2:
- resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== }
+ engines: { node: '>= 0.4' }
set-function-name@2.0.2:
- resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== }
+ engines: { node: '>= 0.4' }
set-proto@1.0.0:
- resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== }
+ engines: { node: '>= 0.4' }
set-value@2.0.1:
- resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== }
+ engines: { node: '>=0.10.0' }
setimmediate@1.0.5:
- resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
+ resolution:
+ { integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== }
setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ resolution:
+ { integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== }
sha.js@2.4.11:
- resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
+ resolution:
+ { integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== }
hasBin: true
shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== }
+ engines: { node: '>=8' }
shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== }
+ engines: { node: '>=8' }
side-channel-list@1.0.0:
- resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== }
+ engines: { node: '>= 0.4' }
side-channel-map@1.0.1:
- resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== }
+ engines: { node: '>= 0.4' }
side-channel-weakmap@1.0.2:
- resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== }
+ engines: { node: '>= 0.4' }
side-channel@1.1.0:
- resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== }
+ engines: { node: '>= 0.4' }
signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ resolution:
+ { integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== }
signal-exit@4.1.0:
- resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
- engines: {node: '>=14'}
+ resolution:
+ { integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== }
+ engines: { node: '>=14' }
simple-concat@1.0.1:
- resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+ resolution:
+ { integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== }
simple-get@4.0.1:
- resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
+ resolution:
+ { integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== }
simple-swizzle@0.2.2:
- resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ resolution:
+ { integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== }
sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ resolution:
+ { integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== }
slash@2.0.0:
- resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== }
+ engines: { node: '>=6' }
slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== }
+ engines: { node: '>=8' }
slice-ansi@4.0.0:
- resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== }
+ engines: { node: '>=10' }
slice-ansi@5.0.0:
- resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== }
+ engines: { node: '>=12' }
slice-ansi@7.1.0:
- resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== }
+ engines: { node: '>=18' }
snake-case@3.0.4:
- resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
+ resolution:
+ { integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== }
snake-case@4.0.0:
- resolution: {integrity: sha512-slvG6efKZ3GYUUZdhPOq/lLIqutwQ4TdPViD1VKqsbf0u76U/aPRswPKjOaAS9T7fAPmRmXuN6C/nM0xsMaFLQ==}
+ resolution:
+ { integrity: sha512-slvG6efKZ3GYUUZdhPOq/lLIqutwQ4TdPViD1VKqsbf0u76U/aPRswPKjOaAS9T7fAPmRmXuN6C/nM0xsMaFLQ== }
deprecated: Use `change-case`
snapdragon-node@2.1.1:
- resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== }
+ engines: { node: '>=0.10.0' }
snapdragon-util@3.0.1:
- resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== }
+ engines: { node: '>=0.10.0' }
snapdragon@0.8.2:
- resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== }
+ engines: { node: '>=0.10.0' }
solc@0.8.26:
- resolution: {integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== }
+ engines: { node: '>=10.0.0' }
hasBin: true
sonic-boom@4.2.0:
- resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==}
+ resolution:
+ { integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww== }
source-map-resolve@0.5.3:
- resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
+ resolution:
+ { integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== }
deprecated: See https://github.com/lydell/source-map-resolve#deprecated
source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+ resolution:
+ { integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== }
source-map-support@0.5.21:
- resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+ resolution:
+ { integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== }
source-map-url@0.4.1:
- resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==}
+ resolution:
+ { integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== }
deprecated: See https://github.com/lydell/source-map-url#deprecated
source-map@0.5.7:
- resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== }
+ engines: { node: '>=0.10.0' }
source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== }
+ engines: { node: '>=0.10.0' }
split-string@3.1.0:
- resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== }
+ engines: { node: '>=0.10.0' }
split2@4.2.0:
- resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
- engines: {node: '>= 10.x'}
+ resolution:
+ { integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== }
+ engines: { node: '>= 10.x' }
split@0.3.3:
- resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==}
+ resolution:
+ { integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== }
sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ resolution:
+ { integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== }
stable-hash-x@0.1.1:
- resolution: {integrity: sha512-l0x1D6vhnsNUGPFVDx45eif0y6eedVC8nm5uACTrVFJFtl2mLRW17aWtVyxFCpn5t94VUPkjU8vSLwIuwwqtJQ==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-l0x1D6vhnsNUGPFVDx45eif0y6eedVC8nm5uACTrVFJFtl2mLRW17aWtVyxFCpn5t94VUPkjU8vSLwIuwwqtJQ== }
+ engines: { node: '>=12.0.0' }
stable-hash-x@0.2.0:
- resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ== }
+ engines: { node: '>=12.0.0' }
stack-trace@0.0.10:
- resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==}
+ resolution:
+ { integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== }
stack-utils@1.0.5:
- resolution: {integrity: sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== }
+ engines: { node: '>=8' }
stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== }
+ engines: { node: '>=10' }
stacktrace-parser@0.1.11:
- resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg== }
+ engines: { node: '>=6' }
start-server-and-test@1.15.4:
- resolution: {integrity: sha512-ucQtp5+UCr0m4aHlY+aEV2JSYNTiMZKdSKK/bsIr6AlmwAWDYDnV7uGlWWEtWa7T4XvRI5cPYcPcQgeLqpz+Tg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-ucQtp5+UCr0m4aHlY+aEV2JSYNTiMZKdSKK/bsIr6AlmwAWDYDnV7uGlWWEtWa7T4XvRI5cPYcPcQgeLqpz+Tg== }
+ engines: { node: '>=6' }
hasBin: true
static-extend@0.1.2:
- resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== }
+ engines: { node: '>=0.10.0' }
stats-lite@2.2.0:
- resolution: {integrity: sha512-/Kz55rgUIv2KP2MKphwYT/NCuSfAlbbMRv2ZWw7wyXayu230zdtzhxxuXXcvsc6EmmhS8bSJl3uS1wmMHFumbA==}
- engines: {node: '>=2.0.0'}
+ resolution:
+ { integrity: sha512-/Kz55rgUIv2KP2MKphwYT/NCuSfAlbbMRv2ZWw7wyXayu230zdtzhxxuXXcvsc6EmmhS8bSJl3uS1wmMHFumbA== }
+ engines: { node: '>=2.0.0' }
statuses@1.5.0:
- resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== }
+ engines: { node: '>= 0.6' }
statuses@2.0.1:
- resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== }
+ engines: { node: '>= 0.8' }
stream-blackhole@1.0.3:
- resolution: {integrity: sha512-7NWl3dkmCd12mPkEwTbBPGxwvxj7L4O9DTjJudn02Fmk9K+RuPaDF8zeGo3kmjbsffU5E1aGpZ1dTR9AaRg6AQ==}
+ resolution:
+ { integrity: sha512-7NWl3dkmCd12mPkEwTbBPGxwvxj7L4O9DTjJudn02Fmk9K+RuPaDF8zeGo3kmjbsffU5E1aGpZ1dTR9AaRg6AQ== }
stream-chain@2.2.5:
- resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==}
+ resolution:
+ { integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== }
stream-combiner@0.0.4:
- resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==}
+ resolution:
+ { integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== }
stream-json@1.9.1:
- resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==}
+ resolution:
+ { integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== }
stream-transform@3.3.3:
- resolution: {integrity: sha512-dALXrXe+uq4aO5oStdHKlfCM/b3NBdouigvxVPxCdrMRAU6oHh3KNss20VbTPQNQmjAHzZGKGe66vgwegFEIog==}
+ resolution:
+ { integrity: sha512-dALXrXe+uq4aO5oStdHKlfCM/b3NBdouigvxVPxCdrMRAU6oHh3KNss20VbTPQNQmjAHzZGKGe66vgwegFEIog== }
string-argv@0.3.2:
- resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
- engines: {node: '>=0.6.19'}
+ resolution:
+ { integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== }
+ engines: { node: '>=0.6.19' }
string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== }
+ engines: { node: '>=10' }
string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== }
+ engines: { node: '>=8' }
string-width@5.1.2:
- resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== }
+ engines: { node: '>=12' }
string-width@7.2.0:
- resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== }
+ engines: { node: '>=18' }
string.prototype.trim@1.2.10:
- resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== }
+ engines: { node: '>= 0.4' }
string.prototype.trimend@1.0.9:
- resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== }
+ engines: { node: '>= 0.4' }
string.prototype.trimstart@1.0.8:
- resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== }
+ engines: { node: '>= 0.4' }
string_decoder@0.10.31:
- resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
+ resolution:
+ { integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== }
string_decoder@1.1.1:
- resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ resolution:
+ { integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== }
string_decoder@1.3.0:
- resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ resolution:
+ { integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== }
strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== }
+ engines: { node: '>=8' }
strip-ansi@7.1.0:
- resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== }
+ engines: { node: '>=12' }
strip-bom@3.0.0:
- resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== }
+ engines: { node: '>=4' }
strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== }
+ engines: { node: '>=8' }
strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== }
+ engines: { node: '>=6' }
strip-hex-prefix@1.0.0:
- resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==}
- engines: {node: '>=6.5.0', npm: '>=3'}
+ resolution:
+ { integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== }
+ engines: { node: '>=6.5.0', npm: '>=3' }
strip-json-comments@2.0.1:
- resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== }
+ engines: { node: '>=0.10.0' }
strip-json-comments@3.1.1:
- resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== }
+ engines: { node: '>=8' }
strnum@1.1.2:
- resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==}
+ resolution:
+ { integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA== }
superstruct@0.15.5:
- resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==}
+ resolution:
+ { integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== }
superstruct@2.0.2:
- resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==}
- engines: {node: '>=14.0.0'}
+ resolution:
+ { integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== }
+ engines: { node: '>=14.0.0' }
supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== }
+ engines: { node: '>=4' }
supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== }
+ engines: { node: '>=8' }
supports-color@8.1.1:
- resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== }
+ engines: { node: '>=10' }
supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== }
+ engines: { node: '>= 0.4' }
synckit@0.11.4:
- resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==}
- engines: {node: ^14.18.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ== }
+ engines: { node: ^14.18.0 || >=16.0.0 }
table@6.9.0:
- resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== }
+ engines: { node: '>=10.0.0' }
tar-fs@2.1.3:
- resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==}
+ resolution:
+ { integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== }
tar-stream@2.2.0:
- resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== }
+ engines: { node: '>=6' }
test-exclude@6.0.0:
- resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== }
+ engines: { node: '>=8' }
text-encoding-utf-8@1.0.2:
- resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==}
+ resolution:
+ { integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== }
text-hex@1.0.0:
- resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
+ resolution:
+ { integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== }
text-table@0.2.0:
- resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ resolution:
+ { integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== }
thread-stream@3.1.0:
- resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
+ resolution:
+ { integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== }
through2@2.0.5:
- resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+ resolution:
+ { integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== }
through@2.3.8:
- resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+ resolution:
+ { integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== }
tiny-emitter@2.1.0:
- resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
+ resolution:
+ { integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== }
tiny-invariant@1.3.3:
- resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
+ resolution:
+ { integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== }
tiny-warning@1.0.3:
- resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+ resolution:
+ { integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== }
tinyglobby@0.2.14:
- resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== }
+ engines: { node: '>=12.0.0' }
tmp-promise@3.0.3:
- resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
+ resolution:
+ { integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ== }
tmp@0.0.33:
- resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
- engines: {node: '>=0.6.0'}
+ resolution:
+ { integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== }
+ engines: { node: '>=0.6.0' }
tmp@0.2.3:
- resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
- engines: {node: '>=14.14'}
+ resolution:
+ { integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== }
+ engines: { node: '>=14.14' }
tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+ resolution:
+ { integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== }
to-buffer@1.2.1:
- resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ== }
+ engines: { node: '>= 0.4' }
to-object-path@0.3.0:
- resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== }
+ engines: { node: '>=0.10.0' }
to-regex-range@2.1.1:
- resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== }
+ engines: { node: '>=0.10.0' }
to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
+ resolution:
+ { integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== }
+ engines: { node: '>=8.0' }
to-regex@3.0.2:
- resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== }
+ engines: { node: '>=0.10.0' }
toad-cache@3.7.0:
- resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw== }
+ engines: { node: '>=12' }
toformat@2.0.0:
- resolution: {integrity: sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ==}
+ resolution:
+ { integrity: sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ== }
toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
+ resolution:
+ { integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== }
+ engines: { node: '>=0.6' }
toml@3.0.0:
- resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
+ resolution:
+ { integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== }
tr46@0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ resolution:
+ { integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== }
treeify@1.1.0:
- resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==}
- engines: {node: '>=0.6'}
+ resolution:
+ { integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== }
+ engines: { node: '>=0.6' }
triple-beam@1.4.1:
- resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
- engines: {node: '>= 14.0.0'}
+ resolution:
+ { integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== }
+ engines: { node: '>= 14.0.0' }
ts-api-utils@1.4.3:
- resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== }
+ engines: { node: '>=16' }
peerDependencies:
typescript: '>=4.2.0'
ts-jest@29.3.2:
- resolution: {integrity: sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug==}
- engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
+ resolution:
+ { integrity: sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug== }
+ engines: { node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0 }
hasBin: true
peerDependencies:
'@babel/core': '>=7.0.0-beta.0 <8'
@@ -6819,7 +8403,8 @@ packages:
optional: true
ts-node@10.9.2:
- resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
+ resolution:
+ { integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== }
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
@@ -6833,200 +8418,251 @@ packages:
optional: true
tsc-alias@1.8.16:
- resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==}
- engines: {node: '>=16.20.2'}
+ resolution:
+ { integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g== }
+ engines: { node: '>=16.20.2' }
hasBin: true
tsconfig-paths@3.15.0:
- resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+ resolution:
+ { integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== }
tsconfig-paths@4.2.0:
- resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== }
+ engines: { node: '>=6' }
tslib@1.14.1:
- resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ resolution:
+ { integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== }
tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+ resolution:
+ { integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== }
tsort@0.0.1:
- resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==}
+ resolution:
+ { integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== }
tsx@4.20.3:
- resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==}
- engines: {node: '>=18.0.0'}
+ resolution:
+ { integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ== }
+ engines: { node: '>=18.0.0' }
hasBin: true
tunnel-agent@0.6.0:
- resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+ resolution:
+ { integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== }
tweetnacl@1.0.3:
- resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
+ resolution:
+ { integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== }
type-check@0.4.0:
- resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
- engines: {node: '>= 0.8.0'}
+ resolution:
+ { integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== }
+ engines: { node: '>= 0.8.0' }
type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== }
+ engines: { node: '>=4' }
type-detect@4.1.0:
- resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==}
- engines: {node: '>=4'}
+ resolution:
+ { integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== }
+ engines: { node: '>=4' }
type-fest@0.20.2:
- resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== }
+ engines: { node: '>=10' }
type-fest@0.21.3:
- resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== }
+ engines: { node: '>=10' }
type-fest@0.7.1:
- resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== }
+ engines: { node: '>=8' }
type-fest@4.41.0:
- resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
- engines: {node: '>=16'}
+ resolution:
+ { integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== }
+ engines: { node: '>=16' }
type-is@1.6.18:
- resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
- engines: {node: '>= 0.6'}
+ resolution:
+ { integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== }
+ engines: { node: '>= 0.6' }
typed-array-buffer@1.0.3:
- resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== }
+ engines: { node: '>= 0.4' }
typed-array-byte-length@1.0.3:
- resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== }
+ engines: { node: '>= 0.4' }
typed-array-byte-offset@1.0.4:
- resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== }
+ engines: { node: '>= 0.4' }
typed-array-length@1.0.7:
- resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== }
+ engines: { node: '>= 0.4' }
typed-function@2.1.0:
- resolution: {integrity: sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==}
- engines: {node: '>= 10'}
+ resolution:
+ { integrity: sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ== }
+ engines: { node: '>= 10' }
typescript@5.8.3:
- resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
- engines: {node: '>=14.17'}
+ resolution:
+ { integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== }
+ engines: { node: '>=14.17' }
hasBin: true
u3@0.1.1:
- resolution: {integrity: sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==}
+ resolution:
+ { integrity: sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w== }
unbox-primitive@1.1.0:
- resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== }
+ engines: { node: '>= 0.4' }
undici-types@7.16.0:
- resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+ resolution:
+ { integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== }
undici@5.29.0:
- resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
- engines: {node: '>=14.0'}
+ resolution:
+ { integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg== }
+ engines: { node: '>=14.0' }
union-value@1.0.1:
- resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== }
+ engines: { node: '>=0.10.0' }
universalify@0.1.2:
- resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
- engines: {node: '>= 4.0.0'}
+ resolution:
+ { integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== }
+ engines: { node: '>= 4.0.0' }
universalify@2.0.1:
- resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
- engines: {node: '>= 10.0.0'}
+ resolution:
+ { integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== }
+ engines: { node: '>= 10.0.0' }
unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== }
+ engines: { node: '>= 0.8' }
unrs-resolver@1.9.2:
- resolution: {integrity: sha512-VUyWiTNQD7itdiMuJy+EuLEErLj3uwX/EpHQF8EOf33Dq3Ju6VW1GXm+swk6+1h7a49uv9fKZ+dft9jU7esdLA==}
+ resolution:
+ { integrity: sha512-VUyWiTNQD7itdiMuJy+EuLEErLj3uwX/EpHQF8EOf33Dq3Ju6VW1GXm+swk6+1h7a49uv9fKZ+dft9jU7esdLA== }
unset-value@1.0.0:
- resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== }
+ engines: { node: '>=0.10.0' }
untildify@4.0.0:
- resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== }
+ engines: { node: '>=8' }
update-browserslist-db@1.1.3:
- resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ resolution:
+ { integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== }
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
uri-js@4.4.1:
- resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ resolution:
+ { integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== }
urix@0.1.0:
- resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
+ resolution:
+ { integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== }
deprecated: Please see https://github.com/lydell/urix#deprecated
usb@2.9.0:
- resolution: {integrity: sha512-G0I/fPgfHUzWH8xo2KkDxTTFruUWfppgSFJ+bQxz/kVY2x15EQ/XDB7dqD1G432G4gBG4jYQuF3U7j/orSs5nw==}
- engines: {node: '>=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0'}
+ resolution:
+ { integrity: sha512-G0I/fPgfHUzWH8xo2KkDxTTFruUWfppgSFJ+bQxz/kVY2x15EQ/XDB7dqD1G432G4gBG4jYQuF3U7j/orSs5nw== }
+ engines: { node: '>=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0' }
use@3.1.1:
- resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== }
+ engines: { node: '>=0.10.0' }
utf-8-validate@5.0.10:
- resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
- engines: {node: '>=6.14.2'}
+ resolution:
+ { integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== }
+ engines: { node: '>=6.14.2' }
utf8@3.0.0:
- resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==}
+ resolution:
+ { integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== }
util-deprecate@1.0.2:
- resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ resolution:
+ { integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== }
util@0.12.5:
- resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
+ resolution:
+ { integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== }
utility-types@3.11.0:
- resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
- engines: {node: '>= 4'}
+ resolution:
+ { integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw== }
+ engines: { node: '>= 4' }
utils-merge@1.0.1:
- resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
- engines: {node: '>= 0.4.0'}
+ resolution:
+ { integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== }
+ engines: { node: '>= 0.4.0' }
uuid@8.3.2:
- resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ resolution:
+ { integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== }
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
hasBin: true
uuid@9.0.1:
- resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+ resolution:
+ { integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== }
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
hasBin: true
v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+ resolution:
+ { integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== }
v8-to-istanbul@9.3.0:
- resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
- engines: {node: '>=10.12.0'}
+ resolution:
+ { integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== }
+ engines: { node: '>=10.12.0' }
vary@1.1.2:
- resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
- engines: {node: '>= 0.8'}
+ resolution:
+ { integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== }
+ engines: { node: '>= 0.8' }
viem@2.31.3:
- resolution: {integrity: sha512-q3JGI5QFB4LEiLfg9f2ZwjUygAn2W0wMLtj++7E/L2i8Y7zKAkR4TEEOhwBn7gyYXpuc7f1vfd26PJbkEKuj5w==}
+ resolution:
+ { integrity: sha512-q3JGI5QFB4LEiLfg9f2ZwjUygAn2W0wMLtj++7E/L2i8Y7zKAkR4TEEOhwBn7gyYXpuc7f1vfd26PJbkEKuj5w== }
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
@@ -7034,7 +8670,8 @@ packages:
optional: true
viem@2.37.1:
- resolution: {integrity: sha512-IzacdIXYlOvzDJwNKIVa53LP/LaP70qvBGAIoGH6R+n06S/ru/nnQxLNZ6+JImvIcxwNwgAl0jUA6FZEIQQWSw==}
+ resolution:
+ { integrity: sha512-IzacdIXYlOvzDJwNKIVa53LP/LaP70qvBGAIoGH6R+n06S/ru/nnQxLNZ6+JImvIcxwNwgAl0jUA6FZEIQQWSw== }
peerDependencies:
typescript: '>=5.0.4'
peerDependenciesMeta:
@@ -7042,101 +8679,126 @@ packages:
optional: true
vlq@2.0.4:
- resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==}
+ resolution:
+ { integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA== }
wait-on@7.0.1:
- resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==}
- engines: {node: '>=12.0.0'}
+ resolution:
+ { integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog== }
+ engines: { node: '>=12.0.0' }
hasBin: true
walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+ resolution:
+ { integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== }
wcwidth@1.0.1:
- resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+ resolution:
+ { integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== }
web3-utils@1.7.3:
- resolution: {integrity: sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==}
- engines: {node: '>=8.0.0'}
+ resolution:
+ { integrity: sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg== }
+ engines: { node: '>=8.0.0' }
webidl-conversions@3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ resolution:
+ { integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== }
whatwg-url@5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ resolution:
+ { integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== }
which-boxed-primitive@1.1.1:
- resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== }
+ engines: { node: '>= 0.4' }
which-builtin-type@1.2.1:
- resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== }
+ engines: { node: '>= 0.4' }
which-collection@1.0.2:
- resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== }
+ engines: { node: '>= 0.4' }
which-typed-array@1.1.19:
- resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
- engines: {node: '>= 0.4'}
+ resolution:
+ { integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== }
+ engines: { node: '>= 0.4' }
which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
+ resolution:
+ { integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== }
+ engines: { node: '>= 8' }
hasBin: true
widest-line@3.1.0:
- resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== }
+ engines: { node: '>=8' }
winston-daily-rotate-file@4.7.1:
- resolution: {integrity: sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA== }
+ engines: { node: '>=8' }
peerDependencies:
winston: ^3
winston-transport@4.9.0:
- resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==}
- engines: {node: '>= 12.0.0'}
+ resolution:
+ { integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A== }
+ engines: { node: '>= 12.0.0' }
winston@3.17.0:
- resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==}
- engines: {node: '>= 12.0.0'}
+ resolution:
+ { integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw== }
+ engines: { node: '>= 12.0.0' }
word-wrap@1.2.5:
- resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
- engines: {node: '>=0.10.0'}
+ resolution:
+ { integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== }
+ engines: { node: '>=0.10.0' }
workerpool@6.5.1:
- resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==}
+ resolution:
+ { integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== }
wrap-ansi@6.2.0:
- resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
- engines: {node: '>=8'}
+ resolution:
+ { integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== }
+ engines: { node: '>=8' }
wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== }
+ engines: { node: '>=10' }
wrap-ansi@8.1.0:
- resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== }
+ engines: { node: '>=12' }
wrap-ansi@9.0.0:
- resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
- engines: {node: '>=18'}
+ resolution:
+ { integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== }
+ engines: { node: '>=18' }
wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ resolution:
+ { integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== }
write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+ resolution:
+ { integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== }
+ engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 }
ws@7.4.6:
- resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==}
- engines: {node: '>=8.3.0'}
+ resolution:
+ { integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== }
+ engines: { node: '>=8.3.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
@@ -7147,8 +8809,9 @@ packages:
optional: true
ws@7.5.10:
- resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}
- engines: {node: '>=8.3.0'}
+ resolution:
+ { integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== }
+ engines: { node: '>=8.3.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
@@ -7159,8 +8822,9 @@ packages:
optional: true
ws@8.18.0:
- resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== }
+ engines: { node: '>=10.0.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
@@ -7171,8 +8835,9 @@ packages:
optional: true
ws@8.18.2:
- resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== }
+ engines: { node: '>=10.0.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
@@ -7183,8 +8848,9 @@ packages:
optional: true
ws@8.18.3:
- resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
- engines: {node: '>=10.0.0'}
+ resolution:
+ { integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== }
+ engines: { node: '>=10.0.0' }
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
@@ -7195,67 +8861,81 @@ packages:
optional: true
xtend@4.0.2:
- resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
- engines: {node: '>=0.4'}
+ resolution:
+ { integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== }
+ engines: { node: '>=0.4' }
y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== }
+ engines: { node: '>=10' }
yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ resolution:
+ { integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== }
yaml@2.7.1:
- resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
- engines: {node: '>= 14'}
+ resolution:
+ { integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ== }
+ engines: { node: '>= 14' }
hasBin: true
yaml@2.8.0:
- resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
- engines: {node: '>= 14.6'}
+ resolution:
+ { integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ== }
+ engines: { node: '>= 14.6' }
hasBin: true
yargs-parser@20.2.9:
- resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== }
+ engines: { node: '>=10' }
yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== }
+ engines: { node: '>=12' }
yargs-unparser@2.0.0:
- resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== }
+ engines: { node: '>=10' }
yargs@16.2.0:
- resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== }
+ engines: { node: '>=10' }
yargs@17.7.2:
- resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
- engines: {node: '>=12'}
+ resolution:
+ { integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== }
+ engines: { node: '>=12' }
yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
+ resolution:
+ { integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== }
+ engines: { node: '>=6' }
yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
+ resolution:
+ { integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== }
+ engines: { node: '>=10' }
zod-to-json-schema@3.24.5:
- resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
+ resolution:
+ { integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== }
peerDependencies:
zod: ^3.24.1
zod@3.24.4:
- resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==}
+ resolution:
+ { integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg== }
zod@3.25.76:
- resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+ resolution:
+ { integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== }
snapshots:
-
'@adraffy/ens-normalize@1.11.0': {}
'@ampproject/remapping@2.3.0':
diff --git a/scripts/README-testing.md b/scripts/README-testing.md
deleted file mode 100644
index 7b132bc4ab..0000000000
--- a/scripts/README-testing.md
+++ /dev/null
@@ -1,241 +0,0 @@
-# Helius RPC Provider Live Testing Scripts
-
-This directory contains comprehensive testing scripts for the Helius RPC provider integration. These scripts use real API keys and endpoints for thorough QA testing.
-
-## Prerequisites
-
-1. **Gateway Server Running**
- ```bash
- pnpm start --passphrase=test123 --dev
- ```
-
-2. **Valid Helius API Key**
- - Ensure `conf/rpc/helius.yml` contains a valid API key
- - Get your API key from [helius.dev](https://helius.dev)
-
-3. **Required Dependencies**
- ```bash
- npm install axios ws js-yaml chalk @solana/web3.js
- ```
-
-## Testing Scripts
-
-### 1. Helius Integration Test (`test-helius-live.js`)
-
-Comprehensive test of all Helius features with real API endpoints.
-
-```bash
-node scripts/test-helius-live.js
-```
-
-**Tests:**
-- ✅ Helius RPC Connection
-- ✅ WebSocket Real-time Monitoring
-- ✅ Balance Fetching via Helius
-- ✅ Token List Loading
-- ✅ Priority Fee Estimation
-- ✅ Direct Helius RPC Methods
-- ✅ Transaction Monitoring Setup
-- ✅ Performance vs Standard RPC
-
-**Expected Output:**
-```
-🚀 Helius Live Integration Tests
-
-[INFO] Running: Helius RPC Connection
-[✓] Helius RPC Connection - PASSED (245ms)
-[INFO] Running: Helius WebSocket Connection
-[✓] WebSocket connected successfully
-[✓] Helius WebSocket Connection - PASSED (1.2s)
-...
-
-📊 Test Summary
-✓ Passed: 8
-✗ Failed: 0
-Total: 8
-```
-
-### 2. Provider Switching Test (`test-provider-switching.js`)
-
-Tests dynamic switching between URL and Helius providers.
-
-```bash
-node scripts/test-provider-switching.js
-```
-
-**Tests:**
-- ✅ Current Provider Configuration
-- ✅ Switch Devnet to Helius
-- ✅ Switch Mainnet to URL
-- ✅ Invalid Provider Configuration
-- ✅ Missing Helius Configuration
-- ✅ Provider Performance Comparison
-- ✅ Configuration Schema Validation
-
-**Key Features:**
-- Temporarily modifies configs (auto-restores)
-- Tests error handling for invalid configs
-- Validates schema compliance
-- Measures performance differences
-
-### 3. Performance Benchmark (`test-helius-performance.js`)
-
-Detailed performance analysis comparing Helius vs standard RPC.
-
-```bash
-# Basic benchmark
-node scripts/test-helius-performance.js
-
-# Custom parameters
-node scripts/test-helius-performance.js --iterations=20 --concurrent=5
-```
-
-**Benchmarks:**
-- 🏁 Balance Fetching Performance
-- 🏁 Token List Loading
-- 🏁 Concurrent Request Handling
-- 🏁 Direct RPC Call Performance
-- 🏁 Priority Fee Estimation
-
-**Sample Output:**
-```
-🏁 Helius Performance Benchmark Suite
-
-[PERF] Helius Balance Fetching Performance Stats:
- Average: 189.3ms
- Median: 185.0ms
- Min: 156.0ms
- Max: 245.0ms
- 95th: 238.0ms
- 99th: 245.0ms
-
-[✓] Performance improvement: 34.2%
-
-💡 Recommendations
-✓ Helius shows better performance for balance fetching
-✓ Helius RPC endpoints are faster than standard
-✓ Helius provider shows good reliability
-```
-
-## Testing Scenarios
-
-### Scenario 1: Fresh Setup Validation
-```bash
-# 1. Clean install
-rm -rf conf/
-pnpm run setup
-
-# 2. Verify RPC provider options are presented
-# 3. Test both providers
-node scripts/test-provider-switching.js
-```
-
-### Scenario 2: Performance Validation
-```bash
-# 1. Run comprehensive performance tests
-node scripts/test-helius-performance.js --iterations=15
-
-# 2. Verify improvements
-# - Expect 30-50% faster response times
-# - Lower error rates
-# - Better concurrent handling
-```
-
-### Scenario 3: Live Integration Testing
-```bash
-# 1. Test all Helius features
-node scripts/test-helius-live.js
-
-# 2. Check server logs for:
-# - "Connecting to Helius WebSocket (mainnet) endpoint"
-# - "Connected to Helius WebSocket for transaction monitoring"
-# - "Starting Helius Sender connection warming"
-
-# 3. Verify no API key exposure in logs
-```
-
-### Scenario 4: Error Handling Validation
-```bash
-# 1. Test with invalid API key
-echo "apiKey: 'invalid-key'" > conf/rpc/helius.yml
-node scripts/test-helius-live.js
-# Should gracefully fallback to standard RPC
-
-# 2. Test missing config
-rm conf/rpc/helius.yml
-# Server should handle missing config gracefully
-```
-
-## Expected Performance Improvements
-
-When using Helius provider, expect:
-
-| Metric | Improvement | Notes |
-|--------|-------------|-------|
-| **Balance Fetching** | 30-50% faster | Optimized RPC endpoints |
-| **Token List Loading** | 15-25% faster | Cached responses |
-| **Concurrent Requests** | 40-60% better | Higher rate limits |
-| **Priority Fees** | Real-time data | More accurate estimation |
-| **WebSocket Monitoring** | Real-time | vs polling-based |
-
-## Troubleshooting
-
-### Common Issues
-
-1. **WebSocket 401 Errors**
- ```
- Error: Unexpected server response: 401
- ```
- - Check API key in `conf/rpc/helius.yml`
- - Ensure key has WebSocket permissions
-
-2. **Config Not Loading**
- ```
- Error: Configuration paths must have at least two components
- ```
- - Restart Gateway server after config changes
- - Verify `conf/rpc/helius.yml` exists
-
-3. **Performance Not Improving**
- - Verify mainnet is using Helius (`rpcProvider: 'helius'`)
- - Check API key is valid and has rate limit headroom
- - Compare same operations (mainnet vs mainnet, not mainnet vs devnet)
-
-### Debug Mode
-
-Enable debug logging:
-```bash
-# Set log level to debug in server config
-# Check logs for detailed Helius service initialization
-tail -f logs/logs_gateway_app.log | grep -i helius
-```
-
-## QA Checklist
-
-- [ ] All integration tests pass (`test-helius-live.js`)
-- [ ] Provider switching works (`test-provider-switching.js`)
-- [ ] Performance improvements confirmed (`test-helius-performance.js`)
-- [ ] WebSocket connections establish successfully
-- [ ] No API keys logged in clear text
-- [ ] Error handling works for invalid configs
-- [ ] Backward compatibility maintained
-- [ ] Server restarts cleanly with new configs
-- [ ] Schema validation prevents invalid configurations
-- [ ] Both devnet (URL) and mainnet (Helius) work simultaneously
-
-## Security Notes
-
-⚠️ **Important**: These scripts use real API keys and make actual network requests.
-
-- Scripts automatically mask API keys in output
-- Test data uses read-only operations
-- No private keys or transactions are involved
-- API keys are loaded from config files, not hardcoded
-
-## Support
-
-For issues with these testing scripts:
-1. Check Gateway server is running and accessible
-2. Verify Helius API key is valid and has sufficient quota
-3. Ensure all dependencies are installed
-4. Review server logs for detailed error messages
\ No newline at end of file
diff --git a/scripts/add-bsc-tokens.ts b/scripts/add-bsc-tokens.ts
index f7a55f436f..2582c81c42 100644
--- a/scripts/add-bsc-tokens.ts
+++ b/scripts/add-bsc-tokens.ts
@@ -43,11 +43,7 @@ async function fetchTokenMetadata(address: string) {
const ethereum = await Ethereum.getInstance(NETWORK);
const contract = new Contract(address, ERC20_ABI, ethereum.provider);
- const [name, symbol, decimals] = await Promise.all([
- contract.name(),
- contract.symbol(),
- contract.decimals(),
- ]);
+ const [name, symbol, decimals] = await Promise.all([contract.name(), contract.symbol(), contract.decimals()]);
return {
chainId: BSC_CHAIN_ID,
@@ -99,9 +95,7 @@ async function addTokens() {
}
// Merge and sort by symbol
- const allTokens = [...existingTokens, ...newTokens].sort((a, b) =>
- a.symbol.localeCompare(b.symbol)
- );
+ const allTokens = [...existingTokens, ...newTokens].sort((a, b) => a.symbol.localeCompare(b.symbol));
// Write updated token list
fs.writeFileSync(TOKEN_FILE, JSON.stringify(allTokens, null, 2));
diff --git a/scripts/add-pancakeswap-pools.ts b/scripts/add-pancakeswap-pools.ts
index 094946c3af..79edb6ad58 100644
--- a/scripts/add-pancakeswap-pools.ts
+++ b/scripts/add-pancakeswap-pools.ts
@@ -41,7 +41,7 @@ const TEMPLATE_PATH = path.join(__dirname, '../src/templates/pools/pancakeswap.j
async function fetchPancakeswapPoolInfo(
poolAddress: string,
- type: 'amm' | 'clmm'
+ type: 'amm' | 'clmm',
): Promise<{
baseTokenAddress: string;
quoteTokenAddress: string;
diff --git a/scripts/generate-openapi.ts b/scripts/generate-openapi.ts
new file mode 100644
index 0000000000..ea8895e527
--- /dev/null
+++ b/scripts/generate-openapi.ts
@@ -0,0 +1,90 @@
+/**
+ * Write the OpenAPI spec to openapi.json without starting a server.
+ *
+ * The previous `generate:openapi` curled http://localhost:15888/docs/json, so
+ * regenerating meant standing up a Gateway first — which kept the committed spec
+ * from being refreshed in CI, and let it drift from the routes. @fastify/swagger
+ * can produce the document from the route table alone once the app is ready, so
+ * this needs nothing running.
+ *
+ * Run with: pnpm generate:openapi
+ */
+import fs from 'fs';
+import path from 'path';
+
+// The app builds an HTTPS server unless it is in dev mode, and HTTPS needs the
+// cert passphrase. Spec generation touches no sockets, so force dev mode before
+// importing the app.
+process.env.GATEWAY_TEST_MODE = 'dev';
+
+/**
+ * The port the shipped template configures, rather than the one this machine runs on.
+ *
+ * `servers[0].url` is built from `server.port`, so a developer who moved Gateway off the
+ * default wrote their port into the committed spec — the same way the wallet defaults
+ * were written in, and with the same effect: the artifact could not match what another
+ * machine produces.
+ */
+function templateServerPort(): number {
+ const template = fs.readFileSync(path.resolve(__dirname, '..', 'src', 'templates', 'server.yml'), 'utf8');
+ const match = template.match(/^port:\s*(\d+)/m);
+ if (!match) {
+ throw new Error("No `port` in src/templates/server.yml; the spec would carry this machine's port.");
+ }
+ return Number(match[1]);
+}
+
+/**
+ * Replace this machine's configured wallets with the placeholders the templates ship.
+ *
+ * The execute routes default `walletAddress` to the chain config's `defaultWallet`, which
+ * is right at runtime — a caller who omits it means "the wallet I configured" — and wrong
+ * in a committed artifact. The spec is checked in and vendored by consumers, so whoever
+ * regenerated it last had their address published, and the file could never match what
+ * another machine or CI produces. `src/templates/chains/*.yml` already use these
+ * placeholders; this makes the artifact agree with them.
+ */
+function withoutLocalWallets(json: string): string {
+ const placeholders: Array<[string, string]> = [];
+
+ try {
+ const { getSolanaChainConfig } = require('../src/chains/solana/solana.config');
+ placeholders.push([getSolanaChainConfig().defaultWallet, '']);
+ } catch {
+ // No Solana config here; nothing of its to redact.
+ }
+ try {
+ const { getEthereumChainConfig } = require('../src/chains/ethereum/ethereum.config');
+ placeholders.push([getEthereumChainConfig().defaultWallet, '']);
+ } catch {
+ // Likewise for Ethereum.
+ }
+
+ return placeholders.reduce(
+ (text, [wallet, placeholder]) => (wallet && !wallet.startsWith('<') ? text.split(wallet).join(placeholder) : text),
+ json,
+ );
+}
+
+async function main() {
+ const { gatewayApp } = await import('../src/app');
+
+ await gatewayApp.ready();
+ const spec = (gatewayApp as any).swagger();
+
+ // The document describes Gateway, not this checkout of it.
+ spec.servers = [{ url: `http://localhost:${templateServerPort()}` }];
+
+ const outPath = path.resolve(__dirname, '..', 'openapi.json');
+ fs.writeFileSync(outPath, `${withoutLocalWallets(JSON.stringify(spec, null, 2))}\n`);
+
+ const paths = Object.keys(spec.paths ?? {});
+ console.log(`OpenAPI spec written to ${outPath} (${paths.length} paths)`);
+
+ await gatewayApp.close();
+}
+
+main().catch((e) => {
+ console.error('Failed to generate the OpenAPI spec:', e);
+ process.exit(1);
+});
diff --git a/scripts/migrate-pool-templates.ts b/scripts/migrate-pool-templates.ts
index 91f1d0bb9b..5372d06bc7 100644
--- a/scripts/migrate-pool-templates.ts
+++ b/scripts/migrate-pool-templates.ts
@@ -33,7 +33,11 @@ interface PoolInfo {
feePct: number;
}
-async function fetchRaydiumPoolInfo(type: 'amm' | 'clmm', network: string, poolAddress: string): Promise {
+async function fetchRaydiumPoolInfo(
+ type: 'amm' | 'clmm',
+ network: string,
+ poolAddress: string,
+): Promise {
try {
const raydium = await Raydium.getInstance(network);
@@ -73,7 +77,11 @@ async function fetchMeteoraPoolInfo(network: string, poolAddress: string): Promi
}
}
-async function fetchUniswapPoolInfo(type: 'amm' | 'clmm', network: string, poolAddress: string): Promise {
+async function fetchUniswapPoolInfo(
+ type: 'amm' | 'clmm',
+ network: string,
+ poolAddress: string,
+): Promise {
try {
const uniswap = await Uniswap.getInstance(network);
const ethereum = await Ethereum.getInstance(network);
diff --git a/scripts/test-chainstack-live.ts b/scripts/test-chainstack-live.ts
deleted file mode 100644
index fc31902050..0000000000
--- a/scripts/test-chainstack-live.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/usr/bin/env -S npx ts-node
-
-/**
- * Live Chainstack Integration Testing Script
- *
- * Verifies the Chainstack RPC provider integration with a real API key.
- * Hits the Gateway's chain status endpoints for every Chainstack-supported
- * network and exercises Solana transaction monitoring if a Solana node exists.
- *
- * Prerequisites:
- * - Valid Chainstack API key configured in conf/apiKeys.yml under `chainstack`
- * - Gateway chains/solana.yml and chains/ethereum.yml use `rpcProvider: chainstack`
- * - At least one running Chainstack node matching each network you want to test
- * - Gateway server running: pnpm start --passphrase=test123 --dev
- *
- * Usage: npx ts-node scripts/test-chainstack-live.ts
- */
-
-import fs from 'fs';
-import path from 'path';
-
-import axios from 'axios';
-
-import { ChainstackService } from '../src/rpc/chainstack-service';
-
-const GATEWAY_URL = 'http://localhost:15888';
-const CHAINSTACK_API = 'https://api.chainstack.com/v1/nodes';
-
-interface TestResult {
- name: string;
- status: 'passed' | 'failed';
- duration?: number;
- error?: string;
-}
-
-const tests: { passed: number; failed: number; results: TestResult[] } = {
- passed: 0,
- failed: 0,
- results: [],
-};
-
-type LogType = 'info' | 'success' | 'error' | 'warn' | 'test';
-
-function log(message: string, type: LogType = 'info'): void {
- const timestamp = new Date().toISOString();
- const colors: Record = {
- info: '\x1b[34m[INFO]\x1b[0m',
- success: '\x1b[32m[✓]\x1b[0m',
- error: '\x1b[31m[✗]\x1b[0m',
- warn: '\x1b[33m[WARN]\x1b[0m',
- test: '\x1b[36m[TEST]\x1b[0m',
- };
- console.log(`${timestamp} ${colors[type] || colors.info} ${message}`);
-}
-
-async function testCase(name: string, fn: () => Promise): Promise {
- log(`Running: ${name}`, 'test');
- try {
- const startTime = Date.now();
- await fn();
- const duration = Date.now() - startTime;
- tests.passed++;
- tests.results.push({ name, status: 'passed', duration });
- log(`✓ ${name} (${duration}ms)`, 'success');
- } catch (error: any) {
- tests.failed++;
- tests.results.push({ name, status: 'failed', error: error.message });
- log(`✗ ${name}: ${error.message}`, 'error');
- }
-}
-
-// Per-network expected chainIds. Chain IDs are gateway-side metadata, not
-// Chainstack's concern; the supported network list itself comes from
-// ChainstackService.getSupportedNetworks() so it stays in sync.
-const EXPECTED_CHAIN_IDS: Record = {
- 'ethereum:mainnet': 1,
- 'ethereum:arbitrum': 42161,
- 'ethereum:polygon': 137,
- 'ethereum:optimism': 10,
- 'ethereum:base': 8453,
- 'ethereum:avalanche': 43114,
- 'ethereum:bsc': 56,
- 'ethereum:celo': 42220,
- 'ethereum:sepolia': 11155111,
-};
-
-async function readChainstackApiKey(): Promise {
- const apiKeysPath = path.join(process.cwd(), 'conf', 'apiKeys.yml');
- if (!fs.existsSync(apiKeysPath)) return '';
- const contents = fs.readFileSync(apiKeysPath, 'utf8');
- const match = contents.match(/^chainstack:\s*['"]?([^'"\s]+)['"]?/m);
- return match ? match[1] : '';
-}
-
-async function listChainstackNodes(apiKey: string): Promise {
- const response = await axios.get(CHAINSTACK_API, {
- headers: { Authorization: `Bearer ${apiKey}` },
- timeout: 10000,
- });
- const data = response.data;
- return Array.isArray(data) ? data : data.results || [];
-}
-
-async function testChainStatus({
- chain,
- network,
- expectedChainId,
-}: {
- chain: 'solana' | 'ethereum';
- network: string;
- expectedChainId?: number;
-}): Promise {
- const response = await axios.get(`${GATEWAY_URL}/chains/${chain}/status?network=${network}`);
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
- const data = response.data;
- if (expectedChainId !== undefined && data.chainId !== expectedChainId) {
- throw new Error(`Expected chainId ${expectedChainId}, got ${data.chainId}`);
- }
- log(`${chain}/${network}: chainId=${data.chainId ?? 'n/a'}, block=${data.blockNumber ?? 'n/a'}`, 'info');
-}
-
-async function runTests(): Promise {
- log('🚀 Starting Chainstack Integration Tests', 'info');
-
- const apiKey = await readChainstackApiKey();
- if (!apiKey) {
- log('No chainstack key found in conf/apiKeys.yml — skipping Platform API discovery', 'warn');
- } else {
- await testCase('Chainstack Platform API: list_nodes', async () => {
- const nodes = await listChainstackNodes(apiKey);
- log(`Discovered ${nodes.length} Chainstack node(s)`, 'info');
- nodes.forEach((n: any) =>
- log(` - ${n.id} ${n.protocol}/${n.network} [${n.status}]`, 'info'),
- );
- });
- }
-
- for (const { chain, network } of ChainstackService.getSupportedNetworks()) {
- const expectedChainId = EXPECTED_CHAIN_IDS[`${chain}:${network}`];
- await testCase(`Chain status: ${chain}/${network}`, () =>
- testChainStatus({ chain, network, expectedChainId }),
- );
- }
-
- log('', 'info');
- log('=== Test Summary ===', 'info');
- log(`Total: ${tests.passed + tests.failed}`, 'info');
- log(`Passed: ${tests.passed}`, tests.passed > 0 ? 'success' : 'info');
- log(`Failed: ${tests.failed}`, tests.failed > 0 ? 'error' : 'info');
-
- if (tests.failed > 0) {
- log('', 'info');
- log('Failed tests:', 'error');
- tests.results
- .filter((r) => r.status === 'failed')
- .forEach((r) => log(` - ${r.name}: ${r.error}`, 'error'));
- process.exit(1);
- }
-}
-
-runTests().catch((err) => {
- log(`Fatal: ${err.message}`, 'error');
- process.exit(1);
-});
diff --git a/scripts/test-clmm-approvals.js b/scripts/test-clmm-approvals.js
deleted file mode 100755
index ddbcbe9b73..0000000000
--- a/scripts/test-clmm-approvals.js
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Test script for CLMM dual approval functionality
- * Tests both Uniswap and PancakeSwap CLMM approve/allowances endpoints
- */
-
-const axios = require('axios');
-
-const API_URL = 'http://localhost:15888';
-
-// Test configuration
-const TEST_CONFIG = {
- network: 'mainnet',
- address: '0xDA50C69342216b538Daf06FfECDa7363E0B96684',
- tokens: ['USDC', 'WETH'],
-};
-
-async function testAllowances(spender, description) {
- console.log(`\n📊 Testing allowances for ${description}...`);
-
- try {
- const response = await axios.post(`${API_URL}/chains/ethereum/allowances`, {
- chain: 'ethereum',
- network: TEST_CONFIG.network,
- address: TEST_CONFIG.address,
- spender: spender,
- tokens: TEST_CONFIG.tokens,
- });
-
- console.log(`✅ Allowances response:`, JSON.stringify(response.data, null, 2));
-
- // Check if spender contains both addresses for CLMM
- if (spender.includes('/clmm')) {
- const spenderAddresses = response.data.spender.split(',');
- if (spenderAddresses.length === 2) {
- console.log(`✅ CLMM dual addresses returned:`);
- console.log(` - SwapRouter02: ${spenderAddresses[0]}`);
- console.log(` - NftManager: ${spenderAddresses[1]}`);
- } else {
- console.log(`⚠️ Expected 2 addresses for CLMM, got: ${response.data.spender}`);
- }
- }
-
- return response.data;
- } catch (error) {
- console.error(`❌ Error testing allowances:`, error.response?.data || error.message);
- return null;
- }
-}
-
-async function testApprove(spender, token, amount, description) {
- console.log(`\n🔐 Testing approve for ${description}...`);
- console.log(` Token: ${token}, Amount: ${amount || 'MAX'}`);
-
- try {
- const response = await axios.post(`${API_URL}/chains/ethereum/approve`, {
- chain: 'ethereum',
- network: TEST_CONFIG.network,
- address: TEST_CONFIG.address,
- spender: spender,
- token: token,
- amount: amount,
- });
-
- console.log(`✅ Approve response:`, JSON.stringify(response.data, null, 2));
-
- // Check if spender contains both addresses for CLMM
- if (spender.includes('/clmm') && response.data.data.spender.includes(',')) {
- const spenderAddresses = response.data.data.spender.split(',');
- console.log(`✅ CLMM dual approval completed for:`);
- console.log(` - SwapRouter02: ${spenderAddresses[0]}`);
- console.log(` - NftManager: ${spenderAddresses[1]}`);
- }
-
- return response.data;
- } catch (error) {
- console.error(`❌ Error testing approve:`, error.response?.data || error.message);
- return null;
- }
-}
-
-async function runTests() {
- console.log('🚀 Starting CLMM Dual Approval Tests');
- console.log('=====================================');
- console.log(`Network: ${TEST_CONFIG.network}`);
- console.log(`Address: ${TEST_CONFIG.address}`);
- console.log(`Tokens: ${TEST_CONFIG.tokens.join(', ')}`);
-
- // Test Uniswap CLMM
- console.log('\n\n=== UNISWAP CLMM TESTS ===');
- await testAllowances('uniswap/clmm', 'Uniswap CLMM');
-
- // Note: Approve will actually submit a transaction if a valid wallet is configured
- // Uncomment below to test approve functionality (requires wallet with funds)
- // await testApprove('uniswap/clmm', 'USDC', '100', 'Uniswap CLMM');
-
- // Test PancakeSwap CLMM
- console.log('\n\n=== PANCAKESWAP CLMM TESTS ===');
- await testAllowances('pancakeswap/clmm', 'PancakeSwap CLMM');
-
- // Note: Approve will actually submit a transaction if a valid wallet is configured
- // Uncomment below to test approve functionality (requires wallet with funds)
- // await testApprove('pancakeswap/clmm', 'USDC', '100', 'PancakeSwap CLMM');
-
- // Test regular connectors for comparison
- console.log('\n\n=== COMPARISON TESTS ===');
- await testAllowances('uniswap/amm', 'Uniswap AMM (V2)');
- await testAllowances('pancakeswap/amm', 'PancakeSwap AMM (V2)');
-
- console.log('\n\n✅ Tests completed!');
-}
-
-// Run tests
-runTests().catch(console.error);
\ No newline at end of file
diff --git a/scripts/test-helius-live.js b/scripts/test-helius-live.js
deleted file mode 100644
index 1a924a3a75..0000000000
--- a/scripts/test-helius-live.js
+++ /dev/null
@@ -1,325 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Live Helius Integration Testing Script
- *
- * This script tests the Helius RPC provider integration with a real API key.
- * It verifies WebSocket connections, Sender endpoints, and RPC functionality.
- *
- * Prerequisites:
- * - Valid Helius API key configured in conf/rpc/helius.yml
- * - Gateway server running: pnpm start --passphrase=test123 --dev
- *
- * Usage: node scripts/test-helius-live.js
- */
-
-const axios = require('axios');
-const WebSocket = require('ws');
-const { Connection, PublicKey, LAMPORTS_PER_SOL } = require('@solana/web3.js');
-
-const GATEWAY_URL = 'http://localhost:15888';
-const TEST_WALLET = 'AabEVCB1sWgCPxbn6hFYM4Ukj7UubpBRbbYqRnqRXnZD';
-
-// Test configuration
-const tests = {
- passed: 0,
- failed: 0,
- results: []
-};
-
-// Helper functions (using simple console colors)
-function log(message, type = 'info') {
- const timestamp = new Date().toISOString();
- const colors = {
- info: '\x1b[34m[INFO]\x1b[0m', // blue
- success: '\x1b[32m[✓]\x1b[0m', // green
- error: '\x1b[31m[✗]\x1b[0m', // red
- warn: '\x1b[33m[WARN]\x1b[0m', // yellow
- test: '\x1b[36m[TEST]\x1b[0m' // cyan
- };
- console.log(`${timestamp} ${colors[type] || colors.info} ${message}`);
-}
-
-async function testCase(name, fn) {
- log(`Running: ${name}`, 'test');
- try {
- const startTime = Date.now();
- await fn();
- const duration = Date.now() - startTime;
- tests.passed++;
- tests.results.push({ name, status: 'passed', duration });
- log(`${name} - PASSED (${duration}ms)`, 'success');
- return true;
- } catch (error) {
- tests.failed++;
- tests.results.push({ name, status: 'failed', error: error.message });
- log(`${name} - FAILED: ${error.message}`, 'error');
- return false;
- }
-}
-
-// Test 1: Verify Helius RPC Connection
-async function testHeliusRPCConnection() {
- const response = await axios.post(`${GATEWAY_URL}/chains/solana/status`, {
- network: 'mainnet-beta'
- });
-
- if (!response.data.rpcUrl) {
- throw new Error('RPC URL not returned in status');
- }
-
- // Check if using Helius RPC - parse URL to properly validate hostname
- try {
- const urlObj = new URL(response.data.rpcUrl);
- const allowedHeliusHosts = [
- 'mainnet.helius-rpc.com',
- 'devnet.helius-rpc.com',
- 'rpc.helius.xyz',
- 'mainnet-beta.helius-rpc.com'
- ];
-
- if (!allowedHeliusHosts.includes(urlObj.hostname)) {
- log('Warning: Not using Helius RPC URL', 'warn');
- }
- } catch (error) {
- log(`Warning: Could not parse RPC URL: ${error.message}`, 'warn');
- }
-
- return response.data;
-}
-
-// Test 2: Test Helius WebSocket Connection
-async function testHeliusWebSocket() {
- return new Promise((resolve, reject) => {
- // Read Helius config to get API key
- const fs = require('fs');
- const yaml = require('js-yaml');
- const configPath = './conf/rpc/helius.yml';
-
- if (!fs.existsSync(configPath)) {
- reject(new Error('Helius config not found'));
- return;
- }
-
- const config = yaml.load(fs.readFileSync(configPath, 'utf8'));
- const apiKey = config.apiKey;
-
- if (!apiKey || apiKey === '') {
- reject(new Error('Helius API key not configured'));
- return;
- }
-
- const wsUrl = `wss://mainnet.helius-rpc.com/?api-key=${apiKey}`;
- const ws = new WebSocket(wsUrl);
-
- const timeout = setTimeout(() => {
- ws.close();
- reject(new Error('WebSocket connection timeout'));
- }, 10000);
-
- ws.on('open', () => {
- log('WebSocket connected successfully', 'success');
-
- // Test subscription
- const subscribeMsg = {
- jsonrpc: '2.0',
- id: 1,
- method: 'programSubscribe',
- params: [
- 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', // Token Program
- { encoding: 'jsonParsed' }
- ]
- };
-
- ws.send(JSON.stringify(subscribeMsg));
- });
-
- ws.on('message', (data) => {
- const msg = JSON.parse(data.toString());
- if (msg.result) {
- log(`WebSocket subscription ID: ${msg.result}`, 'info');
- clearTimeout(timeout);
- ws.close();
- resolve(msg.result);
- }
- });
-
- ws.on('error', (error) => {
- clearTimeout(timeout);
- reject(error);
- });
- });
-}
-
-// Test 3: Test Balance Fetching with Helius
-async function testBalanceFetching() {
- const response = await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'mainnet-beta',
- tokenSymbols: ['SOL']
- });
-
- if (!response.data.balances) {
- throw new Error('No balances returned');
- }
-
- const solBalance = response.data.balances.SOL;
- log(`SOL Balance: ${solBalance || 0}`, 'info');
-
- return response.data;
-}
-
-// Test 4: Test Token List Loading
-async function testTokenList() {
- const response = await axios.post(`${GATEWAY_URL}/chains/solana/tokens`, {
- network: 'mainnet-beta'
- });
-
- if (!response.data.tokens || !Array.isArray(response.data.tokens)) {
- throw new Error('Invalid token list response');
- }
-
- log(`Loaded ${response.data.tokens.length} tokens`, 'info');
- return response.data;
-}
-
-// Test 5: Test Priority Fee Estimation
-async function testPriorityFeeEstimation() {
- const response = await axios.get(`${GATEWAY_URL}/chains/solana/estimate-gas?network=mainnet-beta`);
-
- if (!response.data.priorityFee) {
- throw new Error('No priority fee returned');
- }
-
- log(`Priority Fee: ${response.data.priorityFee} microlamports/CU`, 'info');
- log(`Min Priority Fee: ${response.data.minPriorityFeePerCU} microlamports/CU`, 'info');
-
- return response.data;
-}
-
-// Test 6: Test Helius RPC Methods Directly
-async function testHeliusRPCMethods() {
- const fs = require('fs');
- const yaml = require('js-yaml');
- const configPath = './conf/rpc/helius.yml';
-
- const config = yaml.load(fs.readFileSync(configPath, 'utf8'));
- const apiKey = config.apiKey;
-
- const rpcUrl = `https://mainnet.helius-rpc.com/?api-key=${apiKey}`;
- const connection = new Connection(rpcUrl, 'confirmed');
-
- // Test getLatestBlockhash
- const blockhash = await connection.getLatestBlockhash();
- log(`Latest blockhash: ${blockhash.blockhash}`, 'info');
-
- // Test getBalance
- const pubkey = new PublicKey(TEST_WALLET);
- const balance = await connection.getBalance(pubkey);
- log(`Direct RPC Balance: ${balance / LAMPORTS_PER_SOL} SOL`, 'info');
-
- // Test getAccountInfo
- const accountInfo = await connection.getAccountInfo(pubkey);
- log(`Account exists: ${accountInfo !== null}`, 'info');
-
- return { blockhash, balance, accountInfo: accountInfo !== null };
-}
-
-// Test 7: Test Transaction Monitoring Setup
-async function testTransactionMonitoring() {
- // This tests if the Helius service is properly initialized with WebSocket
- const response = await axios.post(`${GATEWAY_URL}/chains/solana/status`, {
- network: 'mainnet-beta'
- });
-
- // Check server logs for WebSocket initialization
- log('Check server logs for: "Connecting to Helius WebSocket (mainnet) endpoint"', 'info');
- log('Check server logs for: "Connected to Helius WebSocket for transaction monitoring"', 'info');
-
- return response.data;
-}
-
-// Test 8: Performance Comparison
-async function testPerformanceComparison() {
- const results = {
- helius: {},
- standard: {}
- };
-
- // Test with Helius (mainnet-beta uses Helius)
- const heliusStart = Date.now();
- const heliusResponse = await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'mainnet-beta',
- tokenSymbols: ['SOL']
- });
- results.helius.duration = Date.now() - heliusStart;
- results.helius.success = !!heliusResponse.data.balances;
-
- // Test with standard RPC (devnet uses standard)
- const standardStart = Date.now();
- const standardResponse = await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'devnet',
- tokenSymbols: ['SOL']
- });
- results.standard.duration = Date.now() - standardStart;
- results.standard.success = !!standardResponse.data.balances;
-
- log(`Helius RPC: ${results.helius.duration}ms`, 'info');
- log(`Standard RPC: ${results.standard.duration}ms`, 'info');
-
- const improvement = ((results.standard.duration - results.helius.duration) / results.standard.duration * 100).toFixed(1);
- log(`Performance improvement: ${improvement}%`, 'info');
-
- return results;
-}
-
-// Main test runner
-async function runTests() {
- console.log('\n\x1b[1m\x1b[36m🚀 Helius Live Integration Tests\x1b[0m\n');
- console.log('\x1b[90mTesting Helius RPC provider with real API key...\x1b[0m\n');
-
- // Check if server is running
- try {
- await axios.get(`${GATEWAY_URL}/`);
- } catch (error) {
- log('Gateway server is not running. Start it with: pnpm start --passphrase=test123 --dev', 'error');
- process.exit(1);
- }
-
- // Run all tests
- await testCase('Helius RPC Connection', testHeliusRPCConnection);
- await testCase('Helius WebSocket Connection', testHeliusWebSocket);
- await testCase('Balance Fetching via Helius', testBalanceFetching);
- await testCase('Token List Loading', testTokenList);
- await testCase('Priority Fee Estimation', testPriorityFeeEstimation);
- await testCase('Direct Helius RPC Methods', testHeliusRPCMethods);
- await testCase('Transaction Monitoring Setup', testTransactionMonitoring);
- await testCase('Performance Comparison', testPerformanceComparison);
-
- // Print summary
- console.log('\n\x1b[1m\x1b[36m📊 Test Summary\x1b[0m\n');
- console.log(`\x1b[32m✓ Passed: ${tests.passed}\x1b[0m`);
- console.log(`\x1b[31m✗ Failed: ${tests.failed}\x1b[0m`);
- console.log(`\x1b[34mTotal: ${tests.passed + tests.failed}\x1b[0m`);
-
- // Print detailed results
- console.log('\n\x1b[1m\x1b[36m📋 Detailed Results\x1b[0m\n');
- tests.results.forEach(result => {
- const icon = result.status === 'passed' ? '✓' : '✗';
- const color = result.status === 'passed' ? '\x1b[32m' : '\x1b[31m';
- const duration = result.duration ? ` (${result.duration}ms)` : '';
- const error = result.error ? ` - ${result.error}` : '';
- console.log(`${color}${icon} ${result.name}${duration}${error}\x1b[0m`);
- });
-
- // Exit code based on test results
- process.exit(tests.failed > 0 ? 1 : 0);
-}
-
-// Run tests
-runTests().catch(error => {
- log(`Fatal error: ${error.message}`, 'error');
- process.exit(1);
-});
\ No newline at end of file
diff --git a/scripts/test-helius-performance.js b/scripts/test-helius-performance.js
deleted file mode 100644
index 4e18f7c606..0000000000
--- a/scripts/test-helius-performance.js
+++ /dev/null
@@ -1,371 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Helius Performance Benchmark Script
- *
- * This script benchmarks Helius vs standard RPC performance across different operations.
- * It measures latency, throughput, and reliability of both providers.
- *
- * Prerequisites:
- * - Valid Helius API key configured in conf/rpc/helius.yml
- * - Gateway server running: pnpm start --passphrase=test123 --dev
- *
- * Usage: node scripts/test-helius-performance.js [--iterations=10] [--concurrent=3]
- */
-
-const axios = require('axios');
-const { Connection, PublicKey, LAMPORTS_PER_SOL } = require('@solana/web3.js');
-const fs = require('fs');
-const yaml = require('js-yaml');
-
-const GATEWAY_URL = 'http://localhost:15888';
-const TEST_WALLET = 'AabEVCB1sWgCPxbn6hFYM4Ukj7UubpBRbbYqRnqRXnZD';
-const TEST_WALLETS = [
- 'AabEVCB1sWgCPxbn6hFYM4Ukj7UubpBRbbYqRnqRXnZD',
- 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
- 'So11111111111111111111111111111111111111112'
-];
-
-// Parse command line arguments
-const args = process.argv.slice(2);
-const iterations = parseInt(args.find(arg => arg.startsWith('--iterations='))?.split('=')[1]) || 10;
-const concurrent = parseInt(args.find(arg => arg.startsWith('--concurrent='))?.split('=')[1]) || 3;
-
-function log(message, type = 'info') {
- const timestamp = new Date().toISOString();
- const prefix = {
- info: '[INFO]',
- success: '[✓]',
- error: '[✗]',
- warn: '[WARN]',
- perf: '[PERF]'
- };
- console.log(`${timestamp} ${prefix[type] || prefix.info} ${message}`);
-}
-
-function calculateStats(times) {
- const sorted = times.slice().sort((a, b) => a - b);
- const avg = times.reduce((a, b) => a + b, 0) / times.length;
- const median = sorted.length % 2 === 0
- ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2
- : sorted[Math.floor(sorted.length / 2)];
- const min = Math.min(...times);
- const max = Math.max(...times);
- const p95 = sorted[Math.floor(sorted.length * 0.95)];
- const p99 = sorted[Math.floor(sorted.length * 0.99)];
-
- return { avg, median, min, max, p95, p99 };
-}
-
-function printStats(name, stats) {
- log(`${name} Performance Stats:`, 'perf');
- console.log(` Average: ${stats.avg.toFixed(1)}ms`);
- console.log(` Median: ${stats.median.toFixed(1)}ms`);
- console.log(` Min: ${stats.min.toFixed(1)}ms`);
- console.log(` Max: ${stats.max.toFixed(1)}ms`);
- console.log(` 95th: ${stats.p95.toFixed(1)}ms`);
- console.log(` 99th: ${stats.p99.toFixed(1)}ms`);
-}
-
-// Benchmark 1: Balance fetching performance
-async function benchmarkBalanceFetching() {
- log('Benchmarking balance fetching...', 'perf');
-
- const heliusTimes = [];
- const standardTimes = [];
- const errors = { helius: 0, standard: 0 };
-
- // Test Helius provider (mainnet-beta)
- for (let i = 0; i < iterations; i++) {
- try {
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'mainnet-beta',
- tokenSymbols: ['SOL']
- });
- heliusTimes.push(Date.now() - start);
- } catch (error) {
- errors.helius++;
- log(`Helius error ${i}: ${error.message}`, 'error');
- }
- }
-
- // Test standard provider (devnet)
- for (let i = 0; i < iterations; i++) {
- try {
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'devnet',
- tokenSymbols: ['SOL']
- });
- standardTimes.push(Date.now() - start);
- } catch (error) {
- errors.standard++;
- log(`Standard error ${i}: ${error.message}`, 'error');
- }
- }
-
- const heliusStats = calculateStats(heliusTimes);
- const standardStats = calculateStats(standardTimes);
-
- printStats('Helius Balance Fetching', heliusStats);
- printStats('Standard Balance Fetching', standardStats);
-
- const improvement = ((standardStats.avg - heliusStats.avg) / standardStats.avg * 100).toFixed(1);
- log(`Performance improvement: ${improvement}%`, 'success');
- log(`Error rates - Helius: ${errors.helius}/${iterations}, Standard: ${errors.standard}/${iterations}`, 'info');
-
- return { heliusStats, standardStats, errors, improvement };
-}
-
-// Benchmark 2: Token list loading performance
-async function benchmarkTokenList() {
- log('Benchmarking token list loading...', 'perf');
-
- const heliusTimes = [];
- const standardTimes = [];
-
- // Test Helius provider
- for (let i = 0; i < Math.min(iterations, 5); i++) { // Fewer iterations for token list
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/tokens`, {
- network: 'mainnet-beta'
- });
- heliusTimes.push(Date.now() - start);
- }
-
- // Test standard provider
- for (let i = 0; i < Math.min(iterations, 5); i++) {
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/tokens`, {
- network: 'devnet'
- });
- standardTimes.push(Date.now() - start);
- }
-
- const heliusStats = calculateStats(heliusTimes);
- const standardStats = calculateStats(standardTimes);
-
- printStats('Helius Token List', heliusStats);
- printStats('Standard Token List', standardStats);
-
- return { heliusStats, standardStats };
-}
-
-// Benchmark 3: Concurrent request handling
-async function benchmarkConcurrentRequests() {
- log(`Benchmarking concurrent requests (${concurrent} concurrent)...`, 'perf');
-
- const testConcurrentRequests = async (network, label) => {
- const times = [];
- const errors = [];
-
- for (let batch = 0; batch < Math.floor(iterations / concurrent); batch++) {
- const promises = [];
- const batchStart = Date.now();
-
- for (let i = 0; i < concurrent; i++) {
- const promise = axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLETS[i % TEST_WALLETS.length],
- network,
- tokenSymbols: ['SOL']
- }).catch(error => {
- errors.push(error.message);
- return null;
- });
- promises.push(promise);
- }
-
- await Promise.all(promises);
- times.push(Date.now() - batchStart);
- }
-
- return { times, errors };
- };
-
- const heliusResults = await testConcurrentRequests('mainnet-beta', 'Helius');
- const standardResults = await testConcurrentRequests('devnet', 'Standard');
-
- const heliusStats = calculateStats(heliusResults.times);
- const standardStats = calculateStats(standardResults.times);
-
- printStats(`Helius Concurrent (${concurrent} req/batch)`, heliusStats);
- printStats(`Standard Concurrent (${concurrent} req/batch)`, standardStats);
-
- log(`Helius errors: ${heliusResults.errors.length}`, 'info');
- log(`Standard errors: ${standardResults.errors.length}`, 'info');
-
- return { heliusStats, standardStats, errors: { helius: heliusResults.errors, standard: standardResults.errors } };
-}
-
-// Benchmark 4: Direct RPC call performance
-async function benchmarkDirectRPC() {
- log('Benchmarking direct RPC calls...', 'perf');
-
- // Get Helius config
- const configPath = './conf/rpc/helius.yml';
- if (!fs.existsSync(configPath)) {
- log('Helius config not found, skipping direct RPC test', 'warn');
- return null;
- }
-
- const config = yaml.load(fs.readFileSync(configPath, 'utf8'));
- const apiKey = config.apiKey;
-
- const heliusRpcUrl = `https://mainnet.helius-rpc.com/?api-key=${apiKey}`;
- const standardRpcUrl = 'https://api.mainnet-beta.solana.com';
-
- const heliusConnection = new Connection(heliusRpcUrl, 'confirmed');
- const standardConnection = new Connection(standardRpcUrl, 'confirmed');
-
- const testWallet = new PublicKey(TEST_WALLET);
-
- const heliusTimes = [];
- const standardTimes = [];
-
- // Test Helius RPC
- for (let i = 0; i < iterations; i++) {
- try {
- const start = Date.now();
- await heliusConnection.getBalance(testWallet);
- heliusTimes.push(Date.now() - start);
- } catch (error) {
- log(`Helius RPC error: ${error.message}`, 'error');
- }
- }
-
- // Test Standard RPC
- for (let i = 0; i < iterations; i++) {
- try {
- const start = Date.now();
- await standardConnection.getBalance(testWallet);
- standardTimes.push(Date.now() - start);
- } catch (error) {
- log(`Standard RPC error: ${error.message}`, 'error');
- }
- }
-
- const heliusStats = calculateStats(heliusTimes);
- const standardStats = calculateStats(standardTimes);
-
- printStats('Helius Direct RPC', heliusStats);
- printStats('Standard Direct RPC', standardStats);
-
- const improvement = ((standardStats.avg - heliusStats.avg) / standardStats.avg * 100).toFixed(1);
- log(`Direct RPC improvement: ${improvement}%`, 'success');
-
- return { heliusStats, standardStats, improvement };
-}
-
-// Benchmark 5: Priority fee estimation performance
-async function benchmarkPriorityFees() {
- log('Benchmarking priority fee estimation...', 'perf');
-
- const heliusTimes = [];
- const standardTimes = [];
-
- // Test Helius provider
- for (let i = 0; i < Math.min(iterations, 5); i++) {
- const start = Date.now();
- await axios.get(`${GATEWAY_URL}/chains/solana/estimate-gas?network=mainnet-beta`);
- heliusTimes.push(Date.now() - start);
- }
-
- // Test standard provider
- for (let i = 0; i < Math.min(iterations, 5); i++) {
- const start = Date.now();
- await axios.get(`${GATEWAY_URL}/chains/solana/estimate-gas?network=devnet`);
- standardTimes.push(Date.now() - start);
- }
-
- const heliusStats = calculateStats(heliusTimes);
- const standardStats = calculateStats(standardTimes);
-
- printStats('Helius Priority Fees', heliusStats);
- printStats('Standard Priority Fees', standardStats);
-
- return { heliusStats, standardStats };
-}
-
-// Main benchmark runner
-async function runBenchmarks() {
- console.log('\n🏁 Helius Performance Benchmark Suite\n');
- console.log(`Running ${iterations} iterations with ${concurrent} concurrent requests...\n`);
-
- // Check if server is running
- try {
- await axios.get(`${GATEWAY_URL}/`);
- } catch (error) {
- log('Gateway server is not running. Start it with: pnpm start --passphrase=test123 --dev', 'error');
- process.exit(1);
- }
-
- // Run all benchmarks
- const results = {};
-
- results.balanceFetching = await benchmarkBalanceFetching();
- console.log('');
-
- results.tokenList = await benchmarkTokenList();
- console.log('');
-
- results.concurrent = await benchmarkConcurrentRequests();
- console.log('');
-
- results.directRPC = await benchmarkDirectRPC();
- if (results.directRPC) console.log('');
-
- results.priorityFees = await benchmarkPriorityFees();
- console.log('');
-
- // Summary report
- console.log('📊 Performance Summary\n');
-
- const improvements = [];
- if (results.balanceFetching?.improvement) {
- improvements.push(`Balance Fetching: ${results.balanceFetching.improvement}%`);
- }
- if (results.directRPC?.improvement) {
- improvements.push(`Direct RPC: ${results.directRPC.improvement}%`);
- }
-
- improvements.forEach(improvement => {
- log(improvement, 'success');
- });
-
- // Error summary
- const totalHeliusErrors = (results.balanceFetching?.errors?.helius || 0) +
- (results.concurrent?.errors?.helius?.length || 0);
- const totalStandardErrors = (results.balanceFetching?.errors?.standard || 0) +
- (results.concurrent?.errors?.standard?.length || 0);
-
- console.log('');
- log(`Total Helius errors: ${totalHeliusErrors}`, totalHeliusErrors > 0 ? 'warn' : 'success');
- log(`Total Standard errors: ${totalStandardErrors}`, totalStandardErrors > 0 ? 'warn' : 'success');
-
- // Recommendations
- console.log('\n💡 Recommendations\n');
- if (results.balanceFetching?.improvement > 0) {
- console.log('✓ Helius shows better performance for balance fetching');
- }
- if (results.directRPC?.improvement > 0) {
- console.log('✓ Helius RPC endpoints are faster than standard');
- }
- if (totalHeliusErrors === 0) {
- console.log('✓ Helius provider shows good reliability');
- }
- if (results.concurrent?.errors?.helius?.length < results.concurrent?.errors?.standard?.length) {
- console.log('✓ Helius handles concurrent requests better');
- }
-
- console.log('');
- return results;
-}
-
-// Run benchmarks
-runBenchmarks().catch(error => {
- log(`Fatal error: ${error.message}`, 'error');
- process.exit(1);
-});
\ No newline at end of file
diff --git a/scripts/test-infura-live.js b/scripts/test-infura-live.js
deleted file mode 100755
index 152d66521b..0000000000
--- a/scripts/test-infura-live.js
+++ /dev/null
@@ -1,242 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * Live Infura Integration Testing Script
- *
- * This script tests the Infura RPC provider integration with a real API key.
- * It verifies HTTP and WebSocket connections and RPC functionality.
- *
- * Prerequisites:
- * - Valid Infura API key configured in conf/rpc/infura.yml
- * - Gateway server running: pnpm start --passphrase=test123 --dev
- *
- * Usage: node scripts/test-infura-live.js
- */
-
-const axios = require('axios');
-const { ethers } = require('ethers');
-
-const GATEWAY_URL = 'http://localhost:15888';
-const TEST_WALLET = '0x742d35Cc6634C0532925a3b8D66C2Fb4b03F31a0'; // Random Ethereum address
-
-// Test configuration
-const tests = {
- passed: 0,
- failed: 0,
- results: []
-};
-
-// Helper functions (using simple console colors)
-function log(message, type = 'info') {
- const timestamp = new Date().toISOString();
- const colors = {
- info: '\x1b[34m[INFO]\x1b[0m', // blue
- success: '\x1b[32m[✓]\x1b[0m', // green
- error: '\x1b[31m[✗]\x1b[0m', // red
- warn: '\x1b[33m[WARN]\x1b[0m', // yellow
- test: '\x1b[36m[TEST]\x1b[0m' // cyan
- };
- console.log(`${timestamp} ${colors[type] || colors.info} ${message}`);
-}
-
-async function testCase(name, fn) {
- log(`Running: ${name}`, 'test');
- try {
- const startTime = Date.now();
- await fn();
- const duration = Date.now() - startTime;
- tests.passed++;
- tests.results.push({ name, status: 'passed', duration });
- log(`✓ ${name} (${duration}ms)`, 'success');
- } catch (error) {
- tests.failed++;
- tests.results.push({ name, status: 'failed', error: error.message });
- log(`✗ ${name}: ${error.message}`, 'error');
- }
-}
-
-/**
- * Test Ethereum chain status endpoint
- */
-async function testEthereumStatus() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/status?network=mainnet`);
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!data.chainId || !data.blockNumber) {
- throw new Error('Missing required fields in status response');
- }
-
- log(`Chain ID: ${data.chainId}, Block Number: ${data.blockNumber}`, 'info');
-}
-
-/**
- * Test Ethereum balance endpoint with Infura
- */
-async function testEthereumBalance() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/balances`, {
- params: {
- network: 'mainnet',
- address: TEST_WALLET
- }
- });
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!data.balances) {
- throw new Error('Missing balances in response');
- }
-
- log(`ETH Balance: ${data.balances.ETH || '0'} ETH`, 'info');
-}
-
-/**
- * Test token list endpoint
- */
-async function testEthereumTokens() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/tokens?network=mainnet`);
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!Array.isArray(data.tokens) || data.tokens.length === 0) {
- throw new Error('Expected non-empty tokens array');
- }
-
- log(`Loaded ${data.tokens.length} tokens`, 'info');
-}
-
-/**
- * Test Polygon network with Infura
- */
-async function testPolygonStatus() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/status?network=polygon`);
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!data.chainId || data.chainId !== 137) {
- throw new Error(`Expected Polygon chain ID 137, got ${data.chainId}`);
- }
-
- log(`Polygon Chain ID: ${data.chainId}, Block Number: ${data.blockNumber}`, 'info');
-}
-
-/**
- * Test Arbitrum network with Infura
- */
-async function testArbitrumStatus() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/status?network=arbitrum`);
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!data.chainId || data.chainId !== 42161) {
- throw new Error(`Expected Arbitrum chain ID 42161, got ${data.chainId}`);
- }
-
- log(`Arbitrum Chain ID: ${data.chainId}, Block Number: ${data.blockNumber}`, 'info');
-}
-
-/**
- * Test Sepolia testnet (should use standard RPC, not Infura)
- */
-async function testSepoliaStatus() {
- const response = await axios.get(`${GATEWAY_URL}/chains/ethereum/status?network=sepolia`);
-
- if (response.status !== 200) {
- throw new Error(`Expected status 200, got ${response.status}`);
- }
-
- const data = response.data;
- if (!data.chainId || data.chainId !== 11155111) {
- throw new Error(`Expected Sepolia chain ID 11155111, got ${data.chainId}`);
- }
-
- log(`Sepolia Chain ID: ${data.chainId}, Block Number: ${data.blockNumber}`, 'info');
-}
-
-/**
- * Main test runner
- */
-async function runTests() {
- log('🚀 Starting Infura Integration Tests', 'info');
- log('Testing Infura RPC provider integration for Ethereum networks', 'info');
-
- try {
- // Test Ethereum mainnet with Infura
- await testCase('Ethereum Mainnet Status (Infura)', testEthereumStatus);
- await testCase('Ethereum Mainnet Balance (Infura)', testEthereumBalance);
- await testCase('Ethereum Mainnet Tokens', testEthereumTokens);
-
- // Test other networks with Infura
- await testCase('Polygon Status (Infura)', testPolygonStatus);
- await testCase('Arbitrum Status (Infura)', testArbitrumStatus);
-
- // Test testnet with standard RPC
- await testCase('Sepolia Status (Standard RPC)', testSepoliaStatus);
-
- } catch (error) {
- log(`Fatal error: ${error.message}`, 'error');
- process.exit(1);
- }
-
- // Print summary
- log('', 'info');
- log('=== Test Summary ===', 'info');
- log(`Total tests: ${tests.passed + tests.failed}`, 'info');
- log(`Passed: ${tests.passed}`, tests.passed > 0 ? 'success' : 'info');
- log(`Failed: ${tests.failed}`, tests.failed > 0 ? 'error' : 'info');
-
- if (tests.failed > 0) {
- log('', 'info');
- log('Failed tests:', 'error');
- tests.results
- .filter(r => r.status === 'failed')
- .forEach(r => log(` - ${r.name}: ${r.error}`, 'error'));
- }
-
- // Performance summary
- const avgDuration = tests.results
- .filter(r => r.status === 'passed')
- .reduce((sum, r) => sum + r.duration, 0) / tests.passed;
-
- if (tests.passed > 0) {
- log(`Average response time: ${avgDuration.toFixed(2)}ms`, 'info');
- }
-
- log('', 'info');
- if (tests.failed === 0) {
- log('🎉 All tests passed! Infura integration is working correctly.', 'success');
- process.exit(0);
- } else {
- log('❌ Some tests failed. Check Infura configuration and API key.', 'error');
- process.exit(1);
- }
-}
-
-// Handle uncaught errors
-process.on('uncaughtException', (error) => {
- log(`Uncaught exception: ${error.message}`, 'error');
- process.exit(1);
-});
-
-process.on('unhandledRejection', (reason, promise) => {
- log(`Unhandled rejection at ${promise}: ${reason}`, 'error');
- process.exit(1);
-});
-
-// Run the tests
-runTests();
\ No newline at end of file
diff --git a/scripts/test-provider-switching.js b/scripts/test-provider-switching.js
deleted file mode 100644
index 54e22770d7..0000000000
--- a/scripts/test-provider-switching.js
+++ /dev/null
@@ -1,353 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * RPC Provider Switching Test Script
- *
- * This script tests the dynamic switching between URL and Helius providers.
- * It modifies network configurations and verifies the Gateway adapts correctly.
- *
- * Prerequisites:
- * - Gateway server running: pnpm start --passphrase=test123 --dev
- * - Valid Helius API key in conf/rpc/helius.yml
- *
- * Usage: node scripts/test-provider-switching.js
- */
-
-const axios = require('axios');
-const fs = require('fs');
-const yaml = require('js-yaml');
-
-const GATEWAY_URL = 'http://localhost:15888';
-const TEST_WALLET = 'AabEVCB1sWgCPxbn6hFYM4Ukj7UubpBRbbYqRnqRXnZD';
-const DEVNET_CONFIG = './conf/chains/solana/devnet.yml';
-const MAINNET_CONFIG = './conf/chains/solana/mainnet-beta.yml';
-
-// Test tracking
-const tests = { passed: 0, failed: 0, results: [] };
-
-function log(message, type = 'info') {
- const timestamp = new Date().toISOString();
- const prefix = {
- info: '[INFO]',
- success: '[✓]',
- error: '[✗]',
- warn: '[WARN]',
- test: '[TEST]'
- };
- console.log(`${timestamp} ${prefix[type] || prefix.info} ${message}`);
-}
-
-async function testCase(name, fn) {
- log(`Running: ${name}`, 'test');
- try {
- const startTime = Date.now();
- await fn();
- const duration = Date.now() - startTime;
- tests.passed++;
- tests.results.push({ name, status: 'passed', duration });
- log(`${name} - PASSED (${duration}ms)`, 'success');
- return true;
- } catch (error) {
- tests.failed++;
- tests.results.push({ name, status: 'failed', error: error.message });
- log(`${name} - FAILED: ${error.message}`, 'error');
- return false;
- }
-}
-
-// Helper functions
-function readConfig(configPath) {
- if (!fs.existsSync(configPath)) {
- throw new Error(`Config file not found: ${configPath}`);
- }
- return yaml.load(fs.readFileSync(configPath, 'utf8'));
-}
-
-function writeConfig(configPath, config) {
- fs.writeFileSync(configPath, yaml.dump(config, { quotingType: '"' }));
-}
-
-function backupConfig(configPath) {
- const backupPath = `${configPath}.backup`;
- fs.copyFileSync(configPath, backupPath);
- return backupPath;
-}
-
-function restoreConfig(configPath, backupPath) {
- fs.copyFileSync(backupPath, configPath);
- fs.unlinkSync(backupPath);
-}
-
-async function waitForServerRestart(timeout = 10000) {
- log('Waiting for server to restart with new config...', 'info');
- await new Promise(resolve => setTimeout(resolve, 3000)); // Give server time to reload config
-
- const start = Date.now();
- while (Date.now() - start < timeout) {
- try {
- await axios.get(`${GATEWAY_URL}/`, { timeout: 1000 });
- log('Server is ready', 'success');
- return;
- } catch (error) {
- await new Promise(resolve => setTimeout(resolve, 500));
- }
- }
- throw new Error('Server did not restart within timeout');
-}
-
-// Test 1: Verify Current Provider Configuration
-async function testCurrentProviderConfig() {
- const devnetConfig = readConfig(DEVNET_CONFIG);
- const mainnetConfig = readConfig(MAINNET_CONFIG);
-
- log(`Devnet provider: ${devnetConfig.rpcProvider || 'url (default)'}`, 'info');
- log(`Mainnet provider: ${mainnetConfig.rpcProvider || 'url (default)'}`, 'info');
-
- // Test devnet status
- const devnetStatus = await axios.post(`${GATEWAY_URL}/chains/solana/status`, {
- network: 'devnet'
- });
-
- // Test mainnet status
- const mainnetStatus = await axios.post(`${GATEWAY_URL}/chains/solana/status`, {
- network: 'mainnet-beta'
- });
-
- log(`Devnet RPC URL: ${devnetStatus.data.rpcUrl}`, 'info');
- log(`Mainnet RPC URL: ${mainnetStatus.data.rpcUrl}`, 'info');
-
- return { devnetConfig, mainnetConfig, devnetStatus: devnetStatus.data, mainnetStatus: mainnetStatus.data };
-}
-
-// Test 2: Switch Devnet from URL to Helius
-async function testSwitchDevnetToHelius() {
- const backupPath = backupConfig(DEVNET_CONFIG);
-
- try {
- // Modify devnet config to use Helius
- const config = readConfig(DEVNET_CONFIG);
- config.rpcProvider = 'helius';
- writeConfig(DEVNET_CONFIG, config);
-
- log('Switched devnet to Helius provider', 'info');
- log('Note: You need to restart the server to apply changes', 'warn');
-
- // For this test, we'll just verify the config change
- const updatedConfig = readConfig(DEVNET_CONFIG);
- if (updatedConfig.rpcProvider !== 'helius') {
- throw new Error('Config update failed');
- }
-
- log('Config successfully updated', 'success');
-
- } finally {
- // Restore original config
- restoreConfig(DEVNET_CONFIG, backupPath);
- }
-}
-
-// Test 3: Switch Mainnet from Helius to URL
-async function testSwitchMainnetToURL() {
- const backupPath = backupConfig(MAINNET_CONFIG);
-
- try {
- // Modify mainnet config to use URL
- const config = readConfig(MAINNET_CONFIG);
- config.rpcProvider = 'url';
- writeConfig(MAINNET_CONFIG, config);
-
- log('Switched mainnet to URL provider', 'info');
- log('Note: You need to restart the server to apply changes', 'warn');
-
- // Verify config change
- const updatedConfig = readConfig(MAINNET_CONFIG);
- if (updatedConfig.rpcProvider !== 'url') {
- throw new Error('Config update failed');
- }
-
- log('Config successfully updated', 'success');
-
- } finally {
- // Restore original config
- restoreConfig(MAINNET_CONFIG, backupPath);
- }
-}
-
-// Test 4: Test Invalid Provider Configuration
-async function testInvalidProvider() {
- const backupPath = backupConfig(DEVNET_CONFIG);
-
- try {
- // Set invalid provider
- const config = readConfig(DEVNET_CONFIG);
- config.rpcProvider = 'invalid-provider';
- writeConfig(DEVNET_CONFIG, config);
-
- log('Set invalid provider type', 'info');
-
- // Verify config file has invalid value
- const updatedConfig = readConfig(DEVNET_CONFIG);
- if (updatedConfig.rpcProvider !== 'invalid-provider') {
- throw new Error('Config update failed');
- }
-
- log('Invalid provider config created (server should reject this)', 'info');
-
- } finally {
- // Restore original config
- restoreConfig(DEVNET_CONFIG, backupPath);
- }
-}
-
-// Test 5: Test Missing Helius Configuration
-async function testMissingHeliusConfig() {
- const heliusConfigPath = './conf/rpc/helius.yml';
- let backupPath = null;
-
- if (fs.existsSync(heliusConfigPath)) {
- backupPath = `${heliusConfigPath}.backup`;
- fs.copyFileSync(heliusConfigPath, backupPath);
- }
-
- const mainnetBackupPath = backupConfig(MAINNET_CONFIG);
-
- try {
- // Remove helius.yml temporarily
- if (fs.existsSync(heliusConfigPath)) {
- fs.unlinkSync(heliusConfigPath);
- }
-
- // Set mainnet to use helius (should fail)
- const config = readConfig(MAINNET_CONFIG);
- config.rpcProvider = 'helius';
- writeConfig(MAINNET_CONFIG, config);
-
- log('Removed Helius config file and set mainnet to use Helius', 'info');
- log('Server should fallback or show error on restart', 'warn');
-
- } finally {
- // Restore configs
- if (backupPath) {
- fs.copyFileSync(backupPath, heliusConfigPath);
- fs.unlinkSync(backupPath);
- }
- restoreConfig(MAINNET_CONFIG, mainnetBackupPath);
- }
-}
-
-// Test 6: Test Performance Between Providers
-async function testProviderPerformance() {
- const results = {
- url: { times: [], average: 0 },
- helius: { times: [], average: 0 }
- };
-
- // Test URL provider (devnet) multiple times
- for (let i = 0; i < 3; i++) {
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'devnet',
- tokenSymbols: ['SOL']
- });
- results.url.times.push(Date.now() - start);
- }
-
- // Test Helius provider (mainnet) multiple times
- for (let i = 0; i < 3; i++) {
- const start = Date.now();
- await axios.post(`${GATEWAY_URL}/chains/solana/balances`, {
- wallet: TEST_WALLET,
- network: 'mainnet-beta',
- tokenSymbols: ['SOL']
- });
- results.helius.times.push(Date.now() - start);
- }
-
- // Calculate averages
- results.url.average = results.url.times.reduce((a, b) => a + b, 0) / results.url.times.length;
- results.helius.average = results.helius.times.reduce((a, b) => a + b, 0) / results.helius.times.length;
-
- log(`URL Provider (devnet) average: ${results.url.average.toFixed(1)}ms`, 'info');
- log(`Helius Provider (mainnet) average: ${results.helius.average.toFixed(1)}ms`, 'info');
-
- const improvement = ((results.url.average - results.helius.average) / results.url.average * 100).toFixed(1);
- log(`Performance difference: ${improvement}%`, 'info');
-
- return results;
-}
-
-// Test 7: Test Configuration Schema Validation
-async function testConfigurationSchema() {
- // Test valid provider values
- const validProviders = ['url', 'helius'];
- const backupPath = backupConfig(DEVNET_CONFIG);
-
- try {
- for (const provider of validProviders) {
- const config = readConfig(DEVNET_CONFIG);
- config.rpcProvider = provider;
- writeConfig(DEVNET_CONFIG, config);
-
- // Verify it was written correctly
- const updatedConfig = readConfig(DEVNET_CONFIG);
- if (updatedConfig.rpcProvider !== provider) {
- throw new Error(`Failed to set provider to ${provider}`);
- }
-
- log(`Successfully set provider to: ${provider}`, 'info');
- }
- } finally {
- restoreConfig(DEVNET_CONFIG, backupPath);
- }
-}
-
-// Main test runner
-async function runTests() {
- console.log('\n🔄 RPC Provider Switching Tests\n');
- console.log('Testing dynamic provider switching between URL and Helius...\n');
-
- // Check if server is running
- try {
- await axios.get(`${GATEWAY_URL}/`);
- } catch (error) {
- log('Gateway server is not running. Start it with: pnpm start --passphrase=test123 --dev', 'error');
- process.exit(1);
- }
-
- // Run all tests
- await testCase('Current Provider Configuration', testCurrentProviderConfig);
- await testCase('Switch Devnet to Helius', testSwitchDevnetToHelius);
- await testCase('Switch Mainnet to URL', testSwitchMainnetToURL);
- await testCase('Invalid Provider Configuration', testInvalidProvider);
- await testCase('Missing Helius Configuration', testMissingHeliusConfig);
- await testCase('Provider Performance Comparison', testProviderPerformance);
- await testCase('Configuration Schema Validation', testConfigurationSchema);
-
- // Print summary
- console.log('\n📊 Test Summary\n');
- console.log(`✓ Passed: ${tests.passed}`);
- console.log(`✗ Failed: ${tests.failed}`);
- console.log(`Total: ${tests.passed + tests.failed}`);
-
- // Print detailed results
- console.log('\n📋 Detailed Results\n');
- tests.results.forEach(result => {
- const icon = result.status === 'passed' ? '✓' : '✗';
- const duration = result.duration ? ` (${result.duration}ms)` : '';
- const error = result.error ? ` - ${result.error}` : '';
- console.log(`${icon} ${result.name}${duration}${error}`);
- });
-
- console.log('\n⚠️ Note: Some tests modify configs temporarily');
- console.log('Server restart may be required to fully test provider switching\n');
-
- // Exit code based on test results
- process.exit(tests.failed > 0 ? 1 : 0);
-}
-
-// Run tests
-runTests().catch(error => {
- log(`Fatal error: ${error.message}`, 'error');
- process.exit(1);
-});
\ No newline at end of file
diff --git a/src/@types/fastify.d.ts b/src/@types/fastify.d.ts
index bef2d45088..2d4db86b86 100644
--- a/src/@types/fastify.d.ts
+++ b/src/@types/fastify.d.ts
@@ -1,10 +1,10 @@
-import { FastifyPluginCallback } from 'fastify'
+import { FastifyPluginCallback } from 'fastify';
declare module 'fastify' {
export type FastifyPluginAsync = FastifyPluginCallback;
-
+
interface FastifySchema {
swaggerQueryExample?: Record;
'x-examples'?: Record;
}
-}
\ No newline at end of file
+}
diff --git a/src/app.ts b/src/app.ts
index 5ef6fe21dd..25ad9d4598 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,6 +1,5 @@
// External dependencies
-import { spawn } from 'child_process';
-import { exec } from 'child_process';
+import { spawn, exec } from 'child_process';
import { promisify } from 'util';
import fastifyRateLimit from '@fastify/rate-limit';
@@ -13,24 +12,19 @@ import Fastify, { FastifyInstance } from 'fastify';
// Internal dependencies
// Routes
-import { ethereumRoutes } from './chains/ethereum/ethereum.routes';
-import { solanaRoutes } from './chains/solana/solana.routes';
+import { chainRoutes } from './chains/chain.routes';
+import * as ethereumSchemas from './chains/ethereum/schemas';
import { configRoutes } from './config/config.routes';
-import { register0xRoutes } from './connectors/0x/0x.routes';
-import { dflowRoutes } from './connectors/dflow/dflow.routes';
-import { jupiterRoutes } from './connectors/jupiter/jupiter.routes';
-import { meteoraRoutes } from './connectors/meteora/meteora.routes';
-import { okxRoutes } from './connectors/okx/okx.routes';
-import { orcaRoutes } from './connectors/orca/orca.routes';
-import { pancakeswapRoutes } from './connectors/pancakeswap/pancakeswap.routes';
-import { pancakeswapSolRoutes } from './connectors/pancakeswap-sol/pancakeswap-sol.routes';
-import { raydiumRoutes } from './connectors/raydium/raydium.routes';
-import { titanRoutes } from './connectors/titan/titan.routes';
-import { uniswapRoutes } from './connectors/uniswap/uniswap.routes';
import { getHttpsOptions } from './https';
import { rootPath } from './paths';
import { poolRoutes } from './pools/pools.routes';
+import * as ammSchemas from './schemas/amm-schema';
+import * as chainSchemas from './schemas/chain-schema';
+import * as clmmSchemas from './schemas/clmm-schema';
+import * as errorSchemas from './schemas/error-schema';
+import * as routerSchemas from './schemas/router-schema';
import { ConfigManagerV2 } from './services/config-manager-v2';
+import { httpErrors } from './services/error-handler';
import {
constantTimeEqual,
extractBearerToken,
@@ -42,11 +36,19 @@ import {
loadOrCreateApiKey,
} from './services/gateway-security';
import { logger } from './services/logger';
-import { quoteCache } from './services/quote-cache';
+import { OPERATION_IDS } from './services/operation-ids';
+import { ajvOptions, schemaErrorFormatter } from './services/schema-keywords';
import { displayChainConfigurations } from './services/startup-banner';
+import * as tokenSchemas from './tokens/schemas';
import { tokensRoutes } from './tokens/tokens.routes';
-import { tradingRoutes, tradingClmmRoutes, tradingAmmRoutes } from './trading/trading.routes';
+import * as clmmReadRouteSchemas from './trading/clmm';
+import * as poolSwapRoutes from './trading/pool-swap-routes';
+import * as ammRouteSchemas from './trading/trading-amm-routes';
+import * as clmmRouteSchemas from './trading/trading-clmm-routes';
+import * as routerRouteSchemas from './trading/trading-router-routes';
+import { tradingRouterRoutes, tradingClmmRoutes, tradingAmmRoutes } from './trading/trading.routes';
import { GATEWAY_VERSION } from './version';
+import * as walletSchemas from './wallet/schemas';
import { walletRoutes } from './wallet/wallet.routes';
import { asciiLogo } from './index';
@@ -61,6 +63,136 @@ const devMode = process.argv.includes('--dev') || process.env.GATEWAY_TEST_MODE
// Promisify exec for async/await usage
const execPromise = promisify(exec);
+/**
+ * Collect every `$id`-carrying schema reachable from `node`, itself included.
+ *
+ * The search continues *through* a schema it has already collected, because `$id`s
+ * nest: each write response names its confirmed-transaction `data` object, and those
+ * only ever appear inside their parent. Collecting the parent alone would leave the
+ * ref `refIdentifiedSchemas` writes for that child pointing at a component nobody
+ * defined — a spec that resolves nowhere.
+ */
+const collectIdentifiedSchemas = (node: any, found: Map>): void => {
+ if (Array.isArray(node)) {
+ node.forEach((item) => collectIdentifiedSchemas(item, found));
+ return;
+ }
+ if (node === null || typeof node !== 'object') return;
+ if (typeof node.$id === 'string' && !found.has(node.$id)) found.set(node.$id, node);
+ Object.values(node).forEach((value) => collectIdentifiedSchemas(value, found));
+};
+
+/**
+ * Every schema carrying an `$id`, collected from the shared schema modules and from the
+ * route modules that declare their own request bodies.
+ *
+ * Registering these with `addSchema` is what puts them in the spec's
+ * `components.schemas`; `refIdentifiedSchemas` below then points the routes at them.
+ * `$id`s must be unique across all modules — Fastify rejects a duplicate — which is
+ * why the AMM copies of the names CLMM also uses carry an `Amm` prefix.
+ *
+ * The route modules are here because the shapes in `./schemas` are the *base* types the
+ * unified routes compose from, not what a caller sends: they predate the refactor, so
+ * they carry a per-connector `network` and no `connector` or `chainNetwork`. Generating
+ * a client from those alone produced request models that were wrong the same way for
+ * every route, so each route's own body now carries the `$id` instead.
+ */
+const identifiedSchemas = (): Array> => {
+ const found = new Map>();
+ for (const module of [
+ ammSchemas,
+ chainSchemas,
+ clmmSchemas,
+ routerSchemas,
+ ammRouteSchemas,
+ clmmRouteSchemas,
+ clmmReadRouteSchemas,
+ routerRouteSchemas,
+ poolSwapRoutes,
+ ethereumSchemas,
+ walletSchemas,
+ tokenSchemas,
+ errorSchemas,
+ ]) {
+ for (const value of Object.values(module)) {
+ if (typeof value === 'object' && value !== null) collectIdentifiedSchemas(value, found);
+ }
+ }
+ return [...found.values()].map((value) => {
+ // Ref the schema's own $id'd children too, keeping only its root $id. Registering
+ // a parent with its children inlined emits both the child component and an
+ // anonymous copy inside the parent, which is what a generated client names Data1,
+ // Data2, ... — numbered by traversal order, so they churn on any insertion.
+ const { $id, ...rest } = Type.Strict(value as any) as Record;
+ return { $id, ...refIdentifiedSchemas(rest, 'openapi') };
+ });
+};
+
+/**
+ * Replace inline schema objects that carry an `$id` with a `$ref` to the component.
+ *
+ * Fastify inlines whatever a route declares, so without this every operation restates
+ * its schemas in full: the spec had no `components.schemas` at all, identical shapes
+ * (CLMM and AMM execute-swap, say) appeared as separate anonymous objects, and a
+ * generated client got names derived from route paths rather than the domain — which
+ * change whenever a route is renamed.
+ *
+ * This runs only while the spec document is built. Route validation and serialization
+ * keep using the compiled inline schemas, so nothing about request handling changes.
+ *
+ * Two ref forms are needed, because the two places refs appear are processed
+ * differently. Route schemas go through @fastify/swagger's transform, which rewrites
+ * Fastify's own "Id#" form into "#/components/schemas/Id" — passing the components path
+ * there instead makes it read the ref as local to the route schema and fail to resolve
+ * it. Registered components are emitted verbatim, so they must already carry the
+ * components path.
+ */
+type RefStyle = 'fastify' | 'openapi';
+
+const refIdentifiedSchemas = (node: any, style: RefStyle = 'fastify'): any => {
+ if (Array.isArray(node)) return node.map((item) => refIdentifiedSchemas(item, style));
+ if (node === null || typeof node !== 'object') return node;
+ if (typeof node.$id === 'string') {
+ return { $ref: style === 'fastify' ? `${node.$id}#` : `#/components/schemas/${node.$id}` };
+ }
+ return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, refIdentifiedSchemas(value, style)]));
+};
+
+/**
+ * Give an operation the two things a generated client needs and Gateway never stated: a
+ * stable name, and the shape of a failure.
+ *
+ * Both are applied here rather than in 56 route files. The name comes from the table in
+ * `operation-ids.ts` — chosen, not derived, so renaming a path does not rename a caller's
+ * method. The failure shape is the same envelope on every route, so listing it per route
+ * would only be a list to forget to update.
+ *
+ * 400 and 500 are declared everywhere because both are reachable everywhere: Fastify
+ * answers 400 for any request its schema rejects, and `rethrowRouteError` turns anything
+ * without a status of its own into a 500. A route that already declares a status keeps
+ * what it declared.
+ */
+const describeOperation = (schema: any, url: string, route: any): any => {
+ if (!schema || schema.hide) return schema;
+
+ const method = Array.isArray(route?.method) ? route.method[0] : route?.method;
+ // Fastify spells a path parameter `:name`; the table is keyed the way the spec renders
+ // it. Without this the 14 parameterised routes silently keep no name at all.
+ const specPath = url.replace(/:([A-Za-z0-9_]+)/g, '{$1}');
+ const operationId = OPERATION_IDS[`${method} ${specPath}`];
+ const errorRef = { $ref: 'ErrorResponse#' };
+
+ return {
+ ...schema,
+ ...(operationId && !schema.operationId ? { operationId } : {}),
+ response: {
+ 400: errorRef,
+ 500: errorRef,
+ ...(schema.response ?? {}),
+ },
+ };
+};
+
const swaggerOptions = {
openapi: {
info: {
@@ -74,67 +206,14 @@ const swaggerOptions = {
},
],
tags: [
- // Main categories
{ name: '/config', description: 'System configuration endpoints' },
{ name: '/wallet', description: 'Wallet management endpoints' },
{ name: '/tokens', description: 'Token management endpoints' },
{ name: '/pools', description: 'Pool management endpoints' },
- { name: '/trading/swap', description: 'Unified cross-chain swap endpoints' },
- { name: '/trading/clmm', description: 'Unified cross-chain CLMM (Concentrated Liquidity) endpoints' },
- { name: '/trading/amm', description: 'Unified cross-connector AMM endpoints (pool creation)' },
-
- // Chains
- {
- name: '/chain/solana',
- description: 'Solana and SVM-based chain endpoints',
- },
- {
- name: '/chain/ethereum',
- description: 'Ethereum and EVM-based chain endpoints',
- },
-
- // Connectors
- {
- name: '/connector/jupiter',
- description: 'Jupiter connector endpoints',
- },
- {
- name: '/connector/meteora',
- description: 'Meteora connector endpoints',
- },
- {
- name: '/connector/orca',
- description: 'Orca connector endpoints',
- },
- {
- name: '/connector/raydium',
- description: 'Raydium connector endpoints',
- },
- {
- name: '/connector/uniswap',
- description: 'Uniswap connector endpoints',
- },
- { name: '/connector/0x', description: '0x connector endpoints' },
- {
- name: '/connector/pancakeswap-sol',
- description: 'PancakeSwap Solana connector endpoints',
- },
- {
- name: '/connector/pancakeswap',
- description: 'PancakeSwap EVM connector endpoints',
- },
- {
- name: '/connector/dflow',
- description: 'DFlow connector endpoints',
- },
- {
- name: '/connector/okx',
- description: 'OKX DEX aggregator connector endpoints',
- },
- {
- name: '/connector/titan',
- description: 'Titan connector endpoints',
- },
+ { name: '/chains', description: 'Chain endpoints, parameterized by chain' },
+ { name: '/trading/router', description: 'Swaps routed across pools by a router connector' },
+ { name: '/trading/clmm', description: 'Concentrated-liquidity pools: swaps, positions, and pool management' },
+ { name: '/trading/amm', description: 'Constant-product pools: swaps, liquidity, and pool management' },
],
components: {
parameters: {
@@ -148,16 +227,22 @@ const swaggerOptions = {
},
},
},
- transform: ({ schema, url }) => {
+ transform: ({ schema, url, route }: any) => {
try {
- return {
- schema: schema ? Type.Strict(schema) : schema,
- url: url,
- };
+ const transformed = schema ? refIdentifiedSchemas(Type.Strict(schema)) : schema;
+ return { schema: describeOperation(transformed, url, route), url };
} catch (error) {
return { schema, url };
}
},
+ // Name components by their $id. Without this @fastify/swagger numbers them def-0,
+ // def-1, ... in registration order, so every component is renamed whenever a schema
+ // is added or removed — which is precisely the churn components exist to avoid.
+ refResolver: {
+ buildLocalReference(json: any, _baseUri: unknown, _fragment: unknown, i: number) {
+ return json.$id || `def-${i}`;
+ },
+ },
hideUntagged: true,
exposeRoute: true,
};
@@ -181,11 +266,13 @@ const configureGatewayServer = () => {
}
: false,
https: devMode ? undefined : getHttpsOptions(),
+ ajv: ajvOptions,
+ schemaErrorFormatter,
});
const docsPort = ConfigManagerV2.getInstance().get('server.docsPort');
- docsServer = docsPort ? Fastify() : null;
+ docsServer = docsPort ? Fastify({ ajv: ajvOptions, schemaErrorFormatter }) : null;
// Register TypeBox provider
server.withTypeProvider();
@@ -237,10 +324,52 @@ const configureGatewayServer = () => {
});
}
+ // `x-connectors` marks a field as belonging to particular venues — `configAddress` is
+ // meteora's, `ammConfigIndex` is raydium's — and it was documentation only: passing the
+ // wrong one created a pool with the connector's defaults instead of erroring, because
+ // Gateway destructures the keys it knows and ignores the rest.
+ //
+ // preValidation, deliberately: it runs on the body as the caller sent it, before AJV
+ // fills defaults. Checking afterwards would reject every 0x quote, since
+ // `approximateIfNoExactOut` defaults to true and is marked for the Solana routers.
+ server.addHook('preValidation', async (request) => {
+ const schema = (request as any).routeOptions?.schema;
+ if (!schema) return;
+
+ for (const [part, sent] of [
+ [schema.body, request.body],
+ [schema.querystring, request.query],
+ ] as [any, any][]) {
+ if (!part?.properties || !sent || typeof sent !== 'object') continue;
+
+ const connector = sent.connector ?? part.properties.connector?.default;
+ if (!connector) continue;
+
+ for (const [field, spec] of Object.entries(part.properties)) {
+ const connectors: string[] | undefined = spec?.['x-connectors'];
+ if (!connectors || sent[field] === undefined) continue;
+ if (!connectors.includes(connector)) {
+ throw httpErrors.badRequest(
+ `${field} is not a ${connector} parameter — it applies to ${connectors.join(', ')}. ` +
+ 'Remove it, or name a connector that takes it.',
+ );
+ }
+ }
+ }
+ });
+
// Serve Swagger/OpenAPI docs only on loopback (or when explicitly enabled). An exposed
// /docs hands an attacker the full route map of fund-handling endpoints. (#652)
const exposeDocs = !isExposedHost(getBindAddress()) || process.env.GATEWAY_ENABLE_DOCS === 'true';
if (exposeDocs) {
+ // Publish the $id'd schemas as spec components before Swagger builds the document.
+ // Routes keep their inline schemas for validation; this only gives the spec somewhere
+ // for refIdentifiedSchemas to point, so a generated client gets stable, domain names.
+ for (const schema of identifiedSchemas()) {
+ server.addSchema(schema);
+ docsServer?.addSchema(schema);
+ }
+
// Register Swagger
server.register(fastifySwagger, swaggerOptions);
@@ -291,71 +420,13 @@ const configureGatewayServer = () => {
// Register pool routes
app.register(poolRoutes, { prefix: '/pools' });
- // Register trading routes (unified cross-chain swap)
- app.register(tradingRoutes, { prefix: '/trading/swap' });
-
- // Register trading CLMM routes (unified cross-chain concentrated liquidity)
+ // Unified trading routes: the type lives in the path, the connector is a parameter.
+ app.register(tradingRouterRoutes, { prefix: '/trading/router' });
app.register(tradingClmmRoutes, { prefix: '/trading/clmm' });
-
- // Register trading AMM routes (unified cross-connector AMM: pool creation)
app.register(tradingAmmRoutes, { prefix: '/trading/amm' });
- // Register chain routes
- app.register(solanaRoutes, { prefix: '/chains/solana' });
- app.register(ethereumRoutes, { prefix: '/chains/ethereum' });
-
- // Register DEX connector routes - organized by connector
-
- // Jupiter routes
- app.register(jupiterRoutes.router, {
- prefix: '/connectors/jupiter/router',
- });
-
- // DFlow routes
- app.register(dflowRoutes.router, {
- prefix: '/connectors/dflow/router',
- });
-
- // OKX DEX aggregator routes
- app.register(okxRoutes.router, {
- prefix: '/connectors/okx/router',
- });
-
- // Titan routes
- app.register(titanRoutes.router, {
- prefix: '/connectors/titan/router',
- });
-
- // Meteora routes
- app.register(meteoraRoutes.clmm, { prefix: '/connectors/meteora/clmm' });
- app.register(meteoraRoutes.amm, { prefix: '/connectors/meteora/amm' });
-
- // // Orca routes
- app.register(orcaRoutes.clmm, { prefix: '/connectors/orca/clmm' });
-
- // Raydium routes
- app.register(raydiumRoutes.amm, { prefix: '/connectors/raydium/amm' });
- app.register(raydiumRoutes.clmm, { prefix: '/connectors/raydium/clmm' });
-
- // Uniswap routes
- app.register(uniswapRoutes.router, {
- prefix: '/connectors/uniswap/router',
- });
- app.register(uniswapRoutes.amm, { prefix: '/connectors/uniswap/amm' });
- app.register(uniswapRoutes.clmm, { prefix: '/connectors/uniswap/clmm' });
-
- // 0x routes
- app.register(register0xRoutes);
-
- // Pancakeswap routes
- app.register(pancakeswapRoutes.router, {
- prefix: '/connectors/pancakeswap/router',
- });
- app.register(pancakeswapRoutes.amm, { prefix: '/connectors/pancakeswap/amm' });
- app.register(pancakeswapRoutes.clmm, { prefix: '/connectors/pancakeswap/clmm' });
-
- // PancakeSwap Solana routes
- app.register(pancakeswapSolRoutes, { prefix: '/connectors/pancakeswap-sol' });
+ // Chain routes, parameterized by chain (/chains/:chain/...).
+ app.register(chainRoutes, { prefix: '/chains' });
};
// Register routes on main server
diff --git a/src/chains/chain.routes.ts b/src/chains/chain.routes.ts
new file mode 100644
index 0000000000..1081aeba7d
--- /dev/null
+++ b/src/chains/chain.routes.ts
@@ -0,0 +1,274 @@
+/**
+ * Chain routes, parameterized by chain.
+ *
+ * These used to be registered once per chain (/chains/solana/poll,
+ * /chains/ethereum/poll, ...), which made the route table grow with every chain
+ * and forced any client that wanted to be chain-agnostic — or any generated
+ * client — to hardcode the chain list. The handlers were already chain-agnostic:
+ * both chains' operations return the same shared response schemas, so the only
+ * thing per-chain about them is which function to call.
+ *
+ * EVM-only operations (allowances, approve) stay on /chains/ethereum: a
+ * parameterized route that 400s for Solana would be worse than a path that
+ * simply does not exist there.
+ */
+import sensible from '@fastify/sensible';
+import { Type } from '@sinclair/typebox';
+import { FastifyInstance, FastifyPluginAsync } from 'fastify';
+
+import {
+ BalanceRequestSchema,
+ BalanceRequestType,
+ BalanceResponseSchema,
+ EstimateGasRequestSchema,
+ EstimateGasRequestType,
+ EstimateGasResponseSchema,
+ PollRequestSchema,
+ PollRequestType,
+ PollResponseSchema,
+ StatusRequestSchema,
+ StatusRequestType,
+ StatusResponseSchema,
+ UnwrapRequestSchema,
+ UnwrapRequestType,
+ WrapRequestSchema,
+ WrapRequestType,
+ WrapResponseSchema,
+} from '../schemas/chain-schema';
+import { httpErrors } from '../services/error-handler';
+
+import {
+ getEthereumChainConfig,
+ getEthereumNetworkConfig,
+ networks as ethereumNetworks,
+} from './ethereum/ethereum.config';
+import { allowancesRoute } from './ethereum/routes/allowances';
+import { approveRoute } from './ethereum/routes/approve';
+import { getEthereumBalances } from './ethereum/routes/balances';
+import { estimateGasEthereum } from './ethereum/routes/estimate-gas';
+import { pollEthereumTransaction } from './ethereum/routes/poll';
+import { getEthereumStatus } from './ethereum/routes/status';
+import { unwrapEthereum } from './ethereum/routes/unwrap';
+import { wrapEthereum } from './ethereum/routes/wrap';
+import { getSolanaBalances } from './solana/routes/balances';
+import { estimateGasSolana } from './solana/routes/estimate-gas';
+import { pollSolanaTransaction } from './solana/routes/poll';
+import { getSolanaStatus } from './solana/routes/status';
+import { unwrapSolana } from './solana/routes/unwrap';
+import { wrapSolana } from './solana/routes/wrap';
+import { getSolanaChainConfig, getSolanaNetworkConfig, networks as solanaNetworks } from './solana/solana.config';
+
+interface ChainOps {
+ networks: readonly string[];
+ defaultNetwork: () => string;
+ status: (fastify: FastifyInstance, network: string) => Promise;
+ estimateGas: (fastify: FastifyInstance, network: string) => Promise;
+ balances: (fastify: FastifyInstance, network: string, address: string, tokens?: string[]) => Promise;
+ poll: (fastify: FastifyInstance, network: string, signature: string) => Promise;
+ wrap: (fastify: FastifyInstance, network: string, address: string, amount: string) => Promise;
+ unwrap: (fastify: FastifyInstance, network: string, address: string, amount?: string) => Promise;
+ /** EVM chains require an explicit unwrap amount; Solana unwraps the full balance. */
+ unwrapRequiresAmount: boolean;
+}
+
+const CHAINS: Record = {
+ solana: {
+ networks: solanaNetworks,
+ defaultNetwork: () => getSolanaChainConfig().defaultNetwork,
+ status: (fastify, network) => getSolanaStatus(fastify, network),
+ estimateGas: (_fastify, network) => estimateGasSolana(network),
+ balances: (fastify, network, address, tokens) => getSolanaBalances(fastify, network, address, tokens),
+ poll: (fastify, network, signature) => pollSolanaTransaction(fastify, network, signature),
+ wrap: (fastify, network, address, amount) => wrapSolana(fastify, network, address, amount),
+ unwrap: (fastify, network, address, amount) => unwrapSolana(fastify, network, address, amount),
+ unwrapRequiresAmount: false,
+ },
+ ethereum: {
+ networks: ethereumNetworks,
+ defaultNetwork: () => getEthereumChainConfig().defaultNetwork,
+ status: (_fastify, network) => getEthereumStatus(network),
+ estimateGas: (fastify, network) => estimateGasEthereum(fastify, network),
+ balances: (fastify, network, address, tokens) => getEthereumBalances(fastify, network, address, tokens),
+ poll: (fastify, network, signature) => pollEthereumTransaction(fastify, network, signature),
+ wrap: (fastify, network, address, amount) => wrapEthereum(fastify, network, address, amount),
+ unwrap: (fastify, network, address, amount) => unwrapEthereum(fastify, network, address, amount!),
+ unwrapRequiresAmount: true,
+ },
+};
+
+export const SUPPORTED_CHAINS = Object.keys(CHAINS);
+
+/**
+ * The `chain` path parameter, enum-constrained so Swagger renders it as a dropdown
+ * rather than a free-text box and an unknown chain is rejected at the schema. Built
+ * from CHAINS, so adding a chain adds it to the docs. The default is documentation
+ * only — a path parameter is always present, so nothing is ever injected for it.
+ */
+const ChainParamsSchema = Type.Object({
+ chain: Type.String({
+ description: 'Chain to operate on',
+ enum: SUPPORTED_CHAINS,
+ default: 'solana',
+ }),
+});
+
+/**
+ * Resolve the chain and network for a request, rejecting an unknown chain and a
+ * network that belongs to a different one. The per-chain routes got the second
+ * check for free from their network enums; parameterizing the path means doing
+ * it here instead of accepting "ethereum-mainnet-beta".
+ */
+function resolveChain(chain: string, network?: string): { ops: ChainOps; network: string } {
+ const ops = CHAINS[chain];
+ if (!ops) {
+ throw httpErrors.badRequest(`Unsupported chain: ${chain}. Supported: ${SUPPORTED_CHAINS.join(', ')}`);
+ }
+
+ const resolved = network || ops.defaultNetwork();
+ if (!ops.networks.includes(resolved)) {
+ throw httpErrors.badRequest(
+ `Network '${resolved}' is not a ${chain} network. Available: ${ops.networks.join(', ')}`,
+ );
+ }
+ // Surfaces a misconfigured-but-listed network as a clear error rather than a
+ // downstream failure inside the chain client.
+ if (chain === 'solana') getSolanaNetworkConfig(resolved);
+ else getEthereumNetworkConfig(resolved);
+
+ return { ops, network: resolved };
+}
+
+interface ChainParams {
+ chain: string;
+}
+
+export const chainRoutes: FastifyPluginAsync = async (fastify) => {
+ await fastify.register(sensible);
+
+ fastify.get<{ Params: ChainParams; Querystring: StatusRequestType }>(
+ '/:chain/status',
+ {
+ schema: {
+ description: 'Get the status of a chain and network',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ querystring: StatusRequestSchema,
+ response: { 200: StatusResponseSchema },
+ },
+ },
+ async (request) => {
+ const { ops, network } = resolveChain(request.params.chain, request.query.network);
+ return ops.status(fastify, network);
+ },
+ );
+
+ fastify.get<{ Params: ChainParams; Querystring: EstimateGasRequestType }>(
+ '/:chain/estimate-gas',
+ {
+ schema: {
+ description: 'Estimate the current transaction fee on a chain',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ querystring: EstimateGasRequestSchema,
+ response: { 200: EstimateGasResponseSchema },
+ },
+ },
+ async (request) => {
+ const { ops, network } = resolveChain(request.params.chain, request.query.network);
+ return ops.estimateGas(fastify, network);
+ },
+ );
+
+ fastify.post<{ Params: ChainParams; Body: BalanceRequestType }>(
+ '/:chain/balances',
+ {
+ schema: {
+ description: 'Get token balances for a wallet',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ body: BalanceRequestSchema,
+ response: { 200: BalanceResponseSchema },
+ },
+ },
+ async (request) => {
+ const { chain } = request.params;
+ const { ops, network } = resolveChain(chain, request.body.network);
+ const address = request.body.address || defaultWalletFor(chain);
+ if (!address) {
+ throw httpErrors.badRequest(`No address given and no default wallet configured for ${chain}`);
+ }
+ return ops.balances(fastify, network, address, request.body.tokens);
+ },
+ );
+
+ fastify.post<{ Params: ChainParams; Body: PollRequestType }>(
+ '/:chain/poll',
+ {
+ schema: {
+ description: 'Poll a transaction by signature/hash',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ body: PollRequestSchema,
+ response: { 200: PollResponseSchema },
+ },
+ },
+ async (request) => {
+ const { ops, network } = resolveChain(request.params.chain, request.body.network);
+ return ops.poll(fastify, network, request.body.signature);
+ },
+ );
+
+ fastify.post<{ Params: ChainParams; Body: WrapRequestType }>(
+ '/:chain/wrap',
+ {
+ schema: {
+ description: 'Wrap native token into its wrapped form (SOL to WSOL, ETH to WETH, ...)',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ body: WrapRequestSchema,
+ response: { 200: WrapResponseSchema },
+ },
+ },
+ async (request) => {
+ const { ops, network } = resolveChain(request.params.chain, request.body.network);
+ return ops.wrap(fastify, network, request.body.address, request.body.amount);
+ },
+ );
+
+ fastify.post<{ Params: ChainParams; Body: UnwrapRequestType }>(
+ '/:chain/unwrap',
+ {
+ schema: {
+ description: 'Unwrap a wrapped native token back into the native token',
+ tags: ['/chains'],
+ params: ChainParamsSchema,
+ body: UnwrapRequestSchema,
+ response: { 200: WrapResponseSchema },
+ },
+ },
+ async (request) => {
+ const { chain } = request.params;
+ const { ops, network } = resolveChain(chain, request.body.network);
+ if (ops.unwrapRequiresAmount && !request.body.amount) {
+ throw httpErrors.badRequest(`amount is required to unwrap on ${chain}`);
+ }
+ return ops.unwrap(fastify, network, request.body.address, request.body.amount);
+ },
+ );
+
+ // EVM-only operations keep their chain-specific paths.
+ fastify.register(
+ async (evm) => {
+ await evm.register(sensible);
+ evm.register(allowancesRoute);
+ evm.register(approveRoute);
+ },
+ { prefix: '/ethereum' },
+ );
+};
+
+function defaultWalletFor(chain: string): string | undefined {
+ return chain === 'solana' ? getSolanaChainConfig().defaultWallet : getEthereumChainConfig().defaultWallet;
+}
+
+export default chainRoutes;
diff --git a/src/chains/ethereum/ethereum.routes.ts b/src/chains/ethereum/ethereum.routes.ts
deleted file mode 100644
index e3902ba968..0000000000
--- a/src/chains/ethereum/ethereum.routes.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import sensible from '@fastify/sensible';
-import { FastifyPluginAsync } from 'fastify';
-
-import { allowancesRoute } from './routes/allowances';
-import { approveRoute } from './routes/approve';
-import { balancesRoute } from './routes/balances';
-import { estimateGasRoute } from './routes/estimate-gas';
-import { pollRoute } from './routes/poll';
-import { statusRoute } from './routes/status';
-import { unwrapRoute } from './routes/unwrap';
-import { wrapRoute } from './routes/wrap';
-
-// Register the type declaration needed for Fastify schema tags
-declare module 'fastify' {
- interface FastifySchema {
- tags?: readonly string[];
- description?: string;
- }
-}
-
-export const ethereumRoutes: FastifyPluginAsync = async (fastify) => {
- // Register @fastify/sensible plugin to enable httpErrors
- await fastify.register(sensible);
-
- // Register all the route handlers
- fastify.register(statusRoute);
- fastify.register(estimateGasRoute);
- fastify.register(balancesRoute);
- fastify.register(pollRoute);
- fastify.register(allowancesRoute);
- fastify.register(approveRoute);
- fastify.register(wrapRoute);
- fastify.register(unwrapRoute);
-};
-
-export default ethereumRoutes;
diff --git a/src/chains/ethereum/ethereum.ts b/src/chains/ethereum/ethereum.ts
index ec3e34a931..cb4eb4bdcc 100644
--- a/src/chains/ethereum/ethereum.ts
+++ b/src/chains/ethereum/ethereum.ts
@@ -10,6 +10,7 @@ import { RPCProvider } from '../../rpc/rpc-provider-base';
import { TokenValue, tokenValueToString } from '../../services/base';
import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase';
import { ConfigManagerV2 } from '../../services/config-manager-v2';
+import { transactionFailed } from '../../services/error-handler';
import { logger, redactUrl } from '../../services/logger';
import { TokenService } from '../../services/token-service';
import { walletPath, isHardwareWallet as checkIsHardwareWallet } from '../../wallet/utils';
@@ -29,6 +30,15 @@ export interface TokenInfo {
export type NewBlockHandler = (bn: number) => void;
export type NewDebugMsgHandler = (msg: any) => void;
+/**
+ * Outcome of an EVM liquidity/pool transaction as a route is allowed to report it.
+ * A revert is not one of the cases: it throws, so it can never be mistaken for PENDING.
+ * See {@link Ethereum.handleTransactionConfirmation}.
+ */
+export type EthereumTransactionOutcome =
+ | { confirmed: false; signature: string }
+ | { confirmed: true; signature: string; receipt: providers.TransactionReceipt; fee: number };
+
// Networks that support EIP-1559 (type 2) transactions
export const EIP1559_NETWORKS = [
'mainnet',
@@ -47,6 +57,8 @@ export class Ethereum {
public network: string;
public nativeTokenSymbol: string;
public chainId: number;
+ /** Tokens read from the chain because the configured list did not have them. */
+ private readonly chainReadTokens = new Map();
public rpcUrl: string;
public swapProvider: string;
public gasPrice?: number | null;
@@ -527,9 +539,19 @@ export class Ethereum {
}
/**
- * Get token info by symbol or address from local token list only
+ * Get token info by symbol or address, from the configured list or the chain.
+ *
+ * A symbol can only come from the list — there is nothing to ask the chain about a
+ * name it does not hold — so an unknown one is still undefined. An address is
+ * different: it identifies a contract that can be asked what it is, and until it was,
+ * every route describing a pool by its token addresses failed on any token the list
+ * happened to omit. Uniswap's pool-info answered `Token information not found for
+ * pool` for a real pool on real tokens, which is what Solana's getToken has always
+ * avoided by reading the mint.
+ *
* @param tokenSymbol Token symbol or contract address
- * @returns TokenInfo object or undefined if token not found in local list
+ * @returns TokenInfo, or undefined for a symbol that is not listed and an address
+ * that is not an ERC-20
*/
public async getToken(tokenSymbol: string): Promise {
const tokenList = await this.getTokenList();
@@ -544,17 +566,82 @@ export class Ethereum {
}
// If not found by symbol, check if it's a valid address
+ let normalizedAddress: string;
try {
- const normalizedAddress = utils.getAddress(tokenSymbol);
- // Try to find token by normalized address
- return tokenList.find(
- (token: TokenInfo) =>
- token.address.toLowerCase() === normalizedAddress.toLowerCase() && token.chainId === this.chainId,
- );
+ normalizedAddress = utils.getAddress(tokenSymbol);
} catch {
- // If not a valid address format, return undefined
+ // Not an address, so the list was the only place it could have been.
+ return undefined;
+ }
+
+ const tokenByAddress = tokenList.find(
+ (token: TokenInfo) =>
+ token.address.toLowerCase() === normalizedAddress.toLowerCase() && token.chainId === this.chainId,
+ );
+
+ return tokenByAddress ?? (await this.tokenFromChainCached(normalizedAddress));
+ }
+
+ /**
+ * A chain-read token, remembered for the life of the process.
+ *
+ * getToken runs in loops — over the tokens of a balance request, over every position a
+ * wallet owns — so an address the list omits would otherwise cost three eth_calls on
+ * every pass, forever, for a name, symbol and decimals that cannot change. Only
+ * successes are remembered: an address with no contract today may have one tomorrow.
+ */
+ private async tokenFromChainCached(address: string): Promise {
+ const cached = this.chainReadTokens.get(address);
+ if (cached) {
+ return cached;
+ }
+
+ const token = await this.fetchTokenFromChain(address);
+ if (!token) {
return undefined;
}
+
+ this.chainReadTokens.set(address, token);
+ return token;
+ }
+
+ /**
+ * Read a token's name, symbol and decimals from the chain.
+ *
+ * getToken above only searches the configured list, so an unlisted token is simply
+ * absent there. These three are standard ERC-20 view calls and the ABI for them is
+ * already in getContract, so nothing outside the chain is consulted.
+ *
+ * Returns null when the address is not a contract that answers them — a wallet
+ * address, or a token predating the metadata methods — rather than inventing a name.
+ */
+ public async fetchTokenFromChain(address: string): Promise {
+ let normalizedAddress: string;
+ try {
+ normalizedAddress = getAddress(address);
+ } catch {
+ return null;
+ }
+
+ try {
+ const contract = this.getContract(normalizedAddress);
+ const [name, symbol, decimals] = await Promise.all([contract.name(), contract.symbol(), contract.decimals()]);
+
+ if (!symbol) {
+ return null;
+ }
+
+ return {
+ address: normalizedAddress,
+ chainId: this.chainId,
+ decimals: Number(decimals),
+ name: name || symbol,
+ symbol,
+ };
+ } catch (e: any) {
+ logger.debug(`No ERC-20 metadata at ${normalizedAddress}: ${e.message}`);
+ return null;
+ }
}
/**
@@ -1026,6 +1113,60 @@ export class Ethereum {
return null;
}
+ /**
+ * Single confirmation gate for EVM liquidity and pool transactions (open/close position,
+ * add/remove liquidity, collect fees, create pool, execute swap).
+ *
+ * `handleTransactionExecution` has three outcomes but only two of them are a valid response
+ * body, so every caller used to have to remember two separate checks — and almost none did:
+ *
+ * - no receipt (still pending after the extended poll) — dereferencing it throws a TypeError
+ * that the route catch turns into a generic 500, losing the transaction hash and with it
+ * any chance of reconciling a transaction that lands a minute later.
+ * - `receipt.status === 0` (reverted on-chain) — forwarding it verbatim as the response
+ * `status` reports the revert as {@link TransactionStatus.PENDING}, which is also 0, so a
+ * poller waits on it forever while the route's pre-send amounts are booked as if the
+ * tokens had moved.
+ *
+ * This helper resolves both:
+ *
+ * - still pending -> `{ confirmed: false, signature: tx.hash }`. The caller returns
+ * `{ signature, status: TransactionStatus.PENDING }` with NO `data` — the amounts it
+ * computed before sending have not moved and must not be reported as if they had.
+ * - reverted -> throws the shared 400 TRANSACTION_FAILED, the same terminal, non-retryable
+ * error the Solana routes throw for a landed-but-failed transaction.
+ * - confirmed -> `{ confirmed: true, signature, receipt, fee }`, fee already converted from
+ * gas units to the chain's native currency.
+ */
+ public async handleTransactionConfirmation(tx: TransactionResponse): Promise {
+ const receipt = await this.handleTransactionExecution(tx);
+
+ if (!receipt) {
+ logger.warn(`Transaction ${tx.hash} still pending — reporting PENDING so the caller can reconcile it later`);
+ return { confirmed: false, signature: tx.hash };
+ }
+
+ if (receipt.status === 0) {
+ throw transactionFailed(
+ `Transaction ${receipt.transactionHash} reverted on-chain. Gas was spent; no tokens moved.`,
+ );
+ }
+
+ if (receipt.status !== 1) {
+ // No status on the receipt (pre-Byzantium chain or a provider quirk): neither a
+ // confirmation nor a revert, so report it as pending rather than guessing.
+ logger.warn(`Transaction ${receipt.transactionHash} has no receipt status — reporting PENDING`);
+ return { confirmed: false, signature: receipt.transactionHash };
+ }
+
+ return {
+ confirmed: true,
+ signature: receipt.transactionHash,
+ receipt,
+ fee: parseFloat(utils.formatUnits(receipt.gasUsed.mul(receipt.effectiveGasPrice), 18)),
+ };
+ }
+
/**
* Handle transaction confirmation status and return appropriate response
* Similar to Solana's handleConfirmation helper
@@ -1045,6 +1186,7 @@ export class Ethereum {
expectedAmountOut: number,
side?: 'BUY' | 'SELL',
txHash?: string, // Optional tx hash for pending transactions
+ slippagePct?: number, // Slippage tolerance actually applied to the swap (echoed in data)
): {
signature: string;
status: number;
@@ -1056,6 +1198,7 @@ export class Ethereum {
fee: number;
baseTokenBalanceChange: number;
quoteTokenBalanceChange: number;
+ slippagePct?: number;
};
} {
if (!txReceipt) {
@@ -1118,6 +1261,7 @@ export class Ethereum {
fee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
}
diff --git a/src/chains/ethereum/routes/allowances.ts b/src/chains/ethereum/routes/allowances.ts
index 6bad1e72a1..8c0cefe6ed 100644
--- a/src/chains/ethereum/routes/allowances.ts
+++ b/src/chains/ethereum/routes/allowances.ts
@@ -134,7 +134,7 @@ export async function getEthereumAllowances(
);
// Then check Permit2's allowance to Universal Router
- const [amount, expiration, nonce] = await permit2Contract.allowance(
+ const [amount, expiration] = await permit2Contract.allowance(
address,
tokenInfoMap[symbol].address,
universalRouterAddress,
@@ -217,7 +217,7 @@ export const allowancesRoute: FastifyPluginAsync = async (fastify) => {
{
schema: {
description: 'Get token allowances',
- tags: ['/chain/ethereum'],
+ tags: ['/chains'],
body: AllowancesRequestSchema,
response: {
200: AllowancesResponseSchema,
diff --git a/src/chains/ethereum/routes/approve.ts b/src/chains/ethereum/routes/approve.ts
index 026b6be472..215db40b30 100644
--- a/src/chains/ethereum/routes/approve.ts
+++ b/src/chains/ethereum/routes/approve.ts
@@ -3,6 +3,7 @@ import { FastifyPluginAsync, FastifyInstance } from 'fastify';
import { getSpender as pancakeswapSpender } from '../../../connectors/pancakeswap/pancakeswap.contracts';
import { getSpender as uniswapSpender } from '../../../connectors/uniswap/uniswap.contracts';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { bigNumberWithDecimalToStr } from '../../../services/base';
import { logger } from '../../../services/logger';
import { Ethereum } from '../ethereum';
@@ -178,17 +179,20 @@ export async function approveEthereumToken(
const txResponse = await ethereum.provider.sendTransaction(signedTx);
// Wait for confirmation with timeout
- const receipt = await ethereum.handleTransactionExecution(txResponse);
+ // A revert throws 400 TRANSACTION_FAILED out of the helper; only a still-pending
+ // transaction comes back unconfirmed, and an approval cannot be reported without a
+ // confirmed allowance.
+ const outcome = await ethereum.handleTransactionConfirmation(txResponse);
- if (!receipt || receipt.status === -1) {
+ if (!outcome.confirmed) {
throw new Error('Transaction timed out or failed to get receipt');
}
approval = {
- hash: receipt.transactionHash,
+ hash: outcome.signature,
nonce: nonce,
- gasUsed: receipt.gasUsed,
- effectiveGasPrice: receipt.effectiveGasPrice,
+ gasUsed: outcome.receipt.gasUsed,
+ effectiveGasPrice: outcome.receipt.effectiveGasPrice,
};
} else {
// Regular wallet flow
@@ -207,18 +211,17 @@ export async function approveEthereumToken(
const tx = await ethereum.approveERC20(contract, wallet, spenderAddress, amountBigNumber);
// Wait for the transaction to be mined with timeout (60 seconds for approvals)
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
- if (!receipt || receipt.status === -1) {
+ if (!outcome.confirmed) {
throw new Error('Transaction timed out or failed to get receipt');
}
approval = {
hash: tx.hash,
nonce: tx.nonce,
- gasUsed: receipt.gasUsed,
- effectiveGasPrice: receipt.effectiveGasPrice,
- status: receipt.status,
+ gasUsed: outcome.receipt.gasUsed,
+ effectiveGasPrice: outcome.receipt.effectiveGasPrice,
};
}
} else {
@@ -229,7 +232,6 @@ export async function approveEthereumToken(
nonce: 0,
gasUsed: ethers.BigNumber.from('0'),
effectiveGasPrice: ethers.BigNumber.from('0'),
- status: 1,
};
}
@@ -291,20 +293,18 @@ export async function approveEthereumToken(
const txResponse = await ethereum.provider.sendTransaction(signedTx);
// Wait for confirmation with extended timeout
- const permit2Receipt = await ethereum.handleTransactionExecution(txResponse);
+ const permit2Outcome = await ethereum.handleTransactionConfirmation(txResponse);
- if (!permit2Receipt) {
+ if (!permit2Outcome.confirmed) {
throw new Error('Permit2 transaction timed out or failed to get receipt');
}
- logger.info(`Permit2 approval transaction confirmed: ${permit2Receipt.transactionHash}`);
+ logger.info(`Permit2 approval transaction confirmed: ${permit2Outcome.signature}`);
// Update fee to include both transactions
- if (permit2Receipt.gasUsed && permit2Receipt.effectiveGasPrice) {
- const permit2FeeInWei = permit2Receipt.gasUsed.mul(permit2Receipt.effectiveGasPrice);
- const totalFeeInWei = approval.gasUsed.mul(approval.effectiveGasPrice).add(permit2FeeInWei);
- feeInEth = utils.formatEther(totalFeeInWei);
- }
+ const permit2FeeInWei = permit2Outcome.receipt.gasUsed.mul(permit2Outcome.receipt.effectiveGasPrice);
+ const totalFeeInWei = approval.gasUsed.mul(approval.effectiveGasPrice).add(permit2FeeInWei);
+ feeInEth = utils.formatEther(totalFeeInWei);
} else {
// Regular wallet flow for Permit2 approve
const wallet = await ethereum.getWallet(address);
@@ -326,20 +326,18 @@ export async function approveEthereumToken(
);
// Wait for confirmation with extended timeout
- const permit2Receipt = await ethereum.handleTransactionExecution(permit2Tx);
+ const permit2Outcome = await ethereum.handleTransactionConfirmation(permit2Tx);
- if (!permit2Receipt || permit2Receipt.status === -1) {
+ if (!permit2Outcome.confirmed) {
throw new Error('Permit2 transaction timed out or failed to get receipt');
}
- logger.info(`Permit2 approval transaction confirmed: ${permit2Receipt.transactionHash}`);
+ logger.info(`Permit2 approval transaction confirmed: ${permit2Outcome.signature}`);
// Update fee to include both transactions
- if (permit2Receipt.gasUsed && permit2Receipt.effectiveGasPrice) {
- const permit2FeeInWei = permit2Receipt.gasUsed.mul(permit2Receipt.effectiveGasPrice);
- const totalFeeInWei = approval.gasUsed.mul(approval.effectiveGasPrice).add(permit2FeeInWei);
- feeInEth = utils.formatEther(totalFeeInWei);
- }
+ const permit2FeeInWei = permit2Outcome.receipt.gasUsed.mul(permit2Outcome.receipt.effectiveGasPrice);
+ const totalFeeInWei = approval.gasUsed.mul(approval.effectiveGasPrice).add(permit2FeeInWei);
+ feeInEth = utils.formatEther(totalFeeInWei);
}
logger.info(
@@ -349,7 +347,10 @@ export async function approveEthereumToken(
return {
signature: approval.hash,
- status: approval.status ?? -1,
+ // Every path that reaches here confirmed: the helper throws on a revert and the
+ // branches above bail out while a transaction is still pending. `approval.status ?? -1`
+ // used to report a confirmed Ledger approval (which never carried a status) as FAILED.
+ status: TransactionStatus.CONFIRMED,
data: {
tokenAddress: fullToken.address,
spender: isUniversalRouter ? universalRouterAddress || spenderAddress : spenderAddress,
@@ -387,7 +388,7 @@ export const approveRoute: FastifyPluginAsync = async (fastify) => {
{
schema: {
description: 'Approve token spending',
- tags: ['/chain/ethereum'],
+ tags: ['/chains'],
body: ApproveRequestSchema,
response: {
200: ApproveResponseSchema,
diff --git a/src/chains/ethereum/routes/balances.ts b/src/chains/ethereum/routes/balances.ts
index 45ac9d426c..5330e03f0d 100644
--- a/src/chains/ethereum/routes/balances.ts
+++ b/src/chains/ethereum/routes/balances.ts
@@ -1,9 +1,8 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { BalanceRequestType, BalanceResponseType, BalanceResponseSchema } from '../../../schemas/chain-schema';
+import { BalanceResponseType } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
import { Ethereum } from '../ethereum';
-import { EthereumBalanceRequest } from '../schemas';
export async function getEthereumBalances(
fastify: FastifyInstance,
@@ -23,29 +22,3 @@ export async function getEthereumBalances(
throw fastify.httpErrors.internalServerError(`Failed to get balances: ${error.message}`);
}
}
-
-export const balancesRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: BalanceRequestType;
- Reply: BalanceResponseType;
- }>(
- '/balances',
- {
- schema: {
- description:
- 'Get Ethereum balances. If no tokens specified or empty array provided, returns native token (ETH) and only non-zero balances for tokens from the token list. If specific tokens are requested, returns those exact tokens with their balances, including zeros.',
- tags: ['/chain/ethereum'],
- body: EthereumBalanceRequest,
- response: {
- 200: BalanceResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, address, tokens } = request.body;
- return await getEthereumBalances(fastify, network, address, tokens);
- },
- );
-};
-
-export default balancesRoute;
diff --git a/src/chains/ethereum/routes/estimate-gas.ts b/src/chains/ethereum/routes/estimate-gas.ts
index 40541f560a..dc34456ba2 100644
--- a/src/chains/ethereum/routes/estimate-gas.ts
+++ b/src/chains/ethereum/routes/estimate-gas.ts
@@ -1,9 +1,8 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { EstimateGasRequestType, EstimateGasResponse, EstimateGasResponseSchema } from '../../../schemas/chain-schema';
+import { EstimateGasResponse } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
import { Ethereum, EIP1559_NETWORKS } from '../ethereum';
-import { EthereumEstimateGasRequest } from '../schemas';
export async function estimateGasEthereum(fastify: FastifyInstance, network: string): Promise {
try {
@@ -69,28 +68,3 @@ export async function estimateGasEthereum(fastify: FastifyInstance, network: str
throw fastify.httpErrors.internalServerError(`Failed to estimate gas for network ${network}: ${error.message}`);
}
}
-
-export const estimateGasRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: EstimateGasRequestType;
- Reply: EstimateGasResponse;
- }>(
- '/estimate-gas',
- {
- schema: {
- description: 'Estimate gas prices for Ethereum transactions',
- tags: ['/chain/ethereum'],
- querystring: EthereumEstimateGasRequest,
- response: {
- 200: EstimateGasResponseSchema,
- },
- },
- },
- async (request) => {
- const { network } = request.query;
- return await estimateGasEthereum(fastify, network);
- },
- );
-};
-
-export default estimateGasRoute;
diff --git a/src/chains/ethereum/routes/poll.ts b/src/chains/ethereum/routes/poll.ts
index 3d90df9e06..34c616e768 100644
--- a/src/chains/ethereum/routes/poll.ts
+++ b/src/chains/ethereum/routes/poll.ts
@@ -1,11 +1,10 @@
import { ethers } from 'ethers';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PollRequestType, PollResponseType, PollResponseSchema } from '../../../schemas/chain-schema';
+import { PollResponseType, TransactionStatusCode } from '../../../schemas/chain-schema';
import { getConnector } from '../../../services/connection-manager';
import { logger } from '../../../services/logger';
import { Ethereum } from '../ethereum';
-import { EthereumPollRequest } from '../schemas';
// Helper function for transaction response formatting
@@ -36,57 +35,25 @@ export async function pollEthereumTransaction(
const ethereum = await Ethereum.getInstance(network);
const currentBlock = await ethereum.getCurrentBlockNumber();
- let txData = await ethereum.getTransaction(signature);
+ const txData = await ethereum.getTransaction(signature);
let txBlock, txReceipt, txStatus;
if (!txData) {
- const MAX_RETRIES = 3;
- const RETRY_DELAY_MS = 1000;
- let retryCount = 0;
-
- while (retryCount < MAX_RETRIES) {
- await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
- txData = await ethereum.getTransaction(signature);
- if (txData) break;
- retryCount++;
- }
-
- if (!txData) {
- // tx not found after retries
- logger.info(`Transaction ${signature} not found in mempool or does not exist after ${MAX_RETRIES} retries.`);
- txBlock = -1;
- txReceipt = null;
- txStatus = -1;
- }
- }
-
- if (txData) {
+ // Unknown to the node: never received or dropped. eth_getTransactionByHash
+ // returns mempool transactions, so not-found is distinct from pending.
+ logger.info(`Transaction ${signature} not found in mempool or on-chain.`);
+ txBlock = -1;
+ txReceipt = null;
+ txStatus = TransactionStatusCode.NOT_FOUND;
+ } else {
txReceipt = await ethereum.getTransactionReceipt(signature);
if (txReceipt === null) {
- // tx is in the mempool
+ // In the mempool, awaiting inclusion
txBlock = -1;
- txReceipt = null;
-
- // In stateless approach, we simply check if the transaction is still pending
- // We use a basic status code of 0 for pending transactions in mempool
- txStatus = 0;
-
- // Check if transaction is likely to be processed based on gas price
- if (txData.gasPrice) {
- const currentGasPrice = await ethereum.estimateGasPrice();
- // Convert current gas price from GWEI to wei for comparison
- const currentGasPriceWei = currentGasPrice * 1e9;
- // If the transaction's gas price is significantly lower than current gas price,
- // it might be stuck (status 3), otherwise it's likely to be processed (status 2)
- if (txData.gasPrice.toNumber() < currentGasPriceWei * 0.8) {
- txStatus = 3; // Likely stuck
- } else {
- txStatus = 2; // Likely to be processed
- }
- }
+ txStatus = TransactionStatusCode.PENDING;
} else {
- // tx has been processed
txBlock = txReceipt.blockNumber;
- txStatus = typeof txReceipt.status === 'number' ? 1 : -1;
+ // Receipt status 0 = reverted, 1 = success (undefined only pre-Byzantium)
+ txStatus = txReceipt.status === 0 ? TransactionStatusCode.FAILED : TransactionStatusCode.CONFIRMED;
// decode logs
if (connector) {
@@ -121,28 +88,3 @@ export async function pollEthereumTransaction(
throw fastify.httpErrors.internalServerError(`Failed to poll transaction: ${error.message}`);
}
}
-
-export const pollRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: PollRequestType;
- Reply: PollResponseType;
- }>(
- '/poll',
- {
- schema: {
- description: 'Poll Ethereum transaction status',
- tags: ['/chain/ethereum'],
- body: EthereumPollRequest,
- response: {
- 200: PollResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, signature } = request.body;
- return await pollEthereumTransaction(fastify, network, signature);
- },
- );
-};
-
-export default pollRoute;
diff --git a/src/chains/ethereum/routes/status.ts b/src/chains/ethereum/routes/status.ts
index b2714d6afe..35f56615d5 100644
--- a/src/chains/ethereum/routes/status.ts
+++ b/src/chains/ethereum/routes/status.ts
@@ -1,10 +1,7 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { StatusRequestType, StatusResponseType, StatusResponseSchema } from '../../../schemas/chain-schema';
+import { StatusResponseType } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
import { Ethereum } from '../ethereum';
import { getEthereumChainConfig } from '../ethereum.config';
-import { EthereumStatusRequest } from '../schemas';
export async function getEthereumStatus(network: string): Promise {
try {
@@ -57,45 +54,3 @@ export async function getEthereumStatus(network: string): Promise {
- fastify.get<{
- Querystring: StatusRequestType;
- Reply: StatusResponseType;
- }>(
- '/status',
- {
- schema: {
- description: 'Get Ethereum chain status',
- tags: ['/chain/ethereum'],
- querystring: EthereumStatusRequest,
- response: {
- 200: StatusResponseSchema,
- },
- },
- },
- async (request, reply) => {
- const { network } = request.query;
- try {
- // This will handle node timeout internally
- return await getEthereumStatus(network);
- } catch (error) {
- // This will catch any other unexpected errors
- logger.error(`Error in Ethereum status endpoint: ${error.message}`);
- reply.status(500);
- // Return a minimal valid response
- return {
- chain: 'ethereum',
- network,
- rpcUrl: 'unavailable',
- rpcProvider: 'unavailable',
- currentBlockNumber: 0,
- nativeCurrency: 'ETH',
- swapProvider: '',
- };
- }
- },
- );
-};
-
-export default statusRoute;
diff --git a/src/chains/ethereum/routes/unwrap.ts b/src/chains/ethereum/routes/unwrap.ts
index 54001c7a03..db13323ac2 100644
--- a/src/chains/ethereum/routes/unwrap.ts
+++ b/src/chains/ethereum/routes/unwrap.ts
@@ -1,11 +1,11 @@
import { ethers, utils } from 'ethers';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { bigNumberWithDecimalToStr } from '../../../services/base';
import { logger } from '../../../services/logger';
-import { Ethereum } from '../ethereum';
+import { Ethereum, EthereumTransactionOutcome } from '../ethereum';
import { EthereumLedger } from '../ethereum-ledger';
-import { UnwrapRequestSchema, UnwrapResponseSchema, UnwrapRequestType, UnwrapResponseType } from '../schemas';
// Default gas limit for unwrap operations
const UNWRAP_GAS_LIMIT = 50000;
@@ -72,9 +72,9 @@ export async function unwrapEthereum(fastify: FastifyInstance, network: string,
const amountInWei = utils.parseEther(amount);
try {
- let transaction;
+ let transaction: ethers.providers.TransactionResponse;
let nonce: number;
- let receipt;
+ let outcome: EthereumTransactionOutcome;
if (isHardware) {
// Hardware wallet flow
@@ -117,12 +117,7 @@ export async function unwrapEthereum(fastify: FastifyInstance, network: string,
const txResponse = await ethereum.provider.sendTransaction(signedTx);
// Wait for confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(txResponse);
-
- transaction = {
- hash: receipt.transactionHash,
- nonce: nonce,
- };
+ outcome = await ethereum.handleTransactionConfirmation(txResponse);
} else {
// Regular wallet flow
let wallet: ethers.Wallet;
@@ -157,19 +152,21 @@ export async function unwrapEthereum(fastify: FastifyInstance, network: string,
nonce = transaction.nonce;
// Wait for transaction confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(transaction);
+ outcome = await ethereum.handleTransactionConfirmation(transaction);
}
- // Calculate actual fee from receipt
- let feeInEth = '0';
- if (receipt.gasUsed && receipt.effectiveGasPrice) {
- const feeInWei = receipt.gasUsed.mul(receipt.effectiveGasPrice);
- feeInEth = utils.formatEther(feeInWei);
+ // A revert threw out of the confirmation helper as a 400 TRANSACTION_FAILED — it is never
+ // reported as PENDING (receipt.status 0 and TransactionStatus.PENDING are the same number).
+ if (!outcome.confirmed) {
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
}
+ // Calculate actual fee from the confirmed receipt
+ const feeInEth = utils.formatEther(outcome.receipt.gasUsed.mul(outcome.receipt.effectiveGasPrice));
+
return {
- signature: transaction.hash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
nonce: nonce,
fee: feeInEth,
@@ -206,29 +203,3 @@ export async function unwrapEthereum(fastify: FastifyInstance, network: string,
);
}
}
-
-export const unwrapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: UnwrapRequestType;
- Reply: UnwrapResponseType;
- }>(
- '/unwrap',
- {
- schema: {
- description: 'Unwrap wrapped token to native token (e.g., WETH to ETH, WBNB to BNB)',
- tags: ['/chain/ethereum'],
- body: UnwrapRequestSchema,
- response: {
- 200: UnwrapResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, address, amount } = request.body;
-
- return await unwrapEthereum(fastify, network, address, amount);
- },
- );
-};
-
-export default unwrapRoute;
diff --git a/src/chains/ethereum/routes/wrap.ts b/src/chains/ethereum/routes/wrap.ts
index b726f9cd6f..08a4d4adf6 100644
--- a/src/chains/ethereum/routes/wrap.ts
+++ b/src/chains/ethereum/routes/wrap.ts
@@ -1,11 +1,11 @@
import { ethers, utils } from 'ethers';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { bigNumberWithDecimalToStr } from '../../../services/base';
import { logger } from '../../../services/logger';
-import { Ethereum } from '../ethereum';
+import { Ethereum, EthereumTransactionOutcome } from '../ethereum';
import { EthereumLedger } from '../ethereum-ledger';
-import { WrapRequestSchema, WrapResponseSchema, WrapRequestType, WrapResponseType } from '../schemas';
// Gas limit for wrap operations. Plain WETH9 deposit() costs ~27k, but networks
// fronting WETH with a proxy (e.g. robinhoodchain) need appreciably more.
@@ -73,9 +73,9 @@ export async function wrapEthereum(fastify: FastifyInstance, network: string, ad
const amountInWei = utils.parseEther(amount);
try {
- let transaction;
+ let transaction: ethers.providers.TransactionResponse;
let nonce: number;
- let receipt;
+ let outcome: EthereumTransactionOutcome;
if (isHardware) {
// Hardware wallet flow
@@ -110,12 +110,7 @@ export async function wrapEthereum(fastify: FastifyInstance, network: string, ad
const txResponse = await ethereum.provider.sendTransaction(signedTx);
// Wait for confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(txResponse);
-
- transaction = {
- hash: receipt.transactionHash,
- nonce: nonce,
- };
+ outcome = await ethereum.handleTransactionConfirmation(txResponse);
} else {
// Regular wallet flow
let wallet: ethers.Wallet;
@@ -143,19 +138,21 @@ export async function wrapEthereum(fastify: FastifyInstance, network: string, ad
nonce = transaction.nonce;
// Wait for transaction confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(transaction);
+ outcome = await ethereum.handleTransactionConfirmation(transaction);
}
- // Calculate actual fee from receipt
- let feeInEth = '0';
- if (receipt.gasUsed && receipt.effectiveGasPrice) {
- const feeInWei = receipt.gasUsed.mul(receipt.effectiveGasPrice);
- feeInEth = utils.formatEther(feeInWei);
+ // A revert threw out of the confirmation helper as a 400 TRANSACTION_FAILED — it is never
+ // reported as PENDING (receipt.status 0 and TransactionStatus.PENDING are the same number).
+ if (!outcome.confirmed) {
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
}
+ // Calculate actual fee from the confirmed receipt
+ const feeInEth = utils.formatEther(outcome.receipt.gasUsed.mul(outcome.receipt.effectiveGasPrice));
+
return {
- signature: transaction.hash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
nonce: nonce,
fee: feeInEth,
@@ -190,29 +187,3 @@ export async function wrapEthereum(fastify: FastifyInstance, network: string, ad
);
}
}
-
-export const wrapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: WrapRequestType;
- Reply: WrapResponseType;
- }>(
- '/wrap',
- {
- schema: {
- description: 'Wrap native token to wrapped token (e.g., ETH to WETH, BNB to WBNB)',
- tags: ['/chain/ethereum'],
- body: WrapRequestSchema,
- response: {
- 200: WrapResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, address, amount } = request.body;
-
- return await wrapEthereum(fastify, network, address, amount);
- },
- );
-};
-
-export default wrapRoute;
diff --git a/src/chains/ethereum/schemas.ts b/src/chains/ethereum/schemas.ts
index c7cae2d3ce..613f750f5d 100644
--- a/src/chains/ethereum/schemas.ts
+++ b/src/chains/ethereum/schemas.ts
@@ -62,61 +62,79 @@ export const EthereumPollRequest = Type.Object({
});
// Allowances request schema (multiple tokens)
-export const AllowancesRequestSchema = Type.Object({
- network: EthereumNetworkParameter,
- address: EthereumAddressParameter,
- spender: Type.String({
- description: 'Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) or contract address',
- examples: [EXAMPLE_SPENDER],
- }),
- tokens: Type.Array(Type.String(), {
- description: 'Array of token symbols or addresses',
- examples: [EXAMPLE_ALLOWANCE_TOKENS],
- }),
-});
+export const AllowancesRequestSchema = Type.Object(
+ {
+ network: EthereumNetworkParameter,
+ address: EthereumAddressParameter,
+ spender: Type.String({
+ description: 'Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) or contract address',
+ examples: [EXAMPLE_SPENDER],
+ }),
+ tokens: Type.Array(Type.String(), {
+ description: 'Array of token symbols or addresses',
+ examples: [EXAMPLE_ALLOWANCE_TOKENS],
+ }),
+ },
+ { $id: 'AllowancesRequest', additionalProperties: false },
+);
// Allowances response schema
-export const AllowancesResponseSchema = Type.Object({
- spender: Type.String(),
- approvals: Type.Record(Type.String(), Type.String()),
-});
+export const AllowancesResponseSchema = Type.Object(
+ {
+ spender: Type.String(),
+ approvals: Type.Record(Type.String(), Type.String()),
+ },
+ // The last two chain responses without a name of their own. Every other route on
+ // /chains publishes a component; these were inlined, so a generated client got an
+ // anonymous model for them and nothing to import.
+ { $id: 'AllowancesResponse' },
+);
// Approve request schema
-export const ApproveRequestSchema = Type.Object({
- network: EthereumNetworkParameter,
- address: EthereumAddressParameter,
- spender: Type.String({
- description: 'Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) contract address',
- examples: [EXAMPLE_SPENDER],
- }),
- token: Type.String({
- description: 'Token symbol or address',
- examples: [EXAMPLE_ALLOWANCE_TOKENS[0]],
- }),
- amount: Type.Optional(
- Type.String({
- description: 'The amount to approve. If not provided, defaults to maximum amount (unlimited approval).',
- default: '',
+export const ApproveRequestSchema = Type.Object(
+ {
+ network: EthereumNetworkParameter,
+ address: EthereumAddressParameter,
+ spender: Type.String({
+ description: 'Connector name (e.g., uniswap/clmm, uniswap/amm, 0x/router) contract address',
+ examples: [EXAMPLE_SPENDER],
}),
- ),
-});
+ token: Type.String({
+ description: 'Token symbol or address',
+ examples: [EXAMPLE_ALLOWANCE_TOKENS[0]],
+ }),
+ amount: Type.Optional(
+ Type.String({
+ description: 'The amount to approve. If not provided, defaults to maximum amount (unlimited approval).',
+ default: '',
+ }),
+ ),
+ },
+ { $id: 'ApproveRequest', additionalProperties: false },
+);
// Approve response schema
-export const ApproveResponseSchema = Type.Object({
- signature: Type.String(),
- status: Type.Number({ description: 'TransactionStatus enum value' }),
+export const ApproveResponseSchema = Type.Object(
+ {
+ signature: Type.String(),
+ status: Type.Number({ description: 'TransactionStatus enum value' }),
- // Only included when status = CONFIRMED
- data: Type.Optional(
- Type.Object({
- tokenAddress: Type.String(),
- spender: Type.String(),
- amount: Type.String(),
- nonce: Type.Number(),
- fee: Type.String(),
- }),
- ),
-});
+ // Only included when status = CONFIRMED
+ data: Type.Optional(
+ Type.Object(
+ {
+ tokenAddress: Type.String(),
+ spender: Type.String(),
+ amount: Type.String(),
+ nonce: Type.Number(),
+ fee: Type.String(),
+ },
+ { $id: 'ApproveResponseData' },
+ ),
+ ),
+ },
+ { $id: 'ApproveResponse' },
+);
// Wrap request schema
export const WrapRequestSchema = Type.Object({
diff --git a/src/chains/solana/routes/balances.ts b/src/chains/solana/routes/balances.ts
index bb58caafc0..1c4c36045a 100644
--- a/src/chains/solana/routes/balances.ts
+++ b/src/chains/solana/routes/balances.ts
@@ -1,8 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { BalanceRequestType, BalanceResponseType, BalanceResponseSchema } from '../../../schemas/chain-schema';
+import { BalanceResponseType } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
-import { SolanaBalanceRequest } from '../schemas';
import { Solana } from '../solana';
/**
@@ -30,41 +29,3 @@ export async function getSolanaBalances(
throw fastify.httpErrors.internalServerError(`Failed to get balances: ${error.message}`);
}
}
-
-export const balancesRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: BalanceRequestType;
- Reply: BalanceResponseType;
- }>(
- '/balances',
- {
- schema: {
- description:
- "Get token balances for a Solana address. Only returns tokens in the network's token list. If no tokens specified or empty array provided, returns non-zero balances for tokens from the token list that are found in the wallet (includes SOL even if zero). If specific tokens are requested, returns those exact tokens with their balances, including zeros.",
- tags: ['/chain/solana'],
- body: SolanaBalanceRequest,
- response: {
- 200: {
- ...BalanceResponseSchema,
- description: 'Token balances for the specified address (only tokens in token list)',
- examples: [
- {
- balances: {
- SOL: 1.5,
- USDC: 100.0,
- BONK: 50000.0,
- },
- },
- ],
- },
- },
- },
- },
- async (request) => {
- const { network, address, tokens } = request.body;
- return await getSolanaBalances(fastify, network, address, tokens);
- },
- );
-};
-
-export default balancesRoute;
diff --git a/src/chains/solana/routes/estimate-gas.ts b/src/chains/solana/routes/estimate-gas.ts
index fc678ebfd6..c23d798c59 100644
--- a/src/chains/solana/routes/estimate-gas.ts
+++ b/src/chains/solana/routes/estimate-gas.ts
@@ -1,9 +1,6 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { EstimateGasResponse, EstimateGasResponseSchema } from '../../../schemas/chain-schema';
+import { EstimateGasResponse } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
-import { SolanaEstimateGasRequest, SolanaEstimateGasRequestType } from '../schemas';
import { Solana } from '../solana';
export async function estimateGasSolana(network: string): Promise {
@@ -72,29 +69,3 @@ export async function estimateGasSolana(network: string): Promise {
- fastify.get<{
- Querystring: SolanaEstimateGasRequestType;
- Reply: EstimateGasResponse;
- }>(
- '/estimate-gas',
- {
- schema: {
- description:
- 'Estimate priority fees for Solana transactions. Optionally pass addresses (program IDs, pools) for Helius-specific fee estimation.',
- tags: ['/chain/solana'],
- querystring: SolanaEstimateGasRequest,
- response: {
- 200: EstimateGasResponseSchema,
- },
- },
- },
- async (request) => {
- const { network } = request.query;
- return await estimateGasSolana(network);
- },
- );
-};
-
-export default estimateGasRoute;
diff --git a/src/chains/solana/routes/poll.ts b/src/chains/solana/routes/poll.ts
index b9f0266d70..d41e8b0229 100644
--- a/src/chains/solana/routes/poll.ts
+++ b/src/chains/solana/routes/poll.ts
@@ -1,8 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PollRequestType, PollResponseType, PollResponseSchema } from '../../../schemas/chain-schema';
+import { PollResponseType, TransactionStatusCode } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
-import { SolanaPollRequest } from '../schemas';
import { Solana } from '../solana';
import { parseSolanaError } from '../solana-error-parser';
@@ -16,13 +15,15 @@ export async function pollSolanaTransaction(
try {
const currentBlock = await solana.getCurrentBlockNumber();
- // Validate transaction signature format
+ // Validate transaction signature format. A malformed signature can never
+ // resolve, so report NOT_FOUND rather than a pending status a poller would
+ // wait on forever.
if (!signature || typeof signature !== 'string' || !signature.match(/^[A-Za-z0-9]{43,88}$/)) {
return {
currentBlock,
signature,
txBlock: null,
- txStatus: 0,
+ txStatus: TransactionStatusCode.NOT_FOUND,
fee: null,
error: 'INVALID_INPUT: Invalid transaction signature format',
txData: null,
@@ -32,11 +33,16 @@ export async function pollSolanaTransaction(
const txData = await solana.getTransaction(signature);
if (!txData) {
+ // Null txData means either "seen but awaiting confirmation" or "unknown to
+ // the cluster" (dropped, or never received). Only the signature-status
+ // cache separates them: UNCONFIRMED is worth polling again, NOT_FOUND is
+ // terminal once the transaction's blockhash has expired.
+ const txStatus = await solana.getSignatureStatus(signature);
return {
currentBlock,
signature,
txBlock: null,
- txStatus: 0,
+ txStatus,
fee: null,
error: null,
txData: null,
@@ -48,10 +54,13 @@ export async function pollSolanaTransaction(
// Extract fee from transaction
const fee = txData.meta?.fee ? txData.meta.fee / 1e9 : 0; // Convert lamports to SOL
- // Check for transaction error and parse it
+ // Check for transaction error and parse it. The err object carries the code but
+ // names no program, so parse it together with the program logs — attribution
+ // comes from the "Program X failed: custom program error" line, and without it
+ // every program-specific code (e.g. Orca 6018) falls through to UNKNOWN.
let error: string | null = null;
if (txData.meta?.err) {
- const errorStr = JSON.stringify(txData.meta.err);
+ const errorStr = [JSON.stringify(txData.meta.err), ...(txData.meta.logMessages ?? [])].join('\n');
const parsed = parseSolanaError(errorStr);
error = `${parsed.type} (${parsed.errorCodeHex || 'unknown'}): ${parsed.message}`;
logger.info(`Transaction ${signature} failed: ${error}`);
@@ -69,40 +78,17 @@ export async function pollSolanaTransaction(
txData,
};
} catch (err) {
+ // Transient failure (RPC error, etc.) — the transaction's fate is unknown, so
+ // report pending rather than NOT_FOUND: the caller should poll again, not give up.
logger.error(`Error polling transaction ${signature}: ${(err as Error).message}`);
return {
currentBlock: await solana.getCurrentBlockNumber(),
signature,
txBlock: null,
- txStatus: 0,
+ txStatus: TransactionStatusCode.PENDING,
fee: null,
- error: 'Transaction not found or invalid',
+ error: `Error polling transaction: ${(err as Error).message}`,
txData: null,
};
}
}
-
-export const pollRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: PollRequestType;
- Reply: PollResponseType;
- }>(
- '/poll',
- {
- schema: {
- description: 'Poll for the status of a Solana transaction',
- tags: ['/chain/solana'],
- body: SolanaPollRequest,
- response: {
- 200: PollResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, signature } = request.body;
- return await pollSolanaTransaction(fastify, network, signature);
- },
- );
-};
-
-export default pollRoute;
diff --git a/src/chains/solana/routes/status.ts b/src/chains/solana/routes/status.ts
index de0566d5fa..e7e1dfea94 100644
--- a/src/chains/solana/routes/status.ts
+++ b/src/chains/solana/routes/status.ts
@@ -1,8 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { StatusRequestType, StatusResponseType, StatusResponseSchema } from '../../../schemas/chain-schema';
+import { StatusResponseType } from '../../../schemas/chain-schema';
import { logger } from '../../../services/logger';
-import { SolanaStatusRequest } from '../schemas';
import { Solana } from '../solana';
import { getSolanaChainConfig } from '../solana.config';
@@ -43,28 +42,3 @@ export async function getSolanaStatus(fastify: FastifyInstance, network: string)
throw fastify.httpErrors.internalServerError(`Failed to get Solana status: ${error.message}`);
}
}
-
-export const statusRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: StatusRequestType;
- Reply: StatusResponseType;
- }>(
- '/status',
- {
- schema: {
- description: 'Get Solana network status',
- tags: ['/chain/solana'],
- querystring: SolanaStatusRequest,
- response: {
- 200: StatusResponseSchema,
- },
- },
- },
- async (request) => {
- const { network } = request.query;
- return await getSolanaStatus(fastify, network);
- },
- );
-};
-
-export default statusRoute;
diff --git a/src/chains/solana/routes/unwrap.ts b/src/chains/solana/routes/unwrap.ts
index 6c8591c015..1bbd62d445 100644
--- a/src/chains/solana/routes/unwrap.ts
+++ b/src/chains/solana/routes/unwrap.ts
@@ -1,9 +1,9 @@
import { NATIVE_MINT, getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID, AccountLayout } from '@solana/spl-token';
import { PublicKey, TransactionMessage, VersionedTransaction } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { logger } from '../../../services/logger';
-import { UnwrapRequestSchema, UnwrapResponseSchema, UnwrapRequestType, UnwrapResponseType } from '../schemas';
+import { UnwrapResponseType } from '../schemas';
import { Solana } from '../solana';
import { handleSolanaTransactionError } from '../solana-errors';
import { SolanaLedger } from '../solana-ledger';
@@ -134,28 +134,3 @@ export async function unwrapSolana(
handleSolanaTransactionError(fastify, error, 'unwrap WSOL to SOL');
}
}
-
-export const unwrapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: UnwrapRequestType;
- Reply: UnwrapResponseType;
- }>(
- '/unwrap',
- {
- schema: {
- description: 'Unwrap WSOL to SOL. Note: This closes the entire WSOL account, returning all WSOL as SOL.',
- tags: ['/chain/solana'],
- body: UnwrapRequestSchema,
- response: {
- 200: UnwrapResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, address, amount } = request.body;
- return await unwrapSolana(fastify, network, address, amount);
- },
- );
-};
-
-export default unwrapRoute;
diff --git a/src/chains/solana/routes/wrap.ts b/src/chains/solana/routes/wrap.ts
index 5e7d890ded..198e85c48e 100644
--- a/src/chains/solana/routes/wrap.ts
+++ b/src/chains/solana/routes/wrap.ts
@@ -1,8 +1,8 @@
import { PublicKey, TransactionMessage, VersionedTransaction } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { logger } from '../../../services/logger';
-import { WrapRequestSchema, WrapResponseSchema, WrapRequestType, WrapResponseType } from '../schemas';
+import { WrapResponseType } from '../schemas';
import { Solana } from '../solana';
import { handleSolanaTransactionError } from '../solana-errors';
import { SolanaLedger } from '../solana-ledger';
@@ -98,28 +98,3 @@ export async function wrapSolana(
handleSolanaTransactionError(fastify, error, 'wrap SOL to WSOL');
}
}
-
-export const wrapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: WrapRequestType;
- Reply: WrapResponseType;
- }>(
- '/wrap',
- {
- schema: {
- description: 'Wrap SOL to WSOL (Wrapped SOL)',
- tags: ['/chain/solana'],
- body: WrapRequestSchema,
- response: {
- 200: WrapResponseSchema,
- },
- },
- },
- async (request) => {
- const { network, address, amount } = request.body;
- return await wrapSolana(fastify, network, address, amount);
- },
- );
-};
-
-export default wrapRoute;
diff --git a/src/chains/solana/schemas.ts b/src/chains/solana/schemas.ts
index a023ae2469..eb355f2783 100644
--- a/src/chains/solana/schemas.ts
+++ b/src/chains/solana/schemas.ts
@@ -8,8 +8,6 @@ const solanaChainConfig = getSolanaChainConfig();
// Example values
const EXAMPLE_SIGNATURE = '55ukR6VCt1sQFMC8Nyeo51R1SMaTzUC7jikmkEJ2jjkQNdqBxXHraH7vaoaNmf8rX4Y55EXAj8XXoyzvvsrQqWZa';
const EXAMPLE_TOKENS = ['SOL', 'USDC', 'BONK'];
-const USDC_MINT_ADDRESS = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
-const BONK_MINT_ADDRESS = 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263';
// Network parameter with proper defaults and enum
export const SolanaNetworkParameter = Type.Optional(
diff --git a/src/chains/solana/solana-error-parser.ts b/src/chains/solana/solana-error-parser.ts
index f8fec795f3..6d58175a0c 100644
--- a/src/chains/solana/solana-error-parser.ts
+++ b/src/chains/solana/solana-error-parser.ts
@@ -90,8 +90,12 @@ const PROGRAM_ERROR_CODES: Record {
- fastify.register(statusRoute);
- fastify.register(estimateGasRoute);
- fastify.register(balancesRoute);
- fastify.register(pollRoute);
- fastify.register(wrapRoute);
- fastify.register(unwrapRoute);
-};
-
-export default solanaRoutes;
diff --git a/src/chains/solana/solana.ts b/src/chains/solana/solana.ts
index 1e9c83167b..feaa9b740e 100644
--- a/src/chains/solana/solana.ts
+++ b/src/chains/solana/solana.ts
@@ -8,6 +8,7 @@ import {
createSyncNativeInstruction,
createCloseAccountInstruction,
AccountLayout,
+ getTokenMetadata,
} from '@solana/spl-token';
import { TokenInfo } from '@solana/spl-token-registry';
import {
@@ -43,6 +44,7 @@ import { ChainstackService } from '../../rpc/chainstack-service';
import { HeliusService } from '../../rpc/helius-service';
import { createRateLimitAwareSolanaConnection } from '../../rpc/rpc-connection-interceptor';
import { RPCProvider } from '../../rpc/rpc-provider-base';
+import { TransactionStatusCode } from '../../schemas/chain-schema';
import { ConfigManagerCertPassphrase } from '../../services/config-manager-cert-passphrase';
import { ConfigManagerV2 } from '../../services/config-manager-v2';
import { httpErrors, HttpError } from '../../services/error-handler';
@@ -51,13 +53,21 @@ import { encryptSecret, decryptSecret, isLegacyKeystore } from '../../services/s
import { TokenService } from '../../services/token-service';
import { getSafeWalletFilePath, isHardwareWallet as isHardwareWalletUtil } from '../../wallet/utils';
+import { parseSolanaError } from './solana-error-parser';
import { SolanaLedger } from './solana-ledger';
import { PriorityFeeResult, SolanaPriorityFees } from './solana-priority-fees';
import { SolanaNetworkConfig, getSolanaNetworkConfig, getSolanaChainConfig } from './solana.config';
+import { accountLifecycleSol } from './solana.utils';
export type SolanaWalletType = 'local' | 'hardware';
// Constants used for fee calculations
+/** Metaplex Token Metadata program — where every legacy SPL token's name and symbol live. */
+const METAPLEX_METADATA_PROGRAM_ID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s');
+
+/** Metadata account header: key (1) + update authority (32) + mint (32), then the strings. */
+const METAPLEX_NAME_OFFSET = 65;
+
export const BASE_FEE = 5000;
const LAMPORT_TO_SOL = 1 / Math.pow(10, 9);
@@ -67,12 +77,6 @@ interface TokenAccount {
value: any;
}
-enum TransactionResponseStatusCode {
- FAILED = -1,
- UNCONFIRMED = 0,
- CONFIRMED = 1,
-}
-
export class Solana {
public connection: Connection;
public network: string;
@@ -292,6 +296,117 @@ export class Solana {
return token;
}
+ /**
+ * Read a token's name, symbol and decimals from the chain.
+ *
+ * Distinct from getToken, which searches the configured list and, failing that,
+ * invents a `DUMMY_xxxx` symbol so a swap can still be priced. That placeholder is
+ * fine to trade on and unfit to persist, so anything that writes to the token list
+ * comes here instead and gets null when the chain has no name to give.
+ *
+ * A mint account carries only decimals. The name and symbol live in one of two
+ * places, and both are read here because neither covers the other's tokens: the
+ * Token-2022 metadata extension, which most newly minted tokens use, and the
+ * Metaplex metadata account, which is where every legacy SPL token keeps them.
+ */
+ async fetchTokenFromChain(address: string): Promise {
+ let mintPubkey: PublicKey;
+ try {
+ mintPubkey = new PublicKey(address);
+ } catch {
+ return null;
+ }
+
+ const accountInfo = await this.connection.getAccountInfo(mintPubkey);
+ if (!accountInfo) {
+ return null;
+ }
+
+ // A well-formed address that is not a mint — a wallet, a pool, a program — is a
+ // question with an answer ("not a token"), not a failure, so it returns null rather
+ // than letting getMint's rejection escape to the caller.
+ const programId = accountInfo.owner.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID;
+ let mintInfo;
+ try {
+ mintInfo = await getMint(this.connection, mintPubkey, undefined, programId);
+ } catch (e: any) {
+ logger.debug(`${address} on solana is not a mint account: ${e.message}`);
+ return null;
+ }
+
+ const metadata =
+ (await this.readToken2022Metadata(mintPubkey, programId)) ?? (await this.readMetaplexMetadata(mintPubkey));
+ if (!metadata) {
+ logger.info(`No on-chain metadata for mint ${address}; not naming it`);
+ return null;
+ }
+
+ return {
+ address,
+ chainId: 101,
+ decimals: mintInfo.decimals,
+ name: metadata.name,
+ symbol: metadata.symbol,
+ };
+ }
+
+ /** Name and symbol from the Token-2022 metadata extension. Null for a legacy mint. */
+ private async readToken2022Metadata(
+ mint: PublicKey,
+ programId: PublicKey,
+ ): Promise<{ name: string; symbol: string } | null> {
+ if (!programId.equals(TOKEN_2022_PROGRAM_ID)) {
+ return null;
+ }
+ try {
+ const metadata = await getTokenMetadata(this.connection, mint, undefined, programId);
+ if (!metadata?.symbol) {
+ return null;
+ }
+ return { name: metadata.name || metadata.symbol, symbol: metadata.symbol };
+ } catch (e: any) {
+ logger.debug(`Token-2022 metadata unreadable for ${mint.toBase58()}: ${e.message}`);
+ return null;
+ }
+ }
+
+ /**
+ * Name and symbol from the Metaplex metadata account.
+ *
+ * Read directly rather than through the Metaplex SDK, which is not a dependency here:
+ * the account is at a PDA of ['metadata', program, mint], and the three fields wanted
+ * are the first Borsh strings after a fixed 65-byte header of key, update authority
+ * and mint. Each is a 4-byte little-endian length followed by null-padded bytes.
+ */
+ private async readMetaplexMetadata(mint: PublicKey): Promise<{ name: string; symbol: string } | null> {
+ try {
+ const [pda] = PublicKey.findProgramAddressSync(
+ [Buffer.from('metadata'), METAPLEX_METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()],
+ METAPLEX_METADATA_PROGRAM_ID,
+ );
+ const account = await this.connection.getAccountInfo(pda);
+ if (!account) {
+ return null;
+ }
+
+ const readString = (offset: number): { value: string; next: number } => {
+ const length = account.data.readUInt32LE(offset);
+ const raw = account.data.subarray(offset + 4, offset + 4 + length).toString('utf8');
+ return { value: raw.replace(/\0/g, '').trim(), next: offset + 4 + length };
+ };
+
+ const name = readString(METAPLEX_NAME_OFFSET);
+ const symbol = readString(name.next);
+ if (!symbol.value) {
+ return null;
+ }
+ return { name: name.value || symbol.value, symbol: symbol.value };
+ } catch (e: any) {
+ logger.debug(`Metaplex metadata unreadable for ${mint.toBase58()}: ${e.message}`);
+ return null;
+ }
+ }
+
// returns Keypair for a private key, which should be encoded in Base58
getKeypairFromPrivateKey(privateKey: string): Keypair {
const decoded = bs58.decode(privateKey);
@@ -1175,20 +1290,40 @@ export class Solana {
});
}
- // returns a Solana TransactionResponseStatusCode for a txData.
- public async getTransactionStatusCode(txData: TransactionResponse | null): Promise {
+ // returns a Solana TransactionStatusCode for a txData.
+ public async getTransactionStatusCode(txData: TransactionResponse | null): Promise {
let txStatus;
if (!txData) {
// tx not yet confirmed by validator
- txStatus = TransactionResponseStatusCode.UNCONFIRMED;
+ txStatus = TransactionStatusCode.PENDING;
} else {
// If txData exists, check if there's an error in the metadata
- txStatus =
- txData.meta?.err == null ? TransactionResponseStatusCode.CONFIRMED : TransactionResponseStatusCode.FAILED;
+ txStatus = txData.meta?.err == null ? TransactionStatusCode.CONFIRMED : TransactionStatusCode.FAILED;
}
return txStatus;
}
+ // Distinguishes a signature the cluster has seen from one it does not know at all.
+ // getTransaction (commitment 'confirmed') returns null for both a tx awaiting
+ // confirmation and a tx that was dropped, so pollers cannot tell them apart from
+ // txData alone. A signature that stays NOT_FOUND after its blockhash expires
+ // (~90s) can never land.
+ public async getSignatureStatus(signature: string): Promise {
+ const { value } = await this.connection.getSignatureStatuses([signature], {
+ searchTransactionHistory: true,
+ });
+ const status = value[0];
+ if (!status) {
+ return TransactionStatusCode.NOT_FOUND;
+ }
+ if (status.err) {
+ return TransactionStatusCode.FAILED;
+ }
+ // Seen by the cluster: 'processed', or confirmed/finalized racing ahead of
+ // getTransaction visibility — report unconfirmed and let the next poll resolve it.
+ return TransactionStatusCode.PENDING;
+ }
+
// returns the current block number
async getCurrentBlockNumber(): Promise {
return await this.connection.getSlot('processed');
@@ -1325,6 +1460,30 @@ export class Solana {
return totalFee;
}
+ private static throwIfSimulationReturnedError(simulationResult: { err: unknown; logs?: string[] | null }): void {
+ if (!simulationResult.err) return;
+
+ const logs = simulationResult.logs ?? [];
+ const errorMessage = `${SIMULATION_ERROR_MESSAGE}\nError: ${JSON.stringify(simulationResult.err)}\nProgram Logs: ${logs.join('\n')}`;
+ const parsedError = parseSolanaError(errorMessage);
+ const detail = [
+ parsedError.message,
+ parsedError.instructionIndex !== null ? `Failing instruction index: ${parsedError.instructionIndex}.` : '',
+ logs.length > 0 ? `Program logs:\n${logs.slice(-12).join('\n')}` : '',
+ ]
+ .filter(Boolean)
+ .join('\n');
+
+ logger.error(errorMessage);
+ if (parsedError.type === 'SLIPPAGE_EXCEEDED') {
+ throw httpErrors.slippageExceeded(detail);
+ }
+ if (parsedError.type === 'INSUFFICIENT_BALANCE') {
+ throw httpErrors.insufficientBalance(detail);
+ }
+ throw httpErrors.simulationFailed(detail);
+ }
+
public async sendAndConfirmTransaction(
tx: Transaction | VersionedTransaction,
signers: Signer[] = [],
@@ -1334,10 +1493,9 @@ export class Solana {
const currentPriorityFee = priorityFeePerCU ?? (await this.estimateGasPrice());
// Always simulate transaction to get actual compute units
- let computeUnitsToUse: number;
+ let computeUnitsToUse = this.config.defaultComputeUnits;
+ let simulationResult: { err: unknown; logs?: string[] | null; unitsConsumed?: number } | undefined;
try {
- let simulationResult;
-
if (tx instanceof Transaction) {
// For regular transactions, simulate with the Transaction object
const result = await this.connection.simulateTransaction(tx);
@@ -1350,7 +1508,12 @@ export class Solana {
});
simulationResult = result.value;
}
+ } catch (error) {
+ logger.warn(`Failed to simulate for compute units: ${error.message}, using default`);
+ }
+ if (simulationResult) {
+ Solana.throwIfSimulationReturnedError(simulationResult);
if (simulationResult.unitsConsumed) {
// Add 10% margin for safety
computeUnitsToUse = Math.ceil(simulationResult.unitsConsumed * 1.1);
@@ -1358,13 +1521,8 @@ export class Solana {
`Simulation consumed ${simulationResult.unitsConsumed} units, using ${computeUnitsToUse} with 10% margin`,
);
} else {
- // Fallback to default if simulation doesn't return units
- computeUnitsToUse = this.config.defaultComputeUnits;
logger.warn('Simulation did not return units consumed, using default');
}
- } catch (error) {
- logger.warn(`Failed to simulate for compute units: ${error.message}, using default`);
- computeUnitsToUse = this.config.defaultComputeUnits;
}
const basePriorityFeeLamports = currentPriorityFee * computeUnitsToUse;
@@ -1408,28 +1566,54 @@ export class Solana {
}
/**
- * If a broadcast transaction landed on-chain but failed, throw the parsed program error;
- * return silently when the transaction is missing or succeeded so the caller can apply
- * its own confirmation handling. The confirmation helpers report a landed-and-failed
- * transaction as unconfirmed, which callers would otherwise misreport as a timeout.
+ * If a broadcast transaction landed on-chain but failed, throw the parsed program error
+ * (400 TRANSACTION_FAILED — fees were paid, this is terminal, not retryable); return
+ * silently when the transaction is missing or succeeded so the caller can apply its own
+ * confirmation handling. The confirmation helpers report a landed-and-failed transaction
+ * as unconfirmed, which callers would otherwise misreport as a timeout or as PENDING.
+ *
+ * Pass `txData` when it is already at hand to skip the re-fetch; when the caller only
+ * has a null/absent txData the transaction is looked up once more, because the send
+ * helpers can report a landed-and-failed transaction with no data attached.
*/
- private async throwIfLandedWithError(signature: string): Promise {
+ public async throwIfLandedWithError(signature: string, txData?: any): Promise {
if (!signature) return;
- let txData: any = null;
- try {
- txData = await this.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
- } catch {
- return;
+ if (!txData) {
+ try {
+ txData = await this.connection.getTransaction(signature, {
+ commitment: 'confirmed',
+ maxSupportedTransactionVersion: 0,
+ });
+ } catch {
+ return;
+ }
}
if (!txData?.meta?.err) return;
- const { simulationFailed } = await import('../../services/error-handler');
+ throw await this.buildLandedWithErrorException(signature, txData);
+ }
+
+ /** Build the shared landed-but-failed error from a transaction's on-chain data. */
+ private async buildLandedWithErrorException(signature: string, txData: any): Promise {
+ const { transactionFailed } = await import('../../services/error-handler');
const { parseSolanaError } = await import('./solana-error-parser');
const logs: string[] = txData.meta.logMessages ?? [];
const parsed = parseSolanaError([JSON.stringify(txData.meta.err), ...logs].join('\n'));
- throw simulationFailed(`Transaction ${signature} landed on-chain but failed: ${parsed.message}`);
+ return transactionFailed(`Transaction ${signature} landed on-chain but failed: ${parsed.message}`);
+ }
+
+ /**
+ * Route-level re-fetch of a just-sent transaction. Uses the retrying fetch (data can lag
+ * RPC visibility right after confirmation, so a single getTransaction call misreports a
+ * confirmed transaction as PENDING) and throws the shared landed-but-failed error when
+ * the transaction landed with an error. Returns null only when the transaction is
+ * genuinely not visible on-chain yet.
+ */
+ public async getConfirmedTransactionData(signature: string): Promise {
+ const txData = await this._fetchTransactionWithRetry(signature);
+ if (txData?.meta?.err != null) {
+ throw await this.buildLandedWithErrorException(signature, txData);
+ }
+ return txData;
}
public async sendAndConfirmTransactionForWallet(
@@ -1469,18 +1653,22 @@ export class Solana {
// External wallets (hardware/Ledger): add the compute budget and sign any extra
// keypairs, then sign the fee payer externally.
const currentPriorityFee = priorityFeePerCU ?? (await this.estimateGasPrice());
- let computeUnitsToUse: number;
+ let computeUnitsToUse = this.config.defaultComputeUnits;
+ let simulationResult: { err: unknown; logs?: string[] | null; unitsConsumed?: number } | undefined;
try {
const sim =
tx instanceof VersionedTransaction
? await this.connection.simulateTransaction(tx, { replaceRecentBlockhash: true, sigVerify: false })
: await this.connection.simulateTransaction(tx);
- computeUnitsToUse = sim.value.unitsConsumed
- ? Math.ceil(sim.value.unitsConsumed * 1.1)
- : this.config.defaultComputeUnits;
+ simulationResult = sim.value;
} catch (error) {
logger.warn(`Failed to simulate for compute units: ${(error as Error).message}, using default`);
- computeUnitsToUse = this.config.defaultComputeUnits;
+ }
+ if (simulationResult) {
+ Solana.throwIfSimulationReturnedError(simulationResult);
+ computeUnitsToUse = simulationResult.unitsConsumed
+ ? Math.ceil(simulationResult.unitsConsumed * 1.1)
+ : this.config.defaultComputeUnits;
}
let prepared: Transaction | VersionedTransaction;
@@ -1947,6 +2135,8 @@ export class Solana {
): Promise<{
balanceChanges: number[];
fee: number;
+ /** The transaction these were read from, so a caller needing more of it need not refetch. */
+ txDetails: any;
}> {
// Fetch transaction details with retry (data may not be immediately available after confirmation)
const txDetails = await this._fetchTransactionWithRetry(signature, 5, 500, true);
@@ -1978,9 +2168,15 @@ export class Solana {
return 0;
}
- // Calculate SOL change including fees
+ // The raw lamport delta bundles the transaction fee in with the trade whenever
+ // the owner paid it — the fee is debited from the fee payer, which is account 0.
+ // Callers read this as the amount swapped, deposited or collected, so the fee is
+ // added back out: it is reported separately as `fee` and must not be counted
+ // twice. Selling SOL previously overstated amountIn by the fee and understated
+ // realized price; collecting SOL-denominated fees understated the amount.
const lamportChange = postBalances[accountIndex] - preBalances[accountIndex];
- return lamportChange * LAMPORT_TO_SOL;
+ const solChange = lamportChange * LAMPORT_TO_SOL;
+ return accountIndex === 0 ? solChange + fee : solChange;
} else {
// Token mint address provided - get SPL token balance change
const preBalance =
@@ -1995,7 +2191,7 @@ export class Solana {
}
});
- return { balanceChanges, fee };
+ return { balanceChanges, fee, txDetails };
}
/**
@@ -2004,7 +2200,6 @@ export class Solana {
* @param owner Owner address
* @param baseTokenInfo Base token info object with address and symbol
* @param quoteTokenInfo Quote token info object with address and symbol
- * @param txFee Transaction fee in lamports (from txData.meta.fee)
* @returns Object with base and quote token balance changes and calculated rent
*/
async extractClmmBalanceChanges(
@@ -2012,11 +2207,13 @@ export class Solana {
owner: string,
baseTokenInfo: { address: string; symbol: string },
quoteTokenInfo: { address: string; symbol: string },
- txFee: number,
): Promise<{
baseTokenChange: number;
quoteTokenChange: number;
+ /** Rent locked or refunded by the accounts this transaction created or closed. */
rent: number;
+ /** Everything the accounts moved, which is what a native balance change must lose. */
+ accountSol: number;
}> {
const SOL_NATIVE_MINT = 'So11111111111111111111111111111111111111112';
const isBaseSol = baseTokenInfo.symbol === 'SOL' || baseTokenInfo.address === SOL_NATIVE_MINT;
@@ -2046,29 +2243,35 @@ export class Solana {
}
// Extract balance changes
- const { balanceChanges } = await this.extractBalanceChangesAndFee(signature, owner, tokensToExtract);
+ const { balanceChanges, txDetails } = await this.extractBalanceChangesAndFee(signature, owner, tokensToExtract);
// Get individual balance changes
- const solChange = balanceChanges[tokenIndices.sol!];
const baseTokenChange = balanceChanges[tokenIndices.base!];
const quoteTokenChange = balanceChanges[tokenIndices.quote!];
- // Calculate rent from SOL balance
- // When neither token is SOL: rent = |SOL change| - fee
- // When one token is SOL: rent is included in the token's balance change
- let rent = 0;
- if (!isBaseSol && !isQuoteSol) {
- // SOL change = -(fee + rent)
- rent = Math.abs(solChange) - txFee / 1e9;
- } else {
- // For positions, rent is approximately 0.00204928 SOL
- rent = 0.00204928;
- }
+ // Rent is read out of the transaction, not assumed. Every account the transaction
+ // created or closed moved lamports for a reason that is not liquidity, and a CLMM
+ // position is several accounts: the position, its NFT account, the shared protocol
+ // position, and any tick array the range was first to touch. This used to return a
+ // hardcoded 0.00204928 whenever a side was SOL — one token account's worth, for a
+ // position that locks four or five accounts' worth — which understated the rent and
+ // by exactly the same amount overstated the liquidity the native side reported.
+ //
+ // `accountRent` is what a route reports as positionRent / positionRentRefunded;
+ // `accountSol` is the larger figure to take out of a native balance change, and
+ // differs only when a wrapped-SOL account the wallet already had a balance in was
+ // closed. Which direction applies is the transaction's to say: an open creates
+ // accounts, a close closes them, and a swap does neither.
+ const lifecycle = accountLifecycleSol(txDetails);
+ const isOpen = lifecycle.opened >= lifecycle.closed;
+ const rent = isOpen ? lifecycle.rentLocked : lifecycle.rentRefunded;
+ const accountSol = isOpen ? lifecycle.opened : lifecycle.closed;
return {
baseTokenChange,
quoteTokenChange,
rent,
+ accountSol,
};
}
@@ -2208,24 +2411,28 @@ export class Solana {
/**
* Helper function to handle transaction confirmation results
- * Returns appropriate response object based on confirmation status
+ * Returns appropriate response object based on the transaction's on-chain data
* @param signature Transaction signature
- * @param confirmed Whether transaction was confirmed
- * @param txData Transaction data (if available)
+ * @param txData Transaction data from the route-level re-fetch (pass null when the
+ * caller has none — the helper re-fetches with retry so a just-confirmed transaction
+ * whose data lags RPC visibility is not misreported as PENDING)
* @param tokenIn Input token address
* @param tokenOut Output token address
* @param walletAddress Wallet address for balance changes
* @param side Trade side (optional, for AMM/CLMM swaps)
- * @returns Response object with status and data
+ * @param slippagePct Slippage tolerance actually applied to the swap (echoed in data)
+ * @returns Response object with status and data; throws the shared landed-but-failed
+ * error when the transaction landed on-chain with an error — existence of txData is
+ * never treated as confirmation by itself
*/
public async handleConfirmation(
signature: string,
- confirmed: boolean,
txData: any,
tokenIn: string,
tokenOut: string,
walletAddress: string,
side?: 'BUY' | 'SELL',
+ slippagePct?: number,
): Promise<{
signature: string;
status: number;
@@ -2237,9 +2444,20 @@ export class Solana {
fee: number;
baseTokenBalanceChange: number;
quoteTokenBalanceChange: number;
+ slippagePct?: number;
};
}> {
- if (confirmed && txData) {
+ if (!txData) {
+ txData = await this._fetchTransactionWithRetry(signature);
+ }
+
+ // Defense: a landed-but-failed transaction must throw — never report it as
+ // confirmed (its data exists) or as pending.
+ if (txData?.meta?.err != null) {
+ throw await this.buildLandedWithErrorException(signature, txData);
+ }
+
+ if (txData) {
// Transaction confirmed, extract balance changes
const { balanceChanges, fee } = await this.extractBalanceChangesAndFee(signature, walletAddress, [
tokenIn,
@@ -2278,25 +2496,7 @@ export class Solana {
fee,
baseTokenBalanceChange: baseTokenBalanceChange!,
quoteTokenBalanceChange: quoteTokenBalanceChange!,
- },
- };
- } else if (txData && !confirmed) {
- // Transaction exists but not confirmed - extract fee from txData
- const fee = this.getFee(txData);
-
- logger.warn(`Transaction ${signature} not confirmed. May need higher priority fee.`);
-
- return {
- signature,
- status: -1, // NOT_CONFIRMED
- data: {
- tokenIn,
- tokenOut,
- amountIn: 0,
- amountOut: 0,
- fee,
- baseTokenBalanceChange: 0,
- quoteTokenBalanceChange: 0,
+ slippagePct,
},
};
} else {
diff --git a/src/chains/solana/solana.utils.ts b/src/chains/solana/solana.utils.ts
index f114eeb43e..1f326d49c3 100644
--- a/src/chains/solana/solana.utils.ts
+++ b/src/chains/solana/solana.utils.ts
@@ -1,6 +1,9 @@
import * as fs from 'fs';
import * as path from 'path';
+import { NATIVE_MINT } from '@solana/spl-token';
+import { PublicKey } from '@solana/web3.js';
+
import { rootPath } from '../../paths';
import { ConfigManagerV2 } from '../../services/config-manager-v2';
@@ -46,3 +49,176 @@ export function getAvailableSolanaNetworks(): string[] {
return ['mainnet-beta', 'devnet'];
}
}
+
+/**
+ * The SOL a transaction moved because accounts opened or closed, rather than because
+ * liquidity did.
+ *
+ * Opening a position creates several accounts and every one of them is rent-bearing: on
+ * DAMM v2 the position, the position NFT's mint and that mint's token account; on a
+ * PancakeSwap/Raydium CLMM the position, its NFT account, the shared protocol position
+ * and any tick array the range is the first to touch. All of it is funded by the wallet
+ * paying for the transaction, so all of it sits inside that wallet's native balance
+ * change — and none of it is liquidity. Closing gives the same lamports back the same
+ * way. Subtracting only the position account's own rent, which is what these routes used
+ * to do, left every other account's rent inside the reported deposit or withdrawal.
+ *
+ * `opened` and `closed` are the totals to take out of a native-side balance change.
+ * `rentLocked` and `rentRefunded` are the rent halves of those totals, and are what a
+ * route should report as `positionRent` / `positionRentRefunded`.
+ *
+ * The two differ for exactly one kind of account: a wrapped-SOL token account carries a
+ * balance as well as its rent. When a close unwraps one, the lamports that come back are
+ * its rent *plus* whatever WSOL it already held before the transaction — someone else's
+ * money as far as this position is concerned. Taking the whole pre-balance out of the
+ * change is what leaves the true withdrawal behind; calling the whole thing rent would
+ * not be true.
+ *
+ * An account that both opens and closes within the same transaction — a WSOL account
+ * created to receive a withdrawal and unwrapped in the same breath — is neither, and is
+ * correctly ignored: its lamports never left the wallet.
+ *
+ * Reads only the balance arrays and the token balances, both of which `getTransaction`
+ * and `getParsedTransaction` return in the same shape, so it works on either.
+ * Returns SOL, like everything else here that feeds `liquidityWithoutRent`.
+ */
+export interface AccountLifecycleSol {
+ /** Lamports, in SOL, locked into accounts this transaction created. */
+ opened: number;
+ /** Lamports, in SOL, returned by accounts this transaction closed. */
+ closed: number;
+ /** The rent share of `opened` — everything but wrapped SOL already held. */
+ rentLocked: number;
+ /** The rent share of `closed`. */
+ rentRefunded: number;
+}
+
+export function accountLifecycleSol(txData: any): AccountLifecycleSol {
+ const pre: number[] = txData?.meta?.preBalances ?? [];
+ const post: number[] = txData?.meta?.postBalances ?? [];
+
+ const wrapped = (balances: any[]): Record => {
+ const byIndex: Record = {};
+ for (const balance of balances ?? []) {
+ if (balance?.mint !== NATIVE_MINT.toBase58()) continue;
+ // WSOL has 9 decimals, so its raw amount is denominated in lamports already.
+ byIndex[balance.accountIndex] = Number(balance.uiTokenAmount?.amount ?? 0);
+ }
+ return byIndex;
+ };
+ const preWrapped = wrapped(txData?.meta?.preTokenBalances);
+ const postWrapped = wrapped(txData?.meta?.postTokenBalances);
+
+ let opened = 0;
+ let closed = 0;
+ let rentLocked = 0;
+ let rentRefunded = 0;
+
+ for (let i = 0; i < Math.min(pre.length, post.length); i++) {
+ if (pre[i] === 0 && post[i] > 0) {
+ opened += post[i];
+ rentLocked += post[i] - (postWrapped[i] ?? 0);
+ } else if (pre[i] > 0 && post[i] === 0) {
+ closed += pre[i];
+ rentRefunded += pre[i] - (preWrapped[i] ?? 0);
+ }
+ }
+
+ return {
+ opened: opened / 1e9,
+ closed: closed / 1e9,
+ rentLocked: rentLocked / 1e9,
+ rentRefunded: rentRefunded / 1e9,
+ };
+}
+
+/**
+ * Token amounts moved by each top-level instruction of one program, in order.
+ *
+ * The reason this exists rather than the grouping in `orca.utils`: that one drops an
+ * instruction that moved nothing, so a caller cannot tell "the first instruction
+ * collected zero fees" from "the first group IS the principal". Position matters here —
+ * a close sends collect-then-decrease and reads the two by their place — so every
+ * matching instruction gets a row, zero-filled.
+ *
+ * Reads a parsed transaction (`getParsedTransaction`), which is what
+ * `extractBalanceChangesAndFee` already fetches. Amounts are returned per requested
+ * mint, in the order the mints were given, in UI units.
+ *
+ * Returns an empty array when the transaction carries no parsed inner instructions,
+ * which a caller must treat as "unknown", never as "nothing moved".
+ */
+export function transfersByProgramInstruction(parsedTx: any, programId: string, mints: string[]): number[][] {
+ const inner = parsedTx?.meta?.innerInstructions ?? [];
+ const outer = parsedTx?.transaction?.message?.instructions ?? [];
+ if (!inner.length || !outer.length) return [];
+
+ const decimalsByMint: Record = {};
+ const mintByAccount: Record = {};
+ for (const balance of [...(parsedTx.meta?.preTokenBalances ?? []), ...(parsedTx.meta?.postTokenBalances ?? [])]) {
+ const account = parsedTx.transaction.message.accountKeys?.[balance.accountIndex]?.pubkey?.toString();
+ if (account && balance.mint) mintByAccount[account] = balance.mint;
+ if (balance.mint && balance.uiTokenAmount?.decimals !== undefined) {
+ decimalsByMint[balance.mint] = balance.uiTokenAmount.decimals;
+ }
+ }
+
+ const rows: number[][] = [];
+ for (let index = 0; index < outer.length; index++) {
+ if (outer[index]?.programId?.toString() !== programId) continue;
+
+ const amounts = mints.map(() => 0);
+ for (const instruction of inner.find((block: any) => block.index === index)?.instructions ?? []) {
+ const parsed = instruction.parsed;
+ if (!parsed) continue;
+
+ let mint: string | undefined;
+ let raw: string | undefined;
+ let decimals: number | undefined;
+ if (parsed.type === 'transferChecked' && parsed.info) {
+ mint = parsed.info.mint;
+ raw = parsed.info.tokenAmount?.amount;
+ decimals = parsed.info.tokenAmount?.decimals;
+ } else if (parsed.type === 'transfer' && parsed.info) {
+ raw = parsed.info.amount;
+ mint = mintByAccount[parsed.info.source] ?? mintByAccount[parsed.info.destination];
+ }
+ if (!mint || raw === undefined) continue;
+
+ const position = mints.indexOf(mint);
+ if (position === -1) continue;
+ amounts[position] += Number(raw) / 10 ** (decimals ?? decimalsByMint[mint] ?? 0);
+ }
+ rows.push(amounts);
+ }
+ return rows;
+}
+
+/**
+ * The liquidity in a wallet balance change, with the account lamports taken out of it.
+ *
+ * When a pool side IS the native token, the wallet's balance change for that side carries
+ * the position's rent as well as the liquidity: on the way in it was locked alongside the
+ * deposit, on the way out it came back alongside the withdrawal. Rent is not liquidity and
+ * not a cost — the chain returns it when the accounts close — so reporting the raw change
+ * overstates what the position holds. On a small position that is the larger of the two
+ * numbers.
+ *
+ * Both directions use this, with `accountLifecycleSol().opened` at open and `.closed` at
+ * close; the arithmetic is the same because the sign is taken off first. Those totals
+ * rather than the rent halves, because a wrapped-SOL account closing also hands back a
+ * balance the wallet already held, which is no more this position's liquidity than its
+ * rent is. A non-native side never carries either, so it passes through as a magnitude.
+ *
+ * Clamps at zero: a native change smaller than what the accounts moved means they
+ * dominated the transaction, and "nothing was deposited" is the truthful reading of that.
+ * A negative amount would be the arithmetic leaking into a field that means a quantity of
+ * tokens.
+ *
+ * `accountSol` must be in SOL, as `accountLifecycleSol` returns it — the change is
+ * denominated in tokens, so a lamport figure here would clamp every native side to zero
+ * in silence.
+ */
+export function liquidityWithoutRent(change: number, mint: PublicKey, accountSol: number): number {
+ return mint.equals(NATIVE_MINT) ? Math.max(0, Math.abs(change) - accountSol) : Math.abs(change);
+}
diff --git a/src/config/routes/getConnectors.ts b/src/config/routes/getConnectors.ts
index c6eed4dd2c..446a0b5576 100644
--- a/src/config/routes/getConnectors.ts
+++ b/src/config/routes/getConnectors.ts
@@ -1,14 +1,13 @@
import { Type, Static } from '@sinclair/typebox';
import { FastifyPluginAsync } from 'fastify';
-import { PancakeswapConfig } from '#src/connectors/pancakeswap/pancakeswap.config';
-
import { ZeroXConfig } from '../../connectors/0x/0x.config';
import { DFlowConfig } from '../../connectors/dflow/dflow.config';
import { JupiterConfig } from '../../connectors/jupiter/jupiter.config';
import { MeteoraConfig } from '../../connectors/meteora/meteora.config';
import { OkxConfig } from '../../connectors/okx/okx.config';
import { OrcaConfig } from '../../connectors/orca/orca.config';
+import { PancakeswapConfig } from '../../connectors/pancakeswap/pancakeswap.config';
import { PancakeswapSolConfig } from '../../connectors/pancakeswap-sol/pancakeswap-sol.config';
import { RaydiumConfig } from '../../connectors/raydium/raydium.config';
import { TitanConfig } from '../../connectors/titan/titan.config';
diff --git a/src/config/utils.ts b/src/config/utils.ts
index 0a608192eb..8b362ed133 100644
--- a/src/config/utils.ts
+++ b/src/config/utils.ts
@@ -1,8 +1,4 @@
-import * as fs from 'fs';
-import * as path from 'path';
-
import { FastifyInstance } from 'fastify';
-import * as yaml from 'js-yaml';
import { ConfigManagerV2 } from '../services/config-manager-v2';
import { logger } from '../services/logger';
@@ -11,10 +7,13 @@ import { logger } from '../services/logger';
const KNOWN_CHAINS = ['solana', 'ethereum'];
/**
- * Parse a chain-network namespace format into chain and network components.
- * Returns null if not a chain-network format.
+ * Is this config namespace a chain-network one, and if so which?
+ *
+ * Distinct from services/chain-network's parser, which reads a caller's selector and
+ * rejects a malformed one. This classifies a namespace against the known chains and
+ * answers null for anything else — `server`, `uniswap` — which is not an error here.
*/
-function parseChainNetwork(namespace: string): { chain: string; network: string } | null {
+function parseChainNetworkNamespace(namespace: string): { chain: string; network: string } | null {
for (const chain of KNOWN_CHAINS) {
if (namespace.startsWith(`${chain}-`)) {
const network = namespace.slice(chain.length + 1);
@@ -36,7 +35,7 @@ export const getConfig = (fastify: FastifyInstance, namespace?: string): object
}
// Check if this is a chain-network format (e.g., solana-mainnet-beta)
- const parsed = parseChainNetwork(namespace);
+ const parsed = parseChainNetworkNamespace(namespace);
if (parsed) {
// Get the parent chain config and merge it
const chainConfig = ConfigManagerV2.getInstance().getNamespace(parsed.chain);
@@ -65,7 +64,7 @@ export const updateConfig = (fastify: FastifyInstance, configPath: string, confi
const [namespace, ...pathParts] = configPath.split('.');
const field = pathParts[0];
- const parsed = parseChainNetwork(namespace);
+ const parsed = parseChainNetworkNamespace(namespace);
if (parsed && field) {
// Check if this field exists in the chain config (not network config)
const chainConfig = ConfigManagerV2.getInstance().getNamespace(parsed.chain);
diff --git a/src/connectors/0x/0x.routes.ts b/src/connectors/0x/0x.routes.ts
deleted file mode 100644
index 88b754c30e..0000000000
--- a/src/connectors/0x/0x.routes.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { FastifyInstance } from 'fastify';
-
-import zeroXRouterRoutes from './router-routes';
-
-export const register0xRoutes = async (fastify: FastifyInstance): Promise => {
- // Register v2 router routes (4 endpoints)
- await fastify.register(zeroXRouterRoutes, {
- prefix: '/connectors/0x/router',
- });
-};
diff --git a/src/connectors/0x/0x.ts b/src/connectors/0x/0x.ts
index 930cb4794c..90e2aafcff 100644
--- a/src/connectors/0x/0x.ts
+++ b/src/connectors/0x/0x.ts
@@ -215,7 +215,6 @@ export class ZeroX {
public parseTokenAmount(amount: number, decimals: number): string {
// Convert a decimal amount to the token's smallest unit
- const multiplier = BigNumber.from(10).pow(decimals);
const amountStr = amount.toFixed(decimals);
const [whole, decimal = ''] = amountStr.split('.');
const paddedDecimal = decimal.padEnd(decimals, '0');
diff --git a/src/connectors/0x/router-routes/executeQuote.ts b/src/connectors/0x/router-routes/executeQuote.ts
index f49f185496..9825350748 100644
--- a/src/connectors/0x/router-routes/executeQuote.ts
+++ b/src/connectors/0x/router-routes/executeQuote.ts
@@ -1,21 +1,13 @@
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { ZeroX } from '../0x';
-import { ZeroXExecuteQuoteRequest } from '../schemas';
-
-async function executeQuote(
- walletAddress: string,
- network: string,
- quoteId: string,
- gasPrice?: string,
- maxGas?: number,
-): Promise {
+
+async function executeQuote(walletAddress: string, network: string, quoteId: string): Promise {
// Retrieve cached quote from global cache
const quote = quoteCache.get(quoteId);
if (!quote) {
@@ -56,8 +48,7 @@ async function executeQuote(
to: quote.to,
data: quote.data,
value: quote.value,
- gasLimit: maxGas || parseInt(quote.estimatedGas || quote.gas),
- ...(gasPrice && { gasPrice: BigNumber.from(gasPrice) }),
+ gasLimit: parseInt(quote.estimatedGas || quote.gas),
};
const txResponse = await wallet.sendTransaction(txData);
@@ -82,6 +73,9 @@ async function executeQuote(
quote.buyTokenAddress,
expectedAmountIn,
expectedAmountOut,
+ undefined,
+ undefined,
+ quoteCache.getRequest(quoteId)?.slippagePct,
);
// Handle different transaction states
@@ -108,34 +102,3 @@ async function executeQuote(
}
export { executeQuote };
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from 0x',
- tags: ['/connector/0x'],
- body: ZeroXExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, quoteId, gasPrice, maxGas } =
- request.body as typeof ZeroXExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId, gasPrice, maxGas);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing 0x quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/0x/router-routes/executeSwap.ts b/src/connectors/0x/router-routes/executeSwap.ts
index 8e9aa34beb..3e66fb1795 100644
--- a/src/connectors/0x/router-routes/executeSwap.ts
+++ b/src/connectors/0x/router-routes/executeSwap.ts
@@ -1,10 +1,5 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { ZeroXConfig } from '../0x.config';
-import { ZeroXExecuteSwapRequest } from '../schemas';
import { executeQuote } from './executeQuote';
import { quoteSwap } from './quoteSwap';
@@ -17,8 +12,6 @@ async function executeSwap(
amount: number,
side: 'BUY' | 'SELL',
slippagePct: number = ZeroXConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
// Step 1: Get a fresh firm quote using the quoteSwap function
const quoteResult = await quoteSwap(
@@ -33,50 +26,9 @@ async function executeSwap(
);
// Step 2: Execute the quote immediately using executeQuote function
- const executeResult = await executeQuote(walletAddress, network, quoteResult.quoteId, gasPrice, maxGas);
+ const executeResult = await executeQuote(walletAddress, network, quoteResult.quoteId);
return executeResult;
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on 0x in one step',
- tags: ['/connector/0x'],
- body: ZeroXExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct, gasPrice, maxGas } =
- request.body as typeof ZeroXExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- gasPrice,
- maxGas,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing 0x swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/0x/router-routes/index.ts b/src/connectors/0x/router-routes/index.ts
deleted file mode 100644
index e226067b2e..0000000000
--- a/src/connectors/0x/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const zeroXRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default zeroXRouterRoutes;
diff --git a/src/connectors/0x/router-routes/quoteSwap.ts b/src/connectors/0x/router-routes/quoteSwap.ts
index 8a852a027b..55f624ef87 100644
--- a/src/connectors/0x/router-routes/quoteSwap.ts
+++ b/src/connectors/0x/router-routes/quoteSwap.ts
@@ -1,17 +1,14 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { ZeroX } from '../0x';
import { ZeroXConfig } from '../0x.config';
-import { ZeroXQuoteSwapRequest, ZeroXQuoteSwapResponse } from '../schemas';
-
+import { ZeroXQuoteSwapResponse } from '../schemas';
async function quoteSwap(
network: string,
baseToken: string,
@@ -167,56 +164,5 @@ async function quoteSwap(
export { quoteSwap };
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description:
- 'Get a swap quote from 0x. Use indicativePrice=true for price discovery only, or false/undefined for executable quotes',
- tags: ['/connector/0x'],
- querystring: ZeroXQuoteSwapRequest,
- response: { 200: ZeroXQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, slippagePct, indicativePrice, takerAddress } =
- request.query as typeof ZeroXQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- indicativePrice ?? true,
- takerAddress,
- );
- } catch (e: any) {
- if (e.statusCode) throw e;
- logger.error('Error getting 0x quote:', e.message || e);
-
- // Handle specific error cases
- if (e.message?.includes('0x API key not configured')) {
- throw httpErrors.badRequest(e.message);
- }
- if (e.message?.includes('0x API Error')) {
- throw httpErrors.badRequest(e.message);
- }
-
- // Return the actual error message instead of generic one
- throw httpErrors.internalServerError(e.message || 'Failed to get quote');
- }
- },
- );
-};
-
// Export quote cache for use in execute-quote
export { quoteCache };
-
-export default quoteSwapRoute;
diff --git a/src/connectors/0x/schemas.ts b/src/connectors/0x/schemas.ts
index dbd0a0301f..01512c3f3c 100644
--- a/src/connectors/0x/schemas.ts
+++ b/src/connectors/0x/schemas.ts
@@ -1,65 +1,4 @@
-import { Type, Static } from '@sinclair/typebox';
-
-import { getEthereumChainConfig } from '../../chains/ethereum/ethereum.config';
-import * as Base from '../../schemas/router-schema';
-
-import { ZeroXConfig } from './0x.config';
-
-// Get chain config for defaults
-const ethereumChainConfig = getEthereumChainConfig();
-
-// Constants for examples
-const BASE_TOKEN = 'WETH';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 1;
-
-// 0x-specific quote-swap request (superset of base QuoteSwapRequest)
-export const ZeroXQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...ZeroXConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'First token in the trading pair',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Second token in the trading pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- examples: [1],
- }),
- ),
- indicativePrice: Type.Optional(
- Type.Boolean({
- description:
- 'If true, returns indicative pricing only (no commitment). If false, returns firm quote ready for execution',
- default: true,
- }),
- ),
- takerAddress: Type.Optional(
- Type.String({
- description: 'Ethereum wallet address that will execute the swap (optional for quotes)',
- }),
- ),
-});
+import { Type } from '@sinclair/typebox';
// 0x-specific quote-swap response (superset of base QuoteSwapResponse)
export const ZeroXQuoteSwapResponse = Type.Object({
@@ -124,91 +63,3 @@ export const ZeroXQuoteSwapResponse = Type.Object({
}),
),
});
-
-// 0x-specific execute-quote request (superset of base ExecuteQuoteRequest)
-export const ZeroXExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The blockchain network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...ZeroXConfig.networks],
- examples: [...ZeroXConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [1000000],
- }),
- ),
-});
-
-// 0x-specific execute-swap request (superset of base ExecuteSwapRequest)
-export const ZeroXExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- examples: [ethereumChainConfig.defaultWallet],
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The blockchain network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...ZeroXConfig.networks],
- examples: [...ZeroXConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other token in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- examples: [1],
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
diff --git a/src/connectors/clmm-v3-utils.ts b/src/connectors/clmm-v3-utils.ts
new file mode 100644
index 0000000000..de831a1340
--- /dev/null
+++ b/src/connectors/clmm-v3-utils.ts
@@ -0,0 +1,138 @@
+import { Contract } from '@ethersproject/contracts';
+
+import { BinLiquidity } from '../schemas/clmm-schema';
+
+/**
+ * Per-bin liquidity distribution around the current tick for a Uniswap-V3-style
+ * pool. Shared by the Uniswap and PancakeSwap connectors — PancakeSwap V3 is a
+ * Uniswap V3 fork with identical tick semantics, so the walk is the same; each
+ * connector passes its own SDK's math implementations rather than depending on
+ * the other's.
+ *
+ * V3 has no equivalent of Orca's "fetch all positions for pool" RPC — positions
+ * are NFTs on the position manager. Instead we walk the pool's per-tick
+ * liquidity profile directly:
+ *
+ * 1. Read `liquidityNet` at every bin boundary in the window via parallel
+ * `pool.ticks(tick)` reads (one eth_call each, fired with Promise.all).
+ * Ticks that have never been initialized return zeros — that's harmless.
+ * 2. Start with the pool's active L = pool.liquidity() in the bin that
+ * contains the current tick. Propagate L outward by adding/subtracting
+ * `liquidityNet` at each boundary crossed (per the V3 spec).
+ * 3. For each bin, convert L → (amount0, amount1) via
+ * getAmount{0,1}Delta(sqrtA, sqrtB, L, false), splitting at the pool's
+ * current sqrtPriceX96 when the bin straddles the active tick.
+ * 4. Map to base/quote using `isBaseToken0`, scale by decimals.
+ *
+ * Output shape mirrors Meteora's `pool-info.bins[]`.
+ */
+
+// Structural types for the V3 SDK math, in native bigint. The SDKs disagree on
+// their numeric type — @uniswap/v3-sdk is JSBI-based, @pancakeswap/v3-sdk uses
+// native bigint — so each connector adapts its own SDK to this interface rather
+// than one connector importing the other's math.
+export interface V3TickMath {
+ getSqrtRatioAtTick(tick: number): bigint;
+}
+
+export interface V3SqrtPriceMath {
+ getAmount0Delta(sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, liquidity: bigint, roundUp: boolean): bigint;
+ getAmount1Delta(sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, liquidity: bigint, roundUp: boolean): bigint;
+}
+
+export async function computeV3BinDistribution(args: {
+ poolContract: Contract;
+ tickSpacing: number;
+ currentTick: number;
+ currentSqrtPriceX96: bigint;
+ activeLiquidity: bigint;
+ decimals0: number;
+ decimals1: number;
+ isBaseToken0: boolean;
+ binCount: number;
+ tickMath: V3TickMath;
+ sqrtPriceMath: V3SqrtPriceMath;
+}): Promise {
+ const {
+ poolContract,
+ tickSpacing,
+ currentTick,
+ currentSqrtPriceX96,
+ activeLiquidity,
+ decimals0,
+ decimals1,
+ isBaseToken0,
+ binCount,
+ tickMath,
+ sqrtPriceMath,
+ } = args;
+ if (binCount <= 0) return [];
+
+ const halfBins = Math.floor(binCount / 2);
+ const snapped = Math.floor(currentTick / tickSpacing) * tickSpacing;
+ const firstBinStart = snapped - halfBins * tickSpacing;
+ const boundaries: number[] = [];
+ for (let i = 0; i <= binCount; i++) {
+ boundaries.push(firstBinStart + i * tickSpacing);
+ }
+
+ // Parallel reads of pool.ticks(tick) at each boundary. Non-initialized
+ // ticks return zeros which is the correct neutral element for liquidityNet.
+ const tickData = await Promise.all(
+ boundaries.map((tick) => poolContract.ticks(tick).catch(() => ({ liquidityNet: 0 }))),
+ );
+
+ const curIdx = Math.floor((currentTick - firstBinStart) / tickSpacing);
+
+ // Propagate L outward from the current bin (V3 spec: crossing a tick going
+ // UP adds liquidityNet, going DOWN subtracts it).
+ const binLs: bigint[] = new Array(binCount);
+ binLs[curIdx] = activeLiquidity;
+ for (let i = curIdx + 1; i < binCount; i++) {
+ const net = BigInt(tickData[i].liquidityNet.toString());
+ binLs[i] = binLs[i - 1] + net;
+ }
+ for (let i = curIdx - 1; i >= 0; i--) {
+ const net = BigInt(tickData[i + 1].liquidityNet.toString());
+ binLs[i] = binLs[i + 1] - net;
+ }
+
+ const scale0 = Math.pow(10, decimals0);
+ const scale1 = Math.pow(10, decimals1);
+ const zero = 0n;
+ const bins: BinLiquidity[] = [];
+ for (let i = 0; i < binCount; i++) {
+ const tickStart = boundaries[i];
+ const tickEnd = boundaries[i + 1];
+ const L = binLs[i];
+ let amount0: bigint = zero;
+ let amount1: bigint = zero;
+ if (L > zero) {
+ const sqrtA = tickMath.getSqrtRatioAtTick(tickStart);
+ const sqrtB = tickMath.getSqrtRatioAtTick(tickEnd);
+ if (currentTick >= tickEnd) {
+ amount1 = sqrtPriceMath.getAmount1Delta(sqrtA, sqrtB, L, false);
+ } else if (currentTick < tickStart) {
+ amount0 = sqrtPriceMath.getAmount0Delta(sqrtA, sqrtB, L, false);
+ } else {
+ amount0 = sqrtPriceMath.getAmount0Delta(currentSqrtPriceX96, sqrtB, L, false);
+ amount1 = sqrtPriceMath.getAmount1Delta(sqrtA, currentSqrtPriceX96, L, false);
+ }
+ }
+ const amt0 = parseFloat(amount0.toString()) / scale0;
+ const amt1 = parseFloat(amount1.toString()) / scale1;
+ const baseTokenAmount = isBaseToken0 ? amt0 : amt1;
+ const quoteTokenAmount = isBaseToken0 ? amt1 : amt0;
+
+ // Price at tickStart in human units (quote/base regardless of token order).
+ const rawT1PerT0 = Math.pow(1.0001, tickStart) * Math.pow(10, decimals0 - decimals1);
+ const price = isBaseToken0 ? rawT1PerT0 : 1 / rawT1PerT0;
+ bins.push({
+ binId: tickStart,
+ price,
+ baseTokenAmount,
+ quoteTokenAmount,
+ });
+ }
+ return bins;
+}
diff --git a/src/connectors/dflow/README.md b/src/connectors/dflow/README.md
index a5b399e2bc..62bf311dce 100644
--- a/src/connectors/dflow/README.md
+++ b/src/connectors/dflow/README.md
@@ -1,11 +1,12 @@
# DFlow Router Connector
-[DFlow](https://dflow.net) is a low-latency DEX aggregator built for Solana. This connector
-exposes DFlow through Gateway's standard router endpoints:
+[DFlow](https://dflow.net) is a low-latency DEX aggregator built for Solana. Like every
+router connector it is reached through the unified trading routes, naming `dflow` as the
+`connector`:
-- `GET /connectors/dflow/router/quote-swap`
-- `POST /connectors/dflow/router/execute-quote`
-- `POST /connectors/dflow/router/execute-swap`
+- `GET /trading/router/quote-swap`
+- `POST /trading/router/execute-quote`
+- `POST /trading/router/execute-swap`
Network support: `mainnet-beta` only.
diff --git a/src/connectors/dflow/dflow.routes.ts b/src/connectors/dflow/dflow.routes.ts
deleted file mode 100644
index 31f71248b9..0000000000
--- a/src/connectors/dflow/dflow.routes.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { dflowRouterRoutes } from './router-routes';
-
-// DFlow routes with 3 endpoints
-const dflowRouterRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- // Decorate the instance with a hook to modify route options
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/dflow'];
- }
- });
-
- await instance.register(dflowRouterRoutes);
- });
-};
-
-// Export routes in the same pattern as Jupiter
-export const dflowRoutes = {
- router: dflowRouterRoutesWrapper,
-};
diff --git a/src/connectors/dflow/router-routes/executeQuote.ts b/src/connectors/dflow/router-routes/executeQuote.ts
index 8cfba7e664..665f7b2fb9 100644
--- a/src/connectors/dflow/router-routes/executeQuote.ts
+++ b/src/connectors/dflow/router-routes/executeQuote.ts
@@ -1,12 +1,9 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { DFlow } from '../dflow';
-import { DFlowExecuteQuoteRequest } from '../schemas';
export async function executeQuote(
walletAddress: string,
@@ -22,7 +19,7 @@ export async function executeQuote(
const solana = await Solana.getInstance(network);
const dflow = await DFlow.getInstance(network);
- const { inputToken, outputToken, quoteResponse } = cached;
+ const { inputToken, outputToken, quoteResponse, slippagePct } = cached;
// Build the swap UNSIGNED with the wallet as authority, then sign + send via the
// wallet-type-aware chokepoint (local keypair / Ledger) — no per-wallet-type branching here.
@@ -32,18 +29,18 @@ export async function executeQuote(
const transaction = await dflow.buildSwapTransactionUnsigned(walletAddress, quoteResponse);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
+ undefined,
+ slippagePct,
);
// Remove quote from cache only after successful execution (confirmed)
@@ -56,33 +53,3 @@ export async function executeQuote(
return result as SwapExecuteResponseType;
}
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from DFlow',
- tags: ['/connector/dflow'],
- body: DFlowExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, quoteId } = request.body as typeof DFlowExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing DFlow quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/dflow/router-routes/executeSwap.ts b/src/connectors/dflow/router-routes/executeSwap.ts
index 312901b915..9ea1df357c 100644
--- a/src/connectors/dflow/router-routes/executeSwap.ts
+++ b/src/connectors/dflow/router-routes/executeSwap.ts
@@ -1,10 +1,5 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { DFlowConfig } from '../dflow.config';
-import { DFlowExecuteSwapRequest } from '../schemas';
import { executeQuote } from './executeQuote';
import { quoteSwap } from './quoteSwap';
@@ -35,43 +30,3 @@ async function executeSwap(
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on DFlow in one step',
- tags: ['/connector/dflow'],
- body: DFlowExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut } =
- request.body as typeof DFlowExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing DFlow swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/dflow/router-routes/index.ts b/src/connectors/dflow/router-routes/index.ts
deleted file mode 100644
index bed0d187f1..0000000000
--- a/src/connectors/dflow/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const dflowRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default dflowRouterRoutes;
diff --git a/src/connectors/dflow/router-routes/quoteSwap.ts b/src/connectors/dflow/router-routes/quoteSwap.ts
index 9bf093739d..11390459da 100644
--- a/src/connectors/dflow/router-routes/quoteSwap.ts
+++ b/src/connectors/dflow/router-routes/quoteSwap.ts
@@ -1,18 +1,15 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage, sanitizeString } from '../../../services/sanitize';
-import { approximateBuyViaSellLeg } from '../../router-utils';
+import { approximateBuyViaSellLeg, attemptedRoute, priceImpactPercentFromFraction } from '../../router-utils';
import { DFlow, DFlowQuoteResponse } from '../dflow';
import { DFlowConfig } from '../dflow.config';
-import { DFlowQuoteSwapRequest, DFlowQuoteSwapResponse } from '../schemas';
-
+import { DFlowQuoteSwapResponse } from '../schemas';
export async function quoteSwap(
network: string,
baseToken: string,
@@ -48,8 +45,8 @@ export async function quoteSwap(
try {
quoteResponse = await dflow.getQuote(inputToken.address, outputToken.address, amountRaw, slippageBps);
} catch (error) {
- const tokenPair = `${sanitizeString(baseToken)} -> ${sanitizeString(quoteToken)}`;
- throw httpErrors.noRouteFound(`No route found for ${tokenPair} (ExactIn). ${error?.message || error}`);
+ const route = attemptedRoute(side, sanitizeString(baseToken), sanitizeString(quoteToken));
+ throw httpErrors.noRouteFound(`No route found for ${route}. ${error?.message || error}`);
}
} else {
// DFlow is ExactIn-only (it silently ignores swapMode and quotes ExactIn, verified
@@ -106,49 +103,13 @@ export async function quoteSwap(
amountIn: side === 'SELL' ? amount : estimatedAmountIn,
amountOut: estimatedAmountOut,
price,
- priceImpactPct: parseFloat(quoteResponse.priceImpactPct || '0'),
+ // DFlow serves Jupiter's quote schema field for field — same name, same string type,
+ // same siblings — so its priceImpactPct is a fraction too. Inferred from the schema
+ // rather than measured: the public quote endpoint refuses an unkeyed request.
+ priceImpactPct: priceImpactPercentFromFraction(quoteResponse.priceImpactPct),
minAmountOut,
maxAmountIn,
...(isApproximation ? { approximation: true } : {}),
quoteResponse,
};
}
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get an executable swap quote from DFlow',
- tags: ['/connector/dflow'],
- querystring: DFlowQuoteSwapRequest,
- response: { 200: DFlowQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut } =
- request.query as typeof DFlowQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error getting DFlow quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/dflow/schemas.ts b/src/connectors/dflow/schemas.ts
index 5398472c47..22265a6911 100644
--- a/src/connectors/dflow/schemas.ts
+++ b/src/connectors/dflow/schemas.ts
@@ -1,60 +1,8 @@
import { Type } from '@sinclair/typebox';
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { DFlowConfig } from './dflow.config';
-
// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.1;
-
-// DFlow-specific quote-swap request (superset of base QuoteSwapRequest)
-export const DFlowQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...DFlowConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: DFlowConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders: DFlow is ExactIn-only, so BUYs are approximated via a sell-leg ExactIn quote. If false, BUY requests fail with a clear error.',
- default: true,
- }),
- ),
-});
// DFlow-specific quote-swap response (superset of base QuoteSwapResponse)
export const DFlowQuoteSwapResponse = Type.Object({
@@ -95,74 +43,3 @@ export const DFlowQuoteSwapResponse = Type.Object({
description: "DFlow's native quote response, used to build the swap transaction at execution time",
}),
});
-
-// DFlow-specific execute-quote request (superset of base ExecuteQuoteRequest)
-export const DFlowExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...DFlowConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the DFlow quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
-});
-
-// DFlow-specific execute-swap request (superset of base ExecuteSwapRequest)
-export const DFlowExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...DFlowConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: DFlowConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders: DFlow is ExactIn-only, so BUYs are approximated via a sell-leg ExactIn quote. If false, BUY requests fail with a clear error.',
- default: true,
- }),
- ),
-});
diff --git a/src/connectors/evm-slippage.ts b/src/connectors/evm-slippage.ts
new file mode 100644
index 0000000000..19da51b350
--- /dev/null
+++ b/src/connectors/evm-slippage.ts
@@ -0,0 +1,14 @@
+/**
+ * A slippage percentage as the basis-point numerator the EVM SDKs' `Percent(n, 10000)`
+ * takes.
+ *
+ * Uniswap and PancakeSwap each ship their own `Percent` class, so this returns the
+ * numerator rather than a Percent: the call site builds its own SDK's type. The reason it
+ * is a function at all is that the four CLMM liquidity routes used to write
+ * `new Percent(100, 10000)` — a flat 1% that ignored both the caller's slippagePct and the
+ * operator's configured one. Rounding to whole basis points is what the denominator
+ * implies; a tolerance finer than 0.01% is not expressible against it.
+ */
+export function slippageBasisPoints(slippagePct: number): number {
+ return Math.round(slippagePct * 100);
+}
diff --git a/src/connectors/jupiter/jupiter.routes.ts b/src/connectors/jupiter/jupiter.routes.ts
deleted file mode 100644
index f3968bb33c..0000000000
--- a/src/connectors/jupiter/jupiter.routes.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { jupiterRouterRoutes } from './router-routes';
-
-// Jupiter routes with 4 endpoints
-const jupiterRouterRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- // Decorate the instance with a hook to modify route options
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/jupiter'];
- }
- });
-
- await instance.register(jupiterRouterRoutes);
- });
-};
-
-// Export routes in the same pattern as Raydium
-export const jupiterRoutes = {
- router: jupiterRouterRoutesWrapper,
-};
diff --git a/src/connectors/jupiter/router-routes/executeQuote.ts b/src/connectors/jupiter/router-routes/executeQuote.ts
index 6c289efcd8..4325320dbc 100644
--- a/src/connectors/jupiter/router-routes/executeQuote.ts
+++ b/src/connectors/jupiter/router-routes/executeQuote.ts
@@ -1,19 +1,14 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { Jupiter } from '../jupiter';
-import { JupiterExecuteQuoteRequest } from '../schemas';
export async function executeQuote(
walletAddress: string,
network: string,
quoteId: string,
- priorityLevel?: string,
- maxLamports?: number,
): Promise {
// Retrieve cached quote
const quote = quoteCache.get(quoteId);
@@ -38,27 +33,22 @@ export async function executeQuote(
logger.info(
`Executing quote ${quoteId} for ${inputToken.symbol} -> ${outputToken.symbol}, slippageBps=${quote.slippageBps}`,
);
- const transaction = await jupiter.buildSwapTransactionForHardwareWallet(
- walletAddress,
- quote,
- maxLamports,
- priorityLevel,
- );
+ const transaction = await jupiter.buildSwapTransactionForHardwareWallet(walletAddress, quote);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
// Handle confirmation status
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
+ undefined,
+ quote.slippageBps != null ? quote.slippageBps / 100 : undefined,
);
// Remove quote from cache only after successful execution (confirmed)
@@ -71,34 +61,3 @@ export async function executeQuote(
return result as SwapExecuteResponseType;
}
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from Jupiter',
- tags: ['/connector/jupiter'],
- body: JupiterExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, quoteId, priorityLevel, maxLamports } =
- request.body as typeof JupiterExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId, priorityLevel, maxLamports);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/jupiter/router-routes/executeSwap.ts b/src/connectors/jupiter/router-routes/executeSwap.ts
index 078170b326..daeb1ae980 100644
--- a/src/connectors/jupiter/router-routes/executeSwap.ts
+++ b/src/connectors/jupiter/router-routes/executeSwap.ts
@@ -1,10 +1,5 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { JupiterConfig } from '../jupiter.config';
-import { JupiterExecuteSwapRequest } from '../schemas';
import { executeQuote } from './executeQuote';
import { quoteSwap } from './quoteSwap';
@@ -17,8 +12,6 @@ async function executeSwap(
amount: number,
side: 'BUY' | 'SELL',
slippagePct: number = JupiterConfig.config.slippagePct,
- priorityLevel?: string,
- maxLamports?: number,
approximateIfNoExactOut: boolean = true,
): Promise {
// Step 1: Get a fresh quote using the quoteSwap function
@@ -29,73 +22,13 @@ async function executeSwap(
amount,
side,
slippagePct,
- undefined,
- undefined,
approximateIfNoExactOut,
);
- // Step 2: Execute the quote immediately using executeQuote function
- const executeResult = await executeQuote(
- walletAddress,
- network,
- quoteResult.quoteId,
- priorityLevel ?? JupiterConfig.config.priorityLevel,
- maxLamports ?? JupiterConfig.config.maxLamports,
- );
+ // Step 2: Execute the quote immediately (priority fees come from the connector config)
+ const executeResult = await executeQuote(walletAddress, network, quoteResult.quoteId);
return executeResult;
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on Jupiter in one step',
- tags: ['/connector/jupiter'],
- body: JupiterExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const {
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side,
- slippagePct,
- priorityLevel,
- maxLamports,
- approximateIfNoExactOut,
- } = request.body as typeof JupiterExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- priorityLevel,
- maxLamports,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/jupiter/router-routes/index.ts b/src/connectors/jupiter/router-routes/index.ts
deleted file mode 100644
index 0bf7c37769..0000000000
--- a/src/connectors/jupiter/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const jupiterRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default jupiterRouterRoutes;
diff --git a/src/connectors/jupiter/router-routes/quoteSwap.ts b/src/connectors/jupiter/router-routes/quoteSwap.ts
index a66809bf1e..ea89cc2680 100644
--- a/src/connectors/jupiter/router-routes/quoteSwap.ts
+++ b/src/connectors/jupiter/router-routes/quoteSwap.ts
@@ -1,18 +1,15 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage, sanitizeString } from '../../../services/sanitize';
-import { approximateBuyViaSellLeg } from '../../router-utils';
+import { approximateBuyViaSellLeg, attemptedRoute, priceImpactPercentFromFraction } from '../../router-utils';
import { Jupiter } from '../jupiter';
import { JupiterConfig } from '../jupiter.config';
-import { JupiterQuoteSwapRequest, JupiterQuoteSwapResponse } from '../schemas';
-
+import { JupiterQuoteSwapResponse } from '../schemas';
export async function quoteSwap(
network: string,
baseToken: string,
@@ -20,8 +17,6 @@ export async function quoteSwap(
amount: number,
side: 'BUY' | 'SELL',
slippagePct: number = JupiterConfig.config.slippagePct,
- onlyDirectRoutes?: boolean,
- restrictIntermediateTokens?: boolean,
approximateIfNoExactOut: boolean = true,
): Promise> {
const solana = await Solana.getInstance(network);
@@ -43,9 +38,10 @@ export async function quoteSwap(
logger.info(`Getting quote for ${amount} ${inputToken.symbol} -> ${outputToken.symbol}`);
- const effectiveOnlyDirectRoutes = onlyDirectRoutes ?? JupiterConfig.config.onlyDirectRoutes;
- const effectiveRestrictIntermediateTokens =
- restrictIntermediateTokens ?? JupiterConfig.config.restrictIntermediateTokens;
+ // Routing policy comes from the connector config (conf/connectors/jupiter.yml),
+ // not per-request parameters.
+ const effectiveOnlyDirectRoutes = JupiterConfig.config.onlyDirectRoutes;
+ const effectiveRestrictIntermediateTokens = JupiterConfig.config.restrictIntermediateTokens;
let quoteResponse;
let approximation = false;
@@ -98,15 +94,21 @@ export async function quoteSwap(
quoteResponse = approximated.forwardQuote.quote;
approximation = true;
} catch (fallbackError) {
- const tokenPair = `${sanitizeString(baseToken)} -> ${sanitizeString(quoteToken)}`;
const msg = fallbackError?.message || String(fallbackError);
- throw httpErrors.noRouteFound(`No route found for ${tokenPair} (ExactOut, ExactIn fallback failed). ${msg}`);
+ const route = attemptedRoute(
+ side,
+ sanitizeString(baseToken),
+ sanitizeString(quoteToken),
+ 'ExactOut, ExactIn fallback failed',
+ );
+ throw httpErrors.noRouteFound(`No route found for ${route}. ${msg}`);
}
} else {
- // Pass through Jupiter's error with context
- const tokenPair = `${sanitizeString(baseToken)} -> ${sanitizeString(quoteToken)}`;
- const swapMode = side === 'BUY' ? 'ExactOut' : 'ExactIn';
- throw httpErrors.noRouteFound(`No route found for ${tokenPair} (${swapMode}). ${errorMessage}`);
+ // Pass through Jupiter's error, naming the route that was actually attempted. This
+ // branch serves a failed SELL and a BUY that declined approximation, and the two
+ // are quoted in opposite directions and opposite modes.
+ const route = attemptedRoute(side, sanitizeString(baseToken), sanitizeString(quoteToken));
+ throw httpErrors.noRouteFound(`No route found for ${route}. ${errorMessage}`);
}
}
@@ -151,7 +153,7 @@ export async function quoteSwap(
amountIn: side === 'SELL' ? amount : estimatedAmountIn,
amountOut: outputIsExact ? amount : estimatedAmountOut,
price,
- priceImpactPct: parseFloat(quoteResponse.priceImpactPct || '0'),
+ priceImpactPct: priceImpactPercentFromFraction(quoteResponse.priceImpactPct),
minAmountOut,
maxAmountIn,
approximation,
@@ -164,6 +166,8 @@ export async function quoteSwap(
otherAmountThreshold: quoteResponse.otherAmountThreshold || '0',
swapMode: quoteResponse.swapMode || 'ExactIn',
slippageBps: quoteResponse.slippageBps,
+ // Jupiter's own payload, handed back to Jupiter at execution: its fields stay in
+ // Jupiter's units. Only the unified field above is normalised to a percentage.
priceImpactPct: quoteResponse.priceImpactPct || '0',
routePlan: quoteResponse.routePlan || [],
contextSlot: quoteResponse.contextSlot,
@@ -171,53 +175,3 @@ export async function quoteSwap(
},
};
}
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get an executable swap quote from Jupiter',
- tags: ['/connector/jupiter'],
- querystring: JupiterQuoteSwapRequest,
- response: { 200: JupiterQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const {
- network,
- baseToken,
- quoteToken,
- amount,
- side,
- slippagePct,
- onlyDirectRoutes,
- restrictIntermediateTokens,
- approximateIfNoExactOut,
- } = request.query as typeof JupiterQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- onlyDirectRoutes,
- restrictIntermediateTokens,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error getting quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/jupiter/schemas.ts b/src/connectors/jupiter/schemas.ts
index e454b2ece5..abbfe7a352 100644
--- a/src/connectors/jupiter/schemas.ts
+++ b/src/connectors/jupiter/schemas.ts
@@ -1,72 +1,8 @@
import { Type } from '@sinclair/typebox';
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { JupiterConfig } from './jupiter.config';
-
// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.1;
-
-// Jupiter-specific quote-swap request (superset of base QuoteSwapRequest)
-export const JupiterQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...JupiterConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: JupiterConfig.config.slippagePct,
- }),
- ),
- restrictIntermediateTokens: Type.Optional(
- Type.Boolean({
- description: 'Restrict routing through highly liquid intermediate tokens only for better price and stability',
- default: JupiterConfig.config.restrictIntermediateTokens,
- }),
- ),
- onlyDirectRoutes: Type.Optional(
- Type.Boolean({
- description: 'Restrict routing to only go through 1 market',
- default: JupiterConfig.config.onlyDirectRoutes,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders when the pair has no ExactOut route: approximate via a sell-leg ExactIn quote instead of failing',
- default: true,
- }),
- ),
-});
// Jupiter-specific quote-swap response (superset of base QuoteSwapResponse)
export const JupiterQuoteSwapResponse = Type.Object({
@@ -147,112 +83,3 @@ export const JupiterQuoteSwapResponse = Type.Object({
}),
),
});
-
-// Jupiter-specific execute-quote request (superset of base ExecuteQuoteRequest)
-export const JupiterExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...JupiterConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the Jupiter quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
- priorityLevel: Type.Optional(
- Type.String({
- description: 'Priority level for Solana transaction processing',
- enum: ['medium', 'high', 'veryHigh'],
- default: JupiterConfig.config.priorityLevel,
- }),
- ),
- maxLamports: Type.Optional(
- Type.Number({
- description: 'Maximum priority fee in lamports for Solana transaction',
- default: [JupiterConfig.config.maxLamports],
- }),
- ),
-});
-
-// Jupiter-specific execute-swap request (superset of base ExecuteSwapRequest)
-export const JupiterExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...JupiterConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: JupiterConfig.config.slippagePct,
- }),
- ),
- restrictIntermediateTokens: Type.Optional(
- Type.Boolean({
- description: 'Restrict routing through highly liquid intermediate tokens only for better price and stability',
- default: JupiterConfig.config.restrictIntermediateTokens,
- }),
- ),
- onlyDirectRoutes: Type.Optional(
- Type.Boolean({
- description: 'Restrict routing to only go through 1 market',
- default: JupiterConfig.config.onlyDirectRoutes,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders when the pair has no ExactOut route: approximate via a sell-leg ExactIn quote instead of failing',
- default: true,
- }),
- ),
- priorityLevel: Type.Optional(
- Type.String({
- description: 'Priority level for Solana transaction processing',
- enum: ['medium', 'high', 'veryHigh'],
- default: JupiterConfig.config.priorityLevel,
- }),
- ),
- maxLamports: Type.Optional(
- Type.Number({
- description: 'Maximum priority fee in lamports for Solana transaction',
- default: JupiterConfig.config.maxLamports,
- }),
- ),
-});
diff --git a/src/connectors/meteora/amm-routes/addLiquidity.ts b/src/connectors/meteora/amm-routes/addLiquidity.ts
index 4decdb7f4d..9519706a0e 100644
--- a/src/connectors/meteora/amm-routes/addLiquidity.ts
+++ b/src/connectors/meteora/amm-routes/addLiquidity.ts
@@ -1,14 +1,13 @@
-import { Keypair, PublicKey, Transaction } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
+import { PublicKey } from '@solana/web3.js';
import { Solana } from '../../../chains/solana/solana';
-import { AddLiquidityResponse, AddLiquidityResponseType } from '../../../schemas/amm-schema';
+import { AddLiquidityResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { MeteoraDamm } from '../meteora-damm';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraAmmAddLiquidityRequest } from '../schemas';
+import { openPosition } from './openPosition';
import { getLiquidityQuote } from './quoteLiquidity';
export async function addLiquidity(
@@ -20,6 +19,35 @@ export async function addLiquidity(
slippagePct: number = MeteoraConfig.config.slippagePct,
positionAddress?: string,
): Promise {
+ // Opening a new position is its own on-chain operation (it mints the position NFT
+ // and locks rent), so it lives in openPosition and is reachable directly through
+ // /trading/amm/open. Adding without a position address still opens one — we never
+ // silently pick an existing position — and passes its address and rent through, so
+ // the caller who just paid for it is told which position it is.
+ if (!positionAddress) {
+ const opened = await openPosition(
+ network,
+ walletAddress,
+ poolAddress,
+ baseTokenAmount,
+ quoteTokenAmount,
+ slippagePct,
+ );
+ return opened.data
+ ? {
+ signature: opened.signature,
+ status: opened.status,
+ data: {
+ fee: opened.data.fee,
+ positionAddress: opened.data.positionAddress,
+ positionRent: opened.data.positionRent,
+ baseTokenAmountAdded: opened.data.baseTokenAmountAdded,
+ quoteTokenAmountAdded: opened.data.quoteTokenAmountAdded,
+ },
+ }
+ : { signature: opened.signature, status: opened.status };
+ }
+
const solana = await Solana.getInstance(network);
const meteoraDamm = await MeteoraDamm.getInstance(network);
@@ -31,13 +59,23 @@ export async function addLiquidity(
throw httpErrors.badRequest('Computed liquidity is zero — increase the token amounts');
}
- const owner = new PublicKey(walletAddress);
- const pool = new PublicKey(poolAddress);
-
- let transaction: Transaction;
- const extraSigners: Keypair[] = [];
+ const existing = await meteoraDamm.getUserPositions(poolAddress, walletAddress);
+ const target = existing.find((p) => p.position.toBase58() === positionAddress);
+ if (!target) {
+ throw httpErrors.notFound(
+ `Position ${positionAddress} not found for wallet in pool ${poolAddress}. ` +
+ 'List the wallet positions with position-info, or omit positionAddress to open a new position.',
+ );
+ }
- const shared = {
+ logger.info(`Adding liquidity to existing DAMM v2 position ${target.position.toBase58()} in pool ${poolAddress}`);
+ const transaction = await meteoraDamm.cpAmm.addLiquidity({
+ owner: new PublicKey(walletAddress),
+ pool: new PublicKey(poolAddress),
+ position: target.position,
+ positionNftAccount: target.positionNftAccount,
+ tokenAVault: poolState.tokenAVault,
+ tokenBVault: poolState.tokenBVault,
liquidityDelta: quote.liquidityDelta,
maxAmountTokenA: quote.maxAmountTokenA,
maxAmountTokenB: quote.maxAmountTokenB,
@@ -47,48 +85,13 @@ export async function addLiquidity(
tokenBMint: poolState.tokenBMint,
tokenAProgram,
tokenBProgram,
- };
-
- // DAMM v2 positions are NFTs; a wallet may hold several per pool. If a position address is given,
- // add to that specific position (owner-filtered lookup also proves ownership + pool membership).
- // If omitted, open a NEW position NFT — we never silently pick an existing one.
- if (positionAddress) {
- const existing = await meteoraDamm.getUserPositions(poolAddress, walletAddress);
- const target = existing.find((p) => p.position.toBase58() === positionAddress);
- if (!target) {
- throw httpErrors.notFound(
- `Position ${positionAddress} not found for wallet in pool ${poolAddress}. ` +
- 'List the wallet positions with position-info, or omit positionAddress to open a new position.',
- );
- }
- logger.info(`Adding liquidity to existing DAMM v2 position ${target.position.toBase58()} in pool ${poolAddress}`);
- transaction = await meteoraDamm.cpAmm.addLiquidity({
- owner,
- pool,
- position: target.position,
- positionNftAccount: target.positionNftAccount,
- tokenAVault: poolState.tokenAVault,
- tokenBVault: poolState.tokenBVault,
- ...shared,
- });
- } else {
- const positionNft = Keypair.generate();
- extraSigners.push(positionNft);
- logger.info(`Opening new DAMM v2 position (NFT ${positionNft.publicKey.toBase58()}) in pool ${poolAddress}`);
- transaction = await meteoraDamm.cpAmm.createPositionAndAddLiquidity({
- owner,
- pool,
- positionNft: positionNft.publicKey,
- ...shared,
- });
- }
-
- const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress, extraSigners);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
});
+ const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
+
if (txData) {
const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
poolState.tokenAMint.toBase58(),
@@ -99,6 +102,10 @@ export async function addLiquidity(
status: 1, // CONFIRMED
data: {
fee: txData.meta.fee / 1e9,
+ // Echoed so the field always names the position the write touched, whether it
+ // was opened by this call or named by the caller. No rent: the account already
+ // existed, so this add locked none.
+ positionAddress: target.position.toBase58(),
baseTokenAmountAdded: Math.abs(balanceChanges[0]),
quoteTokenAmountAdded: Math.abs(balanceChanges[1]),
},
@@ -106,46 +113,3 @@ export async function addLiquidity(
}
return { signature, status: 0 }; // PENDING
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: typeof MeteoraAmmAddLiquidityRequest.static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description:
- 'Add liquidity to a Meteora DAMM v2 pool. Provide positionAddress to add to a specific ' +
- 'position (NFT); omit it to open a new position.',
- tags: ['/connector/meteora'],
- body: MeteoraAmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct, positionAddress } =
- request.body;
- const effectiveSlippage = slippagePct ?? MeteoraConfig.config.slippagePct;
- return await addLiquidity(
- network,
- walletAddress,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- effectiveSlippage,
- positionAddress,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to add liquidity');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/meteora/amm-routes/closePosition.ts b/src/connectors/meteora/amm-routes/closePosition.ts
new file mode 100644
index 0000000000..96fd4d908b
--- /dev/null
+++ b/src/connectors/meteora/amm-routes/closePosition.ts
@@ -0,0 +1,130 @@
+import { PublicKey } from '@solana/web3.js';
+import BN from 'bn.js';
+import { Decimal } from 'decimal.js';
+
+import { Solana } from '../../../chains/solana/solana';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
+import { httpErrors } from '../../../services/error-handler';
+import { logger } from '../../../services/logger';
+import { MeteoraDamm } from '../meteora-damm';
+import { MeteoraConfig } from '../meteora.config';
+
+function withSlippageDown(raw: BN, slippagePct: number): BN {
+ return new BN(new Decimal(raw.toString()).mul(1 - slippagePct / 100).toFixed(0));
+}
+
+/**
+ * Withdraw all of a DAMM v2 position's liquidity and close the position account
+ * itself, which returns the account's rent to the wallet.
+ *
+ * Not a route of its own. It is what removeLiquidity does at 100%, because removing
+ * all the liquidity without this leaves an empty position NFT behind still holding
+ * its rent, and nothing later reclaims it. The SDK's
+ * removeAllLiquidityAndClosePosition does both in one transaction.
+ */
+export async function closePosition(
+ network: string,
+ walletAddress: string,
+ poolAddress: string,
+ positionAddress: string,
+ slippagePct: number = MeteoraConfig.config.slippagePct,
+): Promise {
+ const solana = await Solana.getInstance(network);
+ const meteoraDamm = await MeteoraDamm.getInstance(network);
+
+ const poolState = await meteoraDamm.getPoolState(poolAddress);
+
+ // getUserPositions is owner-filtered, so finding the position here also proves the
+ // wallet owns it and that it belongs to this pool.
+ const positions = await meteoraDamm.getUserPositions(poolAddress, walletAddress);
+ const target = positions.find((p) => p.position.toBase58() === positionAddress);
+ if (!target) {
+ throw httpErrors.notFound(
+ `Position ${positionAddress} not found for wallet in pool ${poolAddress}. ` +
+ 'List the wallet positions with position-info.',
+ );
+ }
+
+ const unlocked = target.positionState.unlockedLiquidity;
+ // A position whose liquidity is still vesting cannot be closed: the program keeps
+ // the account alive until the lock expires, so report that instead of failing on-chain.
+ if (target.positionState.vestedLiquidity && !target.positionState.vestedLiquidity.isZero()) {
+ throw httpErrors.badRequest(
+ `Position ${positionAddress} still holds vested (locked) liquidity and cannot be closed yet. ` +
+ 'Remove the unlocked portion with remove, and close once the vesting completes.',
+ );
+ }
+
+ const withdrawQuote = meteoraDamm.cpAmm.getWithdrawQuote({
+ liquidityDelta: unlocked,
+ minSqrtPrice: poolState.sqrtMinPrice,
+ maxSqrtPrice: poolState.sqrtMaxPrice,
+ sqrtPrice: poolState.sqrtPrice,
+ collectFeeMode: poolState.collectFeeMode,
+ tokenAAmount: poolState.tokenAAmount,
+ tokenBAmount: poolState.tokenBAmount,
+ liquidity: poolState.liquidity,
+ });
+
+ const vestings = (await meteoraDamm.cpAmm.getAllVestingsByPosition(target.position)).map((v) => ({
+ account: v.publicKey,
+ vestingState: v.account,
+ }));
+
+ const slot = await solana.connection.getSlot();
+ const time = await solana.connection.getBlockTime(slot);
+ const currentPoint = meteoraDamm.getCurrentPoint(poolState, slot, time ?? Math.floor(Date.now() / 1000));
+
+ logger.info(`Closing DAMM v2 position ${target.position.toBase58()} in pool ${poolAddress}`);
+
+ const transaction = await meteoraDamm.cpAmm.removeAllLiquidityAndClosePosition({
+ owner: new PublicKey(walletAddress),
+ position: target.position,
+ positionNftAccount: target.positionNftAccount,
+ poolState,
+ positionState: target.positionState,
+ tokenAAmountThreshold: withSlippageDown(withdrawQuote.outAmountA, slippagePct),
+ tokenBAmountThreshold: withSlippageDown(withdrawQuote.outAmountB, slippagePct),
+ vestings,
+ currentPoint,
+ });
+
+ const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
+
+ if (!txData) {
+ return { signature, status: 0 }; // PENDING
+ }
+
+ // A DAMM v2 position is three rent-bearing accounts, not one: the position, the NFT
+ // that represents it, and that NFT's token account. All three close here and all three
+ // refund to the wallet, so reading the position's own balance alone — which is what
+ // this did — captured 38% of the refund and left the rest inside the withdrawal.
+ const { closed, rentRefunded } = accountLifecycleSol(txData);
+
+ const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
+ poolState.tokenAMint.toBase58(),
+ poolState.tokenBMint.toBase58(),
+ ]);
+
+ const fee = txData.meta.fee / 1e9;
+ // The native side of the change carries every lamport those accounts gave back; take
+ // all of it out to leave the liquidity actually withdrawn. `closed` rather than
+ // `rentRefunded` because a wrapped-SOL account closing here also returns a balance the
+ // wallet already held, which is not this position's money either. The transaction fee
+ // needs no correction: extractBalanceChangesAndFee already adds it back for the fee
+ // payer and reports it separately as `fee`.
+ return {
+ signature,
+ status: 1, // CONFIRMED
+ data: {
+ fee,
+ positionRentRefunded: rentRefunded,
+ baseTokenAmountRemoved: liquidityWithoutRent(balanceChanges[0], poolState.tokenAMint, closed),
+ quoteTokenAmountRemoved: liquidityWithoutRent(balanceChanges[1], poolState.tokenBMint, closed),
+ },
+ };
+}
diff --git a/src/connectors/meteora/amm-routes/createPool.ts b/src/connectors/meteora/amm-routes/createPool.ts
index abe36ca9bf..789cf805cc 100644
--- a/src/connectors/meteora/amm-routes/createPool.ts
+++ b/src/connectors/meteora/amm-routes/createPool.ts
@@ -3,15 +3,13 @@ import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';
import { Keypair, PublicKey, Transaction } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { MeteoraDamm } from '../meteora-damm';
-import { MeteoraAmmCreatePoolRequest } from '../schemas';
/** Resolves a token symbol or mint address to a PublicKey. */
async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
@@ -55,10 +53,10 @@ async function fetchMarketPrice(
seedAmount: number,
): Promise {
const probeAmount = seedAmount * MARKET_PRICE_PROBE_FRACTION;
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, probeAmount, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, probeAmount, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to seed the pool (${e.message}). ` +
@@ -196,10 +194,9 @@ export async function createPool(
});
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress, [positionNft]);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
@@ -220,52 +217,3 @@ export async function createPool(
}
return { signature, status: 0, poolAddress: pool.toBase58(), price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: typeof MeteoraAmmCreatePoolRequest.static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description: 'Create a new Meteora DAMM v2 pool and seed it with initial liquidity',
- tags: ['/connector/meteora'],
- body: MeteoraAmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- configAddress,
- initialPrice,
- } = request.body;
- return await createPool(
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- configAddress,
- initialPrice,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/meteora/amm-routes/executeSwap.ts b/src/connectors/meteora/amm-routes/executeSwap.ts
index 8e12fe4031..80c52aca83 100644
--- a/src/connectors/meteora/amm-routes/executeSwap.ts
+++ b/src/connectors/meteora/amm-routes/executeSwap.ts
@@ -1,14 +1,11 @@
import { SwapMode } from '@meteora-ag/cp-amm-sdk';
import { PublicKey, Transaction } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteSwapResponse, ExecuteSwapResponseType } from '../../../schemas/amm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { ExecuteSwapResponseType } from '../../../schemas/amm-schema';
import { logger } from '../../../services/logger';
import { MeteoraDamm } from '../meteora-damm';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraAmmExecuteSwapRequest } from '../schemas';
import { getRawSwapQuote } from './quoteSwap';
@@ -61,61 +58,19 @@ export async function executeSwap(
});
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
quote.inputMint.toBase58(),
quote.outputMint.toBase58(),
walletAddress,
side,
+ slippagePct,
);
return result as ExecuteSwapResponseType;
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: typeof MeteoraAmmExecuteSwapRequest.static;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on a Meteora DAMM v2 pool',
- tags: ['/connector/meteora'],
- body: MeteoraAmmExecuteSwapRequest,
- response: {
- 200: ExecuteSwapResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, poolAddress, baseToken, amount, side, slippagePct } = request.body;
- const effectiveSlippage = slippagePct ?? MeteoraConfig.config.slippagePct;
-
- return await executeSwap(
- network,
- walletAddress,
- poolAddress,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- effectiveSlippage,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Swap execution failed');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/meteora/amm-routes/index.ts b/src/connectors/meteora/amm-routes/index.ts
deleted file mode 100644
index 9b93ee334d..0000000000
--- a/src/connectors/meteora/amm-routes/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { addLiquidityRoute } from './addLiquidity';
-import { createPoolRoute } from './createPool';
-import { executeSwapRoute } from './executeSwap';
-import { poolInfoRoute } from './poolInfo';
-import { positionInfoRoute } from './positionInfo';
-import { positionsOwnedRoute } from './positionsOwned';
-import { quoteLiquidityRoute } from './quoteLiquidity';
-import { quoteSwapRoute } from './quoteSwap';
-import { removeLiquidityRoute } from './removeLiquidity';
-
-export const meteoraAmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(quoteLiquidityRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(createPoolRoute);
-};
-
-export default meteoraAmmRoutes;
diff --git a/src/connectors/meteora/amm-routes/openPosition.ts b/src/connectors/meteora/amm-routes/openPosition.ts
new file mode 100644
index 0000000000..49d2746f0a
--- /dev/null
+++ b/src/connectors/meteora/amm-routes/openPosition.ts
@@ -0,0 +1,96 @@
+import { derivePositionAddress } from '@meteora-ag/cp-amm-sdk';
+import { Keypair, PublicKey } from '@solana/web3.js';
+
+import { Solana } from '../../../chains/solana/solana';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { AddLiquidityResponseType } from '../../../schemas/amm-schema';
+import { httpErrors } from '../../../services/error-handler';
+import { logger } from '../../../services/logger';
+import { MeteoraDamm } from '../meteora-damm';
+import { MeteoraConfig } from '../meteora.config';
+
+import { getLiquidityQuote } from './quoteLiquidity';
+
+/**
+ * Open a NEW DAMM v2 position and seed it with liquidity.
+ *
+ * DAMM v2 positions are NFTs, so opening one is a distinct on-chain operation
+ * (`createPositionAndAddLiquidity`) rather than a variant of adding: it mints the
+ * position NFT and locks rent for the account. Adding to a position that already
+ * exists goes through addLiquidity with its address.
+ */
+export async function openPosition(
+ network: string,
+ walletAddress: string,
+ poolAddress: string,
+ baseTokenAmount: number,
+ quoteTokenAmount: number,
+ slippagePct: number = MeteoraConfig.config.slippagePct,
+): Promise {
+ const solana = await Solana.getInstance(network);
+ const meteoraDamm = await MeteoraDamm.getInstance(network);
+
+ const poolState = await meteoraDamm.getPoolState(poolAddress);
+ const { tokenAProgram, tokenBProgram } = meteoraDamm.getTokenPrograms(poolState);
+
+ const quote = await getLiquidityQuote(meteoraDamm, poolState, baseTokenAmount, quoteTokenAmount, slippagePct);
+ if (quote.liquidityDelta.isZero()) {
+ throw httpErrors.badRequest('Computed liquidity is zero — increase the token amounts');
+ }
+
+ const positionNft = Keypair.generate();
+ logger.info(`Opening new DAMM v2 position (NFT ${positionNft.publicKey.toBase58()}) in pool ${poolAddress}`);
+
+ const transaction = await meteoraDamm.cpAmm.createPositionAndAddLiquidity({
+ owner: new PublicKey(walletAddress),
+ pool: new PublicKey(poolAddress),
+ positionNft: positionNft.publicKey,
+ liquidityDelta: quote.liquidityDelta,
+ maxAmountTokenA: quote.maxAmountTokenA,
+ maxAmountTokenB: quote.maxAmountTokenB,
+ tokenAAmountThreshold: quote.maxAmountTokenA,
+ tokenBAmountThreshold: quote.maxAmountTokenB,
+ tokenAMint: poolState.tokenAMint,
+ tokenBMint: poolState.tokenBMint,
+ tokenAProgram,
+ tokenBProgram,
+ });
+
+ const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress, [positionNft]);
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
+
+ if (!txData) {
+ // Submitted but not yet confirmed. The position address is only knowable from
+ // the landed transaction, so it is reported once the poller sees it confirm.
+ return { signature, status: 0 };
+ }
+
+ // Opening locks rent in three accounts — the position, the NFT mint that represents
+ // it, and that mint's token account — and the wallet pays for all of them. Reading the
+ // position's own balance alone left the other two inside the reported deposit.
+ const position = derivePositionAddress(positionNft.publicKey);
+ const { opened, rentLocked } = accountLifecycleSol(txData);
+
+ const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
+ poolState.tokenAMint.toBase58(),
+ poolState.tokenBMint.toBase58(),
+ ]);
+
+ // The native side of the change carries every lamport those accounts locked; take all
+ // of it out to leave the liquidity actually deposited. The transaction fee needs no
+ // correction — extractBalanceChangesAndFee already adds it back for the fee payer and
+ // reports it separately as `fee`.
+ return {
+ signature,
+ status: 1, // CONFIRMED
+ data: {
+ fee: txData.meta.fee / 1e9,
+ positionAddress: position.toBase58(),
+ positionRent: rentLocked,
+ baseTokenAmountAdded: liquidityWithoutRent(balanceChanges[0], poolState.tokenAMint, opened),
+ quoteTokenAmountAdded: liquidityWithoutRent(balanceChanges[1], poolState.tokenBMint, opened),
+ },
+ };
+}
diff --git a/src/connectors/meteora/amm-routes/poolInfo.ts b/src/connectors/meteora/amm-routes/poolInfo.ts
index b03e3b2885..e531dac7b9 100644
--- a/src/connectors/meteora/amm-routes/poolInfo.ts
+++ b/src/connectors/meteora/amm-routes/poolInfo.ts
@@ -1,43 +1,8 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/amm-schema';
-import { logger } from '../../../services/logger';
+import { PoolInfo } from '../../../schemas/amm-schema';
import { MeteoraDamm } from '../meteora-damm';
-import { MeteoraAmmGetPoolInfoRequest } from '../schemas';
/** Standard AMM pool-info entry point (network-based) — consumed by the unified /trading/amm dispatcher. */
export async function getPoolInfo(network: string, poolAddress: string): Promise {
const meteoraDamm = await MeteoraDamm.getInstance(network);
return await meteoraDamm.getPoolInfo(poolAddress);
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: PoolInfo;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get AMM pool information from Meteora DAMM v2',
- tags: ['/connector/meteora'],
- querystring: MeteoraAmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, network } = request.query;
- return await getPoolInfo(network, poolAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to fetch pool info');
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/meteora/amm-routes/positionInfo.ts b/src/connectors/meteora/amm-routes/positionInfo.ts
index a7a7fae47d..2fb648e13b 100644
--- a/src/connectors/meteora/amm-routes/positionInfo.ts
+++ b/src/connectors/meteora/amm-routes/positionInfo.ts
@@ -2,18 +2,10 @@ import { q64ToDecimal } from '@meteora-ag/cp-amm-sdk';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
-import {
- GetPositionInfoRequestType,
- PositionInfo,
- PositionInfoSchema,
- PositionDetail,
-} from '../../../schemas/amm-schema';
+import { PositionInfo, PositionDetail } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { MeteoraDamm } from '../meteora-damm';
-import { MeteoraAmmGetPositionInfoRequest } from '../schemas';
/**
* Standard AMM position-info entry point (network-based) — consumed by the unified /trading/amm
@@ -82,36 +74,3 @@ export async function getPositionInfo(
positions: breakdown,
};
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description:
- "Get the wallet's aggregated liquidity in a Meteora DAMM v2 pool. DAMM v2 positions " +
- 'are NFTs; amounts sum across all of the wallet positions in the pool.',
- tags: ['/connector/meteora'],
- querystring: MeteoraAmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, walletAddress, network } = request.query;
- return await getPositionInfo(network, poolAddress, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to fetch position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/meteora/amm-routes/positionsOwned.ts b/src/connectors/meteora/amm-routes/positionsOwned.ts
index 4be02a47ed..3c16b89477 100644
--- a/src/connectors/meteora/amm-routes/positionsOwned.ts
+++ b/src/connectors/meteora/amm-routes/positionsOwned.ts
@@ -1,11 +1,9 @@
-import { Type } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PositionInfo, PositionInfoSchema } from '../../../schemas/amm-schema';
+import { PositionInfo } from '../../../schemas/amm-schema';
import { logger } from '../../../services/logger';
import { MeteoraDamm } from '../meteora-damm';
-import { MeteoraAmmGetPositionsOwnedRequest, MeteoraAmmGetPositionsOwnedRequestType } from '../schemas';
import { getPositionInfo } from './positionInfo';
@@ -41,34 +39,3 @@ export async function getPositionsOwned(
}
return result;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: MeteoraAmmGetPositionsOwnedRequestType;
- Reply: PositionInfo[];
- }>(
- '/positions-owned',
- {
- schema: {
- description: "List all of a wallet's DAMM v2 positions across all Meteora AMM pools",
- tags: ['/connector/meteora'],
- querystring: MeteoraAmmGetPositionsOwnedRequest,
- response: {
- 200: Type.Array(PositionInfoSchema),
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress } = request.query;
- return await getPositionsOwned(fastify, network, walletAddress);
- } catch (e: any) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to fetch positions');
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/meteora/amm-routes/quoteLiquidity.ts b/src/connectors/meteora/amm-routes/quoteLiquidity.ts
index 78544d13e0..1b3e7e661f 100644
--- a/src/connectors/meteora/amm-routes/quoteLiquidity.ts
+++ b/src/connectors/meteora/amm-routes/quoteLiquidity.ts
@@ -1,17 +1,10 @@
import { PoolState } from '@meteora-ag/cp-amm-sdk';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
-import {
- QuoteLiquidityRequestType,
- QuoteLiquidityResponse,
- QuoteLiquidityResponseType,
-} from '../../../schemas/amm-schema';
-import { logger } from '../../../services/logger';
+import { QuoteLiquidityResponseType } from '../../../schemas/amm-schema';
import { MeteoraDamm } from '../meteora-damm';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraAmmQuoteLiquidityRequest } from '../schemas';
/** A resolved deposit quote: which side limits the deposit, the amounts, and the liquidity delta. */
export interface LiquidityQuote {
@@ -128,34 +121,3 @@ export async function quoteLiquidity(
quoteTokenAmountMax: quote.quoteTokenAmountMax,
};
}
-
-export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteLiquidityRequestType;
- Reply: QuoteLiquidityResponseType;
- }>(
- '/quote-liquidity',
- {
- schema: {
- description: 'Quote amounts for adding liquidity to a Meteora DAMM v2 pool',
- tags: ['/connector/meteora'],
- querystring: MeteoraAmmQuoteLiquidityRequest,
- response: {
- 200: QuoteLiquidityResponse,
- },
- },
- },
- async (request): Promise => {
- try {
- const { network, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct } = request.query;
- return await quoteLiquidity(network, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to quote liquidity');
- }
- },
- );
-};
-
-export default quoteLiquidityRoute;
diff --git a/src/connectors/meteora/amm-routes/quoteSwap.ts b/src/connectors/meteora/amm-routes/quoteSwap.ts
index 02def03bb2..e150eed556 100644
--- a/src/connectors/meteora/amm-routes/quoteSwap.ts
+++ b/src/connectors/meteora/amm-routes/quoteSwap.ts
@@ -2,16 +2,13 @@ import { PoolState, SwapMode } from '@meteora-ag/cp-amm-sdk';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapResponse, QuoteSwapResponseType } from '../../../schemas/amm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { MeteoraDamm } from '../meteora-damm';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraAmmQuoteSwapRequest } from '../schemas';
/**
* A fully-resolved DAMM v2 swap quote. The BN fields are what the swap instruction consumes;
@@ -182,34 +179,3 @@ export async function quoteSwap(
priceImpactPct: quote.priceImpactPct,
};
}
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: typeof MeteoraAmmQuoteSwapRequest.static;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get a swap quote for a Meteora DAMM v2 pool',
- tags: ['/connector/meteora'],
- querystring: MeteoraAmmQuoteSwapRequest,
- response: {
- 200: QuoteSwapResponse,
- },
- },
- },
- async (request): Promise => {
- try {
- const { network, poolAddress, baseToken, amount, side, slippagePct } = request.query;
- return await quoteSwap(network, poolAddress, baseToken, side as 'BUY' | 'SELL', amount, slippagePct);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to get swap quote');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/meteora/amm-routes/removeLiquidity.ts b/src/connectors/meteora/amm-routes/removeLiquidity.ts
index 6a8f15839b..c50cf82f1f 100644
--- a/src/connectors/meteora/amm-routes/removeLiquidity.ts
+++ b/src/connectors/meteora/amm-routes/removeLiquidity.ts
@@ -1,15 +1,15 @@
import { PublicKey, Transaction } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { RemoveLiquidityResponse, RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { MeteoraDamm } from '../meteora-damm';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraAmmRemoveLiquidityRequest } from '../schemas';
+
+import { closePosition } from './closePosition';
function withSlippageDown(raw: BN, slippagePct: number): BN {
return new BN(new Decimal(raw.toString()).mul(1 - slippagePct / 100).toFixed(0));
@@ -27,6 +27,15 @@ export async function removeLiquidity(
throw httpErrors.badRequest('percentageToRemove must be between 0 and 100');
}
+ // Removing everything closes the position account with it. Withdrawing the last of a
+ // position's liquidity and stopping there leaves an empty NFT behind still holding its
+ // rent — around 0.0099 SOL, which on a small position is more than the liquidity — and
+ // no later call reclaims it. The SDK does both in one transaction, so a caller asking
+ // for 100% gets the rent back rather than having to know to ask for it separately.
+ if (percentageToRemove === 100) {
+ return await closePosition(network, walletAddress, poolAddress, positionAddress, slippagePct);
+ }
+
const solana = await Solana.getInstance(network);
const meteoraDamm = await MeteoraDamm.getInstance(network);
@@ -96,10 +105,9 @@ export async function removeLiquidity(
});
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
@@ -118,41 +126,3 @@ export async function removeLiquidity(
}
return { signature, status: 0 }; // PENDING
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: typeof MeteoraAmmRemoveLiquidityRequest.static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a specific position (NFT) in a Meteora DAMM v2 pool',
- tags: ['/connector/meteora'],
- body: MeteoraAmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, poolAddress, positionAddress, percentageToRemove } = request.body;
- return await removeLiquidity(
- network,
- walletAddress,
- poolAddress,
- positionAddress,
- percentageToRemove,
- MeteoraConfig.config.slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to remove liquidity');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/meteora/clmm-routes/addLiquidity.ts b/src/connectors/meteora/clmm-routes/addLiquidity.ts
index dd8f1061ed..202574fc53 100644
--- a/src/connectors/meteora/clmm-routes/addLiquidity.ts
+++ b/src/connectors/meteora/clmm-routes/addLiquidity.ts
@@ -1,23 +1,19 @@
import { StrategyType } from '@meteora-ag/dlmm';
import { DecimalUtil } from '@orca-so/common-sdk';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import { BN } from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { AddLiquidityResponse, AddLiquidityResponseType } from '../../../schemas/clmm-schema';
+import { AddLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraClmmAddLiquidityRequest } from '../schemas';
// Using Fastify's native error handling
// Define error messages
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
const MISSING_AMOUNTS_MESSAGE = 'Missing amounts for liquidity addition';
const INSUFFICIENT_BALANCE_MESSAGE = (token: string, required: string, actual: string) =>
`Insufficient balance for ${token}. Required: ${required}, Available: ${actual}`;
@@ -123,10 +119,9 @@ export async function addLiquidity(
const { signature, fee } = await solana.sendAndConfirmTransactionForWallet(addLiquidityTx, address);
// Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -157,6 +152,10 @@ export async function addLiquidity(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: info.publicKey.toBase58(),
baseTokenAmountAdded: tokenXAddedAmount,
quoteTokenAmountAdded: tokenYAddedAmount,
fee,
@@ -169,49 +168,3 @@ export async function addLiquidity(
};
}
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to a Meteora position',
- tags: ['/connector/meteora'],
- body: MeteoraClmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { walletAddress, positionAddress, baseTokenAmount, quoteTokenAmount, slippagePct, strategyType } =
- request.body;
- const network = request.body.network;
-
- return await addLiquidity(
- network,
- walletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- strategyType,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/meteora/clmm-routes/closePosition.ts b/src/connectors/meteora/clmm-routes/closePosition.ts
index 8351b56844..545ee033fd 100644
--- a/src/connectors/meteora/clmm-routes/closePosition.ts
+++ b/src/connectors/meteora/clmm-routes/closePosition.ts
@@ -1,14 +1,11 @@
import { BN } from '@coral-xyz/anchor';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ClosePositionResponse, ClosePositionResponseType } from '../../../schemas/clmm-schema';
+import { ClosePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
-import { MeteoraClmmClosePositionRequest } from '../schemas';
export async function closePosition(
network: string,
@@ -84,10 +81,9 @@ export async function closePosition(
const signature = lastSignature;
// Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -117,15 +113,16 @@ export async function closePosition(
let totalTokenXReceived = Math.abs(balanceChanges[0]);
let totalTokenYReceived = Math.abs(balanceChanges[1]);
- // When SOL is base/quote, wallet balance change includes: liquidity + fees + rent refund - tx fee
- // We need to subtract rent refund to get actual token amounts
+ // When SOL is base/quote, the wallet's change for that side is liquidity + fees
+ // collected + the rent refund, so back the rent out to leave what the position
+ // actually returned. The transaction fee needs no correction: extractBalanceChangesAndFee
+ // nets it out for the fee payer and reports it separately, so adding it back here
+ // would overstate the amount by one fee.
if (tokenXSymbol === 'SOL') {
- // SOL is base token - subtract rent refund and add back tx fee
- totalTokenXReceived = totalTokenXReceived - positionRentRefunded + totalFee;
+ totalTokenXReceived = totalTokenXReceived - positionRentRefunded;
if (totalTokenXReceived < 0) totalTokenXReceived = 0;
} else if (tokenYSymbol === 'SOL') {
- // SOL is quote token - subtract rent refund and add back tx fee
- totalTokenYReceived = totalTokenYReceived - positionRentRefunded + totalFee;
+ totalTokenYReceived = totalTokenYReceived - positionRentRefunded;
if (totalTokenYReceived < 0) totalTokenYReceived = 0;
}
@@ -142,6 +139,10 @@ export async function closePosition(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: info.publicKey.toBase58(),
fee: totalFee,
positionRentRefunded: positionRentRefunded,
baseTokenAmountRemoved,
@@ -169,50 +170,3 @@ export async function closePosition(
throw error;
}
}
-
-export const closePositionRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: ClosePositionResponseType;
- }>(
- '/close-position',
- {
- schema: {
- description: 'Close a Meteora position',
- tags: ['/connector/meteora'],
- body: MeteoraClmmClosePositionRequest,
- response: {
- 200: ClosePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress } = request.body;
- const networkToUse = network;
-
- return await closePosition(networkToUse, walletAddress, positionAddress);
- } catch (e) {
- logger.error('Close position route error:', {
- message: e.message || 'Unknown error',
- name: e.name,
- code: e.code,
- statusCode: e.statusCode,
- stack: e.stack,
- positionAddress: request.body.positionAddress,
- network: request.body.network,
- walletAddress: request.body.walletAddress,
- });
-
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default closePositionRoute;
diff --git a/src/connectors/meteora/clmm-routes/collectFees.ts b/src/connectors/meteora/clmm-routes/collectFees.ts
index 9f1d347161..fa2dc1ab3d 100644
--- a/src/connectors/meteora/clmm-routes/collectFees.ts
+++ b/src/connectors/meteora/clmm-routes/collectFees.ts
@@ -1,13 +1,10 @@
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CollectFeesResponse, CollectFeesRequestType, CollectFeesResponseType } from '../../../schemas/clmm-schema';
+import { CollectFeesResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
-import { MeteoraClmmCollectFeesRequest } from '../schemas';
export async function collectFees(
network: string,
@@ -72,10 +69,9 @@ export async function collectFees(
const fee = totalFee;
// Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -96,6 +92,10 @@ export async function collectFees(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: info.publicKey.toBase58(),
fee,
baseFeeAmountCollected: Math.abs(collectedFeeX),
quoteFeeAmountCollected: Math.abs(collectedFeeY),
@@ -108,40 +108,3 @@ export async function collectFees(
};
}
}
-
-export const collectFeesRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: CollectFeesResponseType;
- }>(
- '/collect-fees',
- {
- schema: {
- description: 'Collect fees from a Meteora position',
- tags: ['/connector/meteora'],
- body: MeteoraClmmCollectFeesRequest,
- response: {
- 200: CollectFeesResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress } = request.body;
- const networkToUse = network;
-
- return await collectFees(networkToUse, walletAddress, positionAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default collectFeesRoute;
diff --git a/src/connectors/meteora/clmm-routes/createPool.ts b/src/connectors/meteora/clmm-routes/createPool.ts
index c301d9bc46..afe4ccb810 100644
--- a/src/connectors/meteora/clmm-routes/createPool.ts
+++ b/src/connectors/meteora/clmm-routes/createPool.ts
@@ -6,14 +6,12 @@ import DLMM, {
} from '@meteora-ag/dlmm';
import { PublicKey, Transaction } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
-import { MeteoraClmmCreatePoolRequest } from '../schemas';
// A DLMM pool is created with no liquidity; the initial active bin only encodes the starting
// price. binStep/feeBps have no universal default, so both are required request params.
@@ -36,10 +34,10 @@ async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to initialize the pool (${e.message}). ` +
@@ -195,10 +193,9 @@ export async function createPool(
}
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
return {
@@ -208,42 +205,8 @@ export async function createPool(
price: seedPrice,
data: {
fee: txData.meta.fee / 1e9,
- baseTokenAmountAdded: 0,
- quoteTokenAmountAdded: 0,
},
};
}
return { signature, status: 0, poolAddress, price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: typeof MeteoraClmmCreatePoolRequest.static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description:
- 'Create and initialize a new Meteora DLMM pool (LB pair) at an initial price (no liquidity seeded)',
- tags: ['/connector/meteora'],
- body: MeteoraClmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, initialPrice, binStep, feeBps } = request.body;
- return await createPool(network, walletAddress, baseToken, quoteToken, initialPrice, binStep, feeBps);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/meteora/clmm-routes/executeSwap.ts b/src/connectors/meteora/clmm-routes/executeSwap.ts
index b35f741ef9..3b3ab2637f 100644
--- a/src/connectors/meteora/clmm-routes/executeSwap.ts
+++ b/src/connectors/meteora/clmm-routes/executeSwap.ts
@@ -1,15 +1,10 @@
import { SwapQuoteExactOut, SwapQuote } from '@meteora-ag/dlmm';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { getSolanaChainConfig } from '../../../chains/solana/solana.config';
-import { ExecuteSwapResponseType, ExecuteSwapResponse } from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
-import { sanitizeErrorMessage } from '../../../services/sanitize';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraClmmExecuteSwapRequest, MeteoraClmmExecuteSwapRequestType } from '../schemas';
import { resolveCounterToken, getRawSwapQuote } from './quoteSwap';
@@ -91,11 +86,10 @@ export async function executeSwap(
logger.info(`Transaction sent with signature: ${signature}`);
- // Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Get transaction data for confirmation. The retrying fetch throws the shared
+ // landed-but-failed error when the transaction landed with an error, so existence of
+ // txData below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -135,6 +129,7 @@ export async function executeSwap(
fee: txFee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
} else {
@@ -145,95 +140,3 @@ export async function executeSwap(
};
}
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: MeteoraClmmExecuteSwapRequestType;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a token swap on Meteora DLMM',
- tags: ['/connector/meteora'],
- body: MeteoraClmmExecuteSwapRequest,
- response: { 200: ExecuteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, amount, side, poolAddress, slippagePct } = request.body;
-
- // Use defaults if not provided
- const networkUsed = network || getSolanaChainConfig().defaultNetwork;
- const walletAddressUsed = walletAddress || getSolanaChainConfig().defaultWallet;
-
- let poolAddressUsed = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressUsed) {
- const solana = await Solana.getInstance(networkUsed);
-
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'meteora',
- networkUsed,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Meteora`,
- );
- }
-
- poolAddressUsed = pool.address;
- }
- logger.info(`Received swap request: ${amount} ${baseToken} -> ${quoteToken} in pool ${poolAddressUsed}`);
-
- return await executeSwap(
- networkUsed,
- walletAddressUsed,
- poolAddressUsed,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Error executing swap:', e.message || e);
- logger.error('Full error:', JSON.stringify(e, null, 2));
-
- if (e.statusCode) {
- // If it's already an HTTP error, throw it properly
- throw e;
- }
-
- // Check for specific error messages
- const errorMessage = e.message || e.toString();
- if (errorMessage.includes('503') || errorMessage.includes('Service Unavailable')) {
- throw httpErrors.createError(503, 'RPC service temporarily unavailable. Please try again.');
- }
-
- throw httpErrors.internalServerError(`Swap execution failed: ${errorMessage}`);
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/meteora/clmm-routes/fetchPools.ts b/src/connectors/meteora/clmm-routes/fetchPools.ts
index fc8027fb61..448e30d08c 100644
--- a/src/connectors/meteora/clmm-routes/fetchPools.ts
+++ b/src/connectors/meteora/clmm-routes/fetchPools.ts
@@ -1,74 +1,55 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { FetchPoolsResponse } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { FetchPoolsResponseType } from '../../../schemas/clmm-schema';
import { Meteora, MeteoraApiPool } from '../meteora';
-import { MeteoraClmmFetchPoolsRequest } from '../schemas';
-
-export const fetchPoolsRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: {
- network?: string;
- page?: number;
- limit?: number;
- query?: string;
- sortBy?: string;
- includeUnverified?: boolean;
- };
- }>('/fetch-pools', {
- schema: {
- description: 'Fetch Meteora pools from API with search and sorting',
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmFetchPoolsRequest,
- response: {
- 200: FetchPoolsResponse,
- },
- },
- handler: async (request, _reply) => {
- try {
- const { network, page, limit, query, sortBy, includeUnverified } = request.query;
- const meteora = await Meteora.getInstance(network);
+export interface MeteoraFetchPoolsArgs {
+ network: string;
+ limit?: number;
+ query?: string;
+ sortBy?: string;
+ /** 0-based page index. Meteora's API paginates; Orca's does not. */
+ page?: number;
+ includeUnverified?: boolean;
+}
- const result = await meteora.fetchPoolsFromApi({
- page,
- limit,
- query,
- sortBy,
- includeUnverified,
- });
+/**
+ * Fetch pools from Meteora's own pool-discovery API and normalize them into the
+ * shared FetchPoolsResponse shape. Reached through GET /trading/clmm/fetch-pools.
+ */
+export async function fetchPools(args: MeteoraFetchPoolsArgs): Promise {
+ const { network, page, limit, query, sortBy, includeUnverified } = args;
- // Map API response to simplified format
- const pools = result.pools.map((pool: MeteoraApiPool) => ({
- address: pool.address,
- name: pool.name,
- baseTokenAddress: pool.token_x.address,
- baseTokenSymbol: pool.token_x.symbol,
- quoteTokenAddress: pool.token_y.address,
- quoteTokenSymbol: pool.token_y.symbol,
- binStep: pool.pool_config.bin_step,
- baseFee: pool.pool_config.base_fee_pct,
- price: pool.current_price,
- tvl: pool.tvl,
- apr: pool.apr,
- apy: pool.apy,
- volume24h: pool.volume?.['24h'],
- fees24h: pool.fees?.['24h'],
- }));
+ const meteora = await Meteora.getInstance(network);
- return {
- pools,
- total: result.total,
- page: result.page,
- pageSize: result.pageSize,
- };
- } catch (e) {
- logger.error('Error in fetch-pools:', e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Error processing the request');
- }
- },
+ const result = await meteora.fetchPoolsFromApi({
+ page,
+ limit,
+ query,
+ sortBy,
+ includeUnverified,
});
-};
-export default fetchPoolsRoute;
+ // Map the API response to the shared format
+ const pools = result.pools.map((pool: MeteoraApiPool) => ({
+ address: pool.address,
+ name: pool.name,
+ baseTokenAddress: pool.token_x.address,
+ baseTokenSymbol: pool.token_x.symbol,
+ quoteTokenAddress: pool.token_y.address,
+ quoteTokenSymbol: pool.token_y.symbol,
+ binStep: pool.pool_config.bin_step,
+ baseFee: pool.pool_config.base_fee_pct,
+ price: pool.current_price,
+ tvl: pool.tvl,
+ apr: pool.apr,
+ apy: pool.apy,
+ volume24h: pool.volume?.['24h'],
+ fees24h: pool.fees?.['24h'],
+ }));
+
+ return {
+ pools,
+ total: result.total,
+ page: result.page,
+ pageSize: result.pageSize,
+ };
+}
diff --git a/src/connectors/meteora/clmm-routes/index.ts b/src/connectors/meteora/clmm-routes/index.ts
deleted file mode 100644
index c05793c64b..0000000000
--- a/src/connectors/meteora/clmm-routes/index.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { addLiquidityRoute } from './addLiquidity';
-import { closePositionRoute } from './closePosition';
-import { collectFeesRoute } from './collectFees';
-import { createPoolRoute } from './createPool';
-import { executeSwapRoute } from './executeSwap';
-import { fetchPoolsRoute } from './fetchPools';
-import { openPositionRoute } from './openPosition';
-import { poolInfoRoute } from './poolInfo';
-import { positionInfoRoute } from './positionInfo';
-import { positionsOwnedRoute } from './positionsOwned';
-import { quotePositionRoute } from './quotePosition';
-import { quoteSwapRoute } from './quoteSwap';
-import { removeLiquidityRoute } from './removeLiquidity';
-
-export const meteoraClmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(fetchPoolsRoute);
- await fastify.register(createPoolRoute);
- await fastify.register(poolInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quotePositionRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(openPositionRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(collectFeesRoute);
- await fastify.register(closePositionRoute);
-};
-
-export default meteoraClmmRoutes;
diff --git a/src/connectors/meteora/clmm-routes/openPosition.ts b/src/connectors/meteora/clmm-routes/openPosition.ts
index d60340c678..c5e18f5311 100644
--- a/src/connectors/meteora/clmm-routes/openPosition.ts
+++ b/src/connectors/meteora/clmm-routes/openPosition.ts
@@ -1,17 +1,14 @@
import { DecimalUtil } from '@orca-so/common-sdk';
-import { Static } from '@sinclair/typebox';
import { Keypair, PublicKey } from '@solana/web3.js';
import { BN } from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { OpenPositionResponse, OpenPositionResponseType } from '../../../schemas/clmm-schema';
+import { OpenPositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraClmmOpenPositionRequest } from '../schemas';
// Using Fastify's native error handling
@@ -174,10 +171,9 @@ export async function openPosition(
]);
// Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -205,15 +201,15 @@ export async function openPosition(
let baseAmountAdded = Math.abs(balanceChanges[0]);
let quoteAmountAdded = Math.abs(balanceChanges[1]);
- // When SOL is base/quote, wallet balance change includes: liquidity + rent + fee
- // We need to subtract rent to get actual liquidity added
+ // When SOL is base/quote, the wallet paid liquidity + rent on that side, so back the
+ // rent out to leave the liquidity added. The transaction fee needs no correction:
+ // extractBalanceChangesAndFee nets it out for the fee payer and reports it separately,
+ // so subtracting it again would understate the amount by one fee.
if (tokenXSymbol === 'SOL') {
- // SOL is base token - subtract rent from balance change to get actual liquidity
- baseAmountAdded = baseAmountAdded - positionRent - txFee;
+ baseAmountAdded = baseAmountAdded - positionRent;
if (baseAmountAdded < 0) baseAmountAdded = 0;
} else if (tokenYSymbol === 'SOL') {
- // SOL is quote token - subtract rent from balance change to get actual liquidity
- quoteAmountAdded = quoteAmountAdded - positionRent - txFee;
+ quoteAmountAdded = quoteAmountAdded - positionRent;
if (quoteAmountAdded < 0) quoteAmountAdded = 0;
}
@@ -239,58 +235,3 @@ export async function openPosition(
};
}
}
-
-export const openPositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: OpenPositionResponseType;
- }>(
- '/open-position',
- {
- schema: {
- description: 'Open a new Meteora position',
- tags: ['/connector/meteora'],
- body: MeteoraClmmOpenPositionRequest,
- response: {
- 200: OpenPositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- strategyType,
- } = request.body;
- const networkToUse = network;
-
- return await openPosition(
- networkToUse,
- walletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- strategyType,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default openPositionRoute;
diff --git a/src/connectors/meteora/clmm-routes/poolInfo.ts b/src/connectors/meteora/clmm-routes/poolInfo.ts
index 2eb52ff1fb..b26675356b 100644
--- a/src/connectors/meteora/clmm-routes/poolInfo.ts
+++ b/src/connectors/meteora/clmm-routes/poolInfo.ts
@@ -1,9 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { MeteoraPoolInfo, MeteoraPoolInfoSchema, GetPoolInfoRequestType, PoolInfo } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { MeteoraPoolInfo, PoolInfo } from '../../../schemas/clmm-schema';
import { Meteora } from '../meteora';
-import { MeteoraClmmGetPoolInfoRequest } from '../schemas';
export async function getPoolInfo(
fastify: FastifyInstance,
@@ -27,37 +25,3 @@ export async function getPoolInfo(
return poolInfo;
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: MeteoraPoolInfo;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get pool information for a Meteora pool',
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmGetPoolInfoRequest,
- response: {
- 200: MeteoraPoolInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { poolAddress } = request.query;
- const network = request.query.network;
- return (await getPoolInfo(fastify, network, poolAddress)) as MeteoraPoolInfo;
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/meteora/clmm-routes/positionInfo.ts b/src/connectors/meteora/clmm-routes/positionInfo.ts
index 558bc7cde9..09f21fbd30 100644
--- a/src/connectors/meteora/clmm-routes/positionInfo.ts
+++ b/src/connectors/meteora/clmm-routes/positionInfo.ts
@@ -1,9 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PositionInfo, PositionInfoSchema, GetPositionInfoRequestType } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { Meteora } from '../meteora';
-import { MeteoraClmmGetPositionInfoRequest } from '../schemas';
export async function getPositionInfo(
fastify: FastifyInstance,
@@ -22,37 +20,3 @@ export async function getPositionInfo(
}
return positionInfo;
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get details for a specific Meteora position',
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { positionAddress } = request.query;
- const network = request.query.network;
- return await getPositionInfo(fastify, network, positionAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/meteora/clmm-routes/positionsOwned.ts b/src/connectors/meteora/clmm-routes/positionsOwned.ts
index 310b582686..5119bcc725 100644
--- a/src/connectors/meteora/clmm-routes/positionsOwned.ts
+++ b/src/connectors/meteora/clmm-routes/positionsOwned.ts
@@ -1,13 +1,11 @@
-import { Type } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PositionInfo, PositionInfoSchema } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
-import { MeteoraClmmGetPositionsOwnedRequest, MeteoraClmmGetPositionsOwnedRequestType } from '../schemas';
+
// Using Fastify's native error handling
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
export async function getPositionsOwned(
fastify: FastifyInstance,
@@ -40,40 +38,3 @@ async function fetchPositionsFromRPC(network: string, walletAddress: string): Pr
logger.info(`Found ${positions.length} Meteora position(s) for wallet ${walletAddress.slice(0, 8)}...`);
return positions;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: MeteoraClmmGetPositionsOwnedRequestType;
- Reply: PositionInfo[];
- }>(
- '/positions-owned',
- {
- schema: {
- description: "Retrieve all positions owned by a user's wallet across all Meteora pools",
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmGetPositionsOwnedRequest,
- response: {
- 200: Type.Array(PositionInfoSchema),
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress } = request.query;
- return await getPositionsOwned(fastify, network, walletAddress);
- } catch (e: any) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- // If it's an Error object with a message, use that message
- if (e.message) {
- throw fastify.httpErrors.serviceUnavailable(e.message);
- }
- throw fastify.httpErrors.internalServerError('Failed to fetch positions');
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/meteora/clmm-routes/quotePosition.ts b/src/connectors/meteora/clmm-routes/quotePosition.ts
index 4174701309..c78634110a 100644
--- a/src/connectors/meteora/clmm-routes/quotePosition.ts
+++ b/src/connectors/meteora/clmm-routes/quotePosition.ts
@@ -1,15 +1,31 @@
-import { StrategyType, getPriceOfBinByBinId } from '@meteora-ag/dlmm';
-import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
+import { BN } from '@coral-xyz/anchor';
+import { StrategyType, autoFillXByStrategy, autoFillYByStrategy } from '@meteora-ag/dlmm';
+import { DecimalUtil } from '@orca-so/common-sdk';
+import { Decimal } from 'decimal.js';
-import { Solana } from '../../../chains/solana/solana';
-import { QuotePositionResponseType, QuotePositionResponse } from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { QuotePositionResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraClmmQuotePositionRequest } from '../schemas';
+const toLamports = (amount: number, decimals: number): BN => new BN(DecimalUtil.toBN(new Decimal(amount), decimals));
+
+const fromLamports = (amount: BN, decimals: number): number => Number(amount.toString()) / Math.pow(10, decimals);
+
+/**
+ * Quote what a DLMM position of this shape would actually take.
+ *
+ * The paired amount comes from the SDK's autoFill helpers, which take the active bin,
+ * the bin step and the bin range and return what the strategy requires on the other
+ * side — the same math the open performs, so the quote describes the position the
+ * caller is about to create.
+ *
+ * It matters most for a range that does not straddle spot: such a position is entirely
+ * one-sided, and the unused side is 0. Pricing the paired amount off the range's
+ * midpoint instead — as this did — quoted a nonzero amount for a side the position
+ * cannot hold, and openPosition rejects exactly that, so following the quote produced
+ * a 400 from the open it fed.
+ */
export async function quotePosition(
network: string,
lowerPrice: number,
@@ -21,93 +37,87 @@ export async function quotePosition(
strategyType?: StrategyType,
): Promise {
try {
- const solana = await Solana.getInstance(network);
const meteora = await Meteora.getInstance(network);
-
- // Get DLMM pool instance
const dlmmPool = await meteora.getDlmmPool(poolAddress);
- // Get current bin information
- const activeBinId = dlmmPool.lbPair.activeId;
- const binStep = dlmmPool.lbPair.binStep;
+ const baseDecimals = dlmmPool.tokenX.mint.decimals;
+ const quoteDecimals = dlmmPool.tokenY.mint.decimals;
- // Calculate bin IDs from price range
- const lowerBinId = dlmmPool.getBinIdFromPrice(lowerPrice, false);
- const upperBinId = dlmmPool.getBinIdFromPrice(upperPrice, true);
+ // Derive the bin range exactly as openPosition does — per-lamport prices, and the
+ // rounding flags that way round. Passing raw prices with the flags swapped, as this
+ // did, described a different bin range than the position would occupy.
+ const lowerPricePerLamport = dlmmPool.toPricePerLamport(lowerPrice);
+ const upperPricePerLamport = dlmmPool.toPricePerLamport(upperPrice);
+ const minBinId = dlmmPool.getBinIdFromPrice(Number(lowerPricePerLamport), true);
+ const maxBinId = dlmmPool.getBinIdFromPrice(Number(upperPricePerLamport), false);
- // Use provided strategy type or default to Spot
- const strategy = {
- minBinId: Math.min(lowerBinId, upperBinId),
- maxBinId: Math.max(lowerBinId, upperBinId),
- strategyType: strategyType ?? StrategyType.Spot,
- };
+ const activeBin = await dlmmPool.getActiveBin();
+ const activeId = activeBin.binId;
+ const binStep = dlmmPool.lbPair.binStep;
+ const strategy = strategyType ?? MeteoraConfig.config.strategyType;
+ const amountXInActiveBin = new BN(activeBin.xAmount.toString());
+ const amountYInActiveBin = new BN(activeBin.yAmount.toString());
- // Get token amounts needed for the position
const slippage = slippagePct / 100;
- // Calculate liquidity distribution if amounts are provided
+ /** What the strategy needs on the quote side for a given base amount. */
+ const fillQuote = (base: number): number =>
+ fromLamports(
+ autoFillYByStrategy(
+ activeId,
+ binStep,
+ toLamports(base, baseDecimals),
+ amountXInActiveBin,
+ amountYInActiveBin,
+ minBinId,
+ maxBinId,
+ strategy,
+ ),
+ quoteDecimals,
+ );
+
+ /** What the strategy needs on the base side for a given quote amount. */
+ const fillBase = (quote: number): number =>
+ fromLamports(
+ autoFillXByStrategy(
+ activeId,
+ binStep,
+ toLamports(quote, quoteDecimals),
+ amountXInActiveBin,
+ amountYInActiveBin,
+ minBinId,
+ maxBinId,
+ strategy,
+ ),
+ baseDecimals,
+ );
+
let baseAmount = 0;
let quoteAmount = 0;
- let baseAmountMax = 0;
- let quoteAmountMax = 0;
let baseLimited = false;
- let liquidityValue = '0';
-
- if (baseTokenAmount || quoteTokenAmount) {
- // Get current price adjusted for decimals
- const rawPrice = getPriceOfBinByBinId(activeBinId, binStep).toNumber();
- const decimalDiff = dlmmPool.tokenX.mint.decimals - dlmmPool.tokenY.mint.decimals;
- const adjustmentFactor = Math.pow(10, decimalDiff);
- const currentPrice = rawPrice * adjustmentFactor;
- // Calculate amounts based on strategy
- if (baseTokenAmount && !quoteTokenAmount) {
- baseLimited = true;
+ if (baseTokenAmount && !quoteTokenAmount) {
+ baseLimited = true;
+ baseAmount = baseTokenAmount;
+ quoteAmount = fillQuote(baseTokenAmount);
+ } else if (quoteTokenAmount && !baseTokenAmount) {
+ baseLimited = false;
+ quoteAmount = quoteTokenAmount;
+ baseAmount = fillBase(quoteTokenAmount);
+ } else if (baseTokenAmount && quoteTokenAmount) {
+ // Ask what the offered base would require on the quote side. If that needs more
+ // quote than the caller has, the quote side binds; otherwise the base does. This
+ // asks the strategy rather than comparing a ratio against spot, which was wrong
+ // for any range not centred on the current price.
+ const quoteNeeded = fillQuote(baseTokenAmount);
+ baseLimited = quoteNeeded <= quoteTokenAmount;
+
+ if (baseLimited) {
baseAmount = baseTokenAmount;
- baseAmountMax = baseTokenAmount * (1 + slippage);
- // Estimate quote amount based on price range and strategy
- const avgPrice = (lowerPrice + upperPrice) / 2;
- quoteAmount = baseAmount * avgPrice;
- quoteAmountMax = quoteAmount * (1 + slippage);
- } else if (quoteTokenAmount && !baseTokenAmount) {
- baseLimited = false;
+ quoteAmount = quoteNeeded;
+ } else {
quoteAmount = quoteTokenAmount;
- quoteAmountMax = quoteTokenAmount * (1 + slippage);
- // Estimate base amount based on price range and strategy
- const avgPrice = (lowerPrice + upperPrice) / 2;
- baseAmount = quoteAmount / avgPrice;
- baseAmountMax = baseAmount * (1 + slippage);
- } else if (baseTokenAmount && quoteTokenAmount) {
- // Both amounts provided - use ratio to determine limiting token
- const providedRatio = quoteTokenAmount / baseTokenAmount;
- baseLimited = providedRatio > currentPrice;
-
- if (baseLimited) {
- baseAmount = baseTokenAmount;
- baseAmountMax = baseTokenAmount * (1 + slippage);
- quoteAmount = baseTokenAmount * currentPrice;
- quoteAmountMax = quoteAmount * (1 + slippage);
- } else {
- quoteAmount = quoteTokenAmount;
- quoteAmountMax = quoteTokenAmount * (1 + slippage);
- baseAmount = quoteTokenAmount / currentPrice;
- baseAmountMax = baseAmount * (1 + slippage);
- }
- }
-
- // Calculate liquidity estimate
- // For DLMM pools, liquidity is distributed across bins based on the strategy
- // We'll estimate it based on the token amounts in lamports
- try {
- const tokenXAmountLamports = baseAmount * Math.pow(10, dlmmPool.tokenX.mint.decimals);
- const tokenYAmountLamports = quoteAmount * Math.pow(10, dlmmPool.tokenY.mint.decimals);
-
- // For a balanced position, liquidity can be approximated as the geometric mean
- // This is a simplified estimate; actual distribution depends on bin strategy
- const estimatedLiquidity = Math.floor(Math.sqrt(tokenXAmountLamports * tokenYAmountLamports));
- liquidityValue = estimatedLiquidity.toString();
- } catch (error) {
- logger.warn('Failed to calculate liquidity estimate:', error);
+ baseAmount = fillBase(quoteTokenAmount);
}
}
@@ -115,64 +125,14 @@ export async function quotePosition(
baseLimited,
baseTokenAmount: baseAmount,
quoteTokenAmount: quoteAmount,
- baseTokenAmountMax: baseAmountMax,
- quoteTokenAmountMax: quoteAmountMax,
- liquidity: liquidityValue,
+ baseTokenAmountMax: baseAmount * (1 + slippage),
+ quoteTokenAmountMax: quoteAmount * (1 + slippage),
+ // No `liquidity`: the geometric mean this used to report collapses to 0 for any
+ // one-sided position, which is most of them. The field is optional in the schema
+ // and Orca already omits it.
};
} catch (error) {
logger.error(error);
throw error;
}
}
-
-export const quotePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: Static;
- Reply: QuotePositionResponseType;
- }>(
- '/quote-position',
- {
- schema: {
- description: 'Quote amounts for a new Meteora CLMM position',
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmQuotePositionRequest,
- response: {
- 200: QuotePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- strategyType,
- } = request.query;
-
- return await quotePosition(
- network,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- strategyType,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError('Failed to quote position');
- }
- },
- );
-};
-
-export default quotePositionRoute;
diff --git a/src/connectors/meteora/clmm-routes/quoteSwap.ts b/src/connectors/meteora/clmm-routes/quoteSwap.ts
index 1baabe6f3c..1fa85242fa 100644
--- a/src/connectors/meteora/clmm-routes/quoteSwap.ts
+++ b/src/connectors/meteora/clmm-routes/quoteSwap.ts
@@ -2,17 +2,12 @@ import { SwapQuoteExactOut, SwapQuote } from '@meteora-ag/dlmm';
import { DecimalUtil } from '@orca-so/common-sdk';
import { BN } from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
-import { estimateGasSolana } from '../../../chains/solana/routes/estimate-gas';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapResponseType, QuoteSwapResponse } from '../../../schemas/clmm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
-import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Meteora } from '../meteora';
import { MeteoraConfig } from '../meteora.config';
-import { MeteoraClmmQuoteSwapRequest, MeteoraClmmQuoteSwapRequestType } from '../schemas';
export async function getRawSwapQuote(
network: string,
@@ -92,6 +87,23 @@ async function formatSwapQuote(
throw httpErrors.notFound('Failed to get pool tokens');
}
+ // The spot price to measure the quote against, in the same orientation the response
+ // reports its price: quote per base, for the pair as the caller named it. A DLMM's
+ // active bin is priced tokenY per tokenX, so it inverts when the caller's base is Y.
+ const activeBin = await dlmmPool.getActiveBin();
+ const baseMint = side === 'SELL' ? inputToken.address : outputToken.address;
+ const pricePerToken = Number(activeBin?.pricePerToken ?? 0);
+ const spotPrice =
+ baseMint === dlmmPool.tokenX.publicKey.toBase58() ? pricePerToken : pricePerToken > 0 ? 1 / pricePerToken : 0;
+
+ // What the quote costs against that spot, as a percentage — the same measure Orca
+ // reports, and it includes the pool fee, since it is taken from the executed price
+ // rather than from depth alone. This route used to return a hardcoded 0, so a swap of
+ // any size through a Meteora pool claimed zero impact and a caller could not tell that
+ // from a real measurement.
+ const priceImpactFrom = (executionPrice: number): number =>
+ spotPrice > 0 ? Math.abs((executionPrice - spotPrice) / spotPrice) * 100 : 0;
+
if (side === 'BUY') {
const exactOutQuote = quote as SwapQuoteExactOut;
const estimatedAmountIn = DecimalUtil.fromBN(exactOutQuote.inAmount, inputToken.decimals).toNumber();
@@ -116,7 +128,7 @@ async function formatSwapQuote(
minAmountOut: amountOut,
maxAmountIn,
// CLMM-specific fields
- priceImpactPct: 0, // TODO: Calculate actual price impact
+ priceImpactPct: priceImpactFrom(price),
};
} else {
const exactInQuote = quote as SwapQuote;
@@ -127,9 +139,6 @@ async function formatSwapQuote(
// For sell orders:
// - Base token (input) decreases (negative)
// - Quote token (output) increases (positive)
- const baseTokenChange = -estimatedAmountIn;
- const quoteTokenChange = estimatedAmountOut;
-
const price = estimatedAmountOut / estimatedAmountIn;
return {
@@ -144,105 +153,11 @@ async function formatSwapQuote(
minAmountOut,
maxAmountIn: estimatedAmountIn,
// CLMM-specific fields
- priceImpactPct: 0, // TODO: Calculate actual price impact
+ priceImpactPct: priceImpactFrom(price),
};
}
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: MeteoraClmmQuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Meteora CLMM',
- tags: ['/connector/meteora'],
- querystring: MeteoraClmmQuoteSwapRequest,
- response: {
- 200: QuoteSwapResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, poolAddress, slippagePct } = request.query;
- const networkUsed = network;
-
- // Validate essential parameters
- if (!baseToken || !quoteToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, quoteToken, amount, and side are required');
- }
-
- const solana = await Solana.getInstance(networkUsed);
-
- let poolAddressToUse = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressToUse) {
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'meteora',
- networkUsed,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Meteora`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- const result = await formatSwapQuote(
- networkUsed,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- poolAddressToUse,
- slippagePct,
- );
-
- try {
- // Note: estimateGasSolana returns feePerComputeUnit, not gasLimit
- await estimateGasSolana(networkUsed);
- } catch (error) {
- logger.warn(`Failed to estimate gas for swap quote: ${error.message}`);
- }
-
- return result;
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Resolves the counter ("quote") token for a DLMM pool given the base token. The standardized swap
* wrappers take poolAddress + baseToken and derive the other side from the pool (tokenX/tokenY),
diff --git a/src/connectors/meteora/clmm-routes/removeLiquidity.ts b/src/connectors/meteora/clmm-routes/removeLiquidity.ts
index 38bee36e56..23dc1db643 100644
--- a/src/connectors/meteora/clmm-routes/removeLiquidity.ts
+++ b/src/connectors/meteora/clmm-routes/removeLiquidity.ts
@@ -1,21 +1,13 @@
import { BN } from '@coral-xyz/anchor';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import {
- RemoveLiquidityResponse,
- RemoveLiquidityRequestType,
- RemoveLiquidityResponseType,
-} from '../../../schemas/clmm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Meteora } from '../meteora';
-import { MeteoraClmmRemoveLiquidityRequest } from '../schemas';
// Using centralized error handling
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
export async function removeLiquidity(
network: string,
@@ -97,10 +89,9 @@ export async function removeLiquidity(
const fee = totalFee;
// Get transaction data for confirmation
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
@@ -131,6 +122,10 @@ export async function removeLiquidity(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: info.publicKey.toBase58(),
fee,
baseTokenAmountRemoved: tokenXRemovedAmount,
quoteTokenAmountRemoved: tokenYRemovedAmount,
@@ -143,41 +138,3 @@ export async function removeLiquidity(
};
}
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a Meteora position',
- tags: ['/connector/meteora'],
- body: MeteoraClmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress, liquidityPct } = request.body;
-
- const networkToUse = network;
-
- return await removeLiquidity(networkToUse, walletAddress, positionAddress, liquidityPct);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/meteora/meteora.routes.ts b/src/connectors/meteora/meteora.routes.ts
deleted file mode 100644
index 5c7ca802e4..0000000000
--- a/src/connectors/meteora/meteora.routes.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { meteoraAmmRoutes } from './amm-routes';
-import { meteoraClmmRoutes } from './clmm-routes';
-
-// CLMM routes including swap endpoints
-const meteoraClmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/meteora'];
- }
- });
-
- await instance.register(meteoraClmmRoutes);
- });
-};
-
-// AMM routes (DAMM v2 / cp-amm), including swap endpoints
-const meteoraAmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/meteora'];
- }
- });
-
- await instance.register(meteoraAmmRoutes);
- });
-};
-
-// Export the CLMM and AMM routes
-export const meteoraRoutes = {
- clmm: meteoraClmmRoutesWrapper,
- amm: meteoraAmmRoutesWrapper,
-};
-
-export default meteoraRoutes;
diff --git a/src/connectors/meteora/meteora.ts b/src/connectors/meteora/meteora.ts
index a346c12c4f..5a19cdb9e4 100644
--- a/src/connectors/meteora/meteora.ts
+++ b/src/connectors/meteora/meteora.ts
@@ -1,6 +1,5 @@
-import DLMM, { getPriceOfBinByBinId, LbPair, LBCLMM_PROGRAM_IDS } from '@meteora-ag/dlmm';
-import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
-import { PublicKey, MemcmpFilter } from '@solana/web3.js';
+import DLMM, { getPriceOfBinByBinId, LbPair } from '@meteora-ag/dlmm';
+import { PublicKey } from '@solana/web3.js';
import { Solana } from '../../chains/solana/solana';
import { MeteoraPoolInfo, PositionInfo, BinLiquidity } from '../../schemas/clmm-schema';
diff --git a/src/connectors/meteora/meteora.utils.ts b/src/connectors/meteora/meteora.utils.ts
index 6b9c5694f7..795ffc4298 100644
--- a/src/connectors/meteora/meteora.utils.ts
+++ b/src/connectors/meteora/meteora.utils.ts
@@ -1,5 +1,3 @@
-import { MeteoraConfig } from './meteora.config';
-
/**
* Find a pool address for a token pair in the configured pools
*
diff --git a/src/connectors/meteora/schemas.ts b/src/connectors/meteora/schemas.ts
deleted file mode 100644
index 14d0d2ebb0..0000000000
--- a/src/connectors/meteora/schemas.ts
+++ /dev/null
@@ -1,844 +0,0 @@
-import { StrategyType } from '@meteora-ag/dlmm';
-import { Type, Static } from '@sinclair/typebox';
-
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { MeteoraConfig } from './meteora.config';
-
-// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
-
-// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.01;
-const BASE_TOKEN_AMOUNT = 0.01;
-const QUOTE_TOKEN_AMOUNT = 2;
-const LOWER_PRICE_BOUND = 150;
-const UPPER_PRICE_BOUND = 250;
-const CLMM_POOL_ADDRESS_EXAMPLE = '2sf5NYcY4zUPXUSmG6f66mskb24t5F8S11pC1Nz5nQT3';
-
-// Meteora Router-specific extensions for quote-swap
-export const MeteoraQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
- poolAddress: Type.Optional(Type.String()),
-});
-
-// Meteora Router-specific extensions for quote-swap response
-export const MeteoraQuoteSwapResponse = Type.Object({
- baseTokenAmount: Type.Number(),
- quoteTokenAmount: Type.Number(),
- exchangeRate: Type.Number(),
- priceImpactPct: Type.Number(),
- poolAddress: Type.String(),
- fee: Type.Number(),
- gasEstimate: Type.String(),
- computeUnits: Type.Number(),
-});
-
-// Meteora CLMM-specific extensions
-export const MeteoraClmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Meteora DLMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair (optional - required if poolAddress not provided)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-// Export the type for QuoteSwapRequest
-export type MeteoraClmmQuoteSwapRequestType = Static;
-
-export const MeteoraClmmExecuteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Meteora DLMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address (optional - required if poolAddress not provided)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-// Export the type for ExecuteSwapRequest
-export type MeteoraClmmExecuteSwapRequestType = Static;
-
-// Meteora CLMM Open Position Request
-export const MeteoraClmmOpenPositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will open the position',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Meteora DLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
- strategyType: Type.Optional(
- Type.Number({
- description: 'Strategy type for the position',
- examples: [StrategyType.Spot],
- enum: Object.values(StrategyType).filter((x) => typeof x === 'number'),
- }),
- ),
-});
-
-// Meteora CLMM Add Liquidity Request
-export const MeteoraClmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will add liquidity',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
- strategyType: Type.Optional(
- Type.Number({
- description: 'Strategy type for the position',
- examples: [StrategyType.Spot],
- enum: Object.values(StrategyType).filter((x) => typeof x === 'number'),
- }),
- ),
-});
-
-// Meteora CLMM Remove Liquidity Request
-export const MeteoraClmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will remove liquidity',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- liquidityPct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- default: 100,
- examples: [100],
- }),
- ),
-});
-
-// Meteora CLMM Close Position Request
-export const MeteoraClmmClosePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will close the position',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
-});
-
-// Meteora CLMM Collect Fees Request
-export const MeteoraClmmCollectFeesRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will collect fees',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
-});
-
-// Meteora CLMM Fetch Pools Request
-export const MeteoraClmmFetchPoolsRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- page: Type.Optional(
- Type.Number({
- minimum: 0,
- default: 0,
- description: 'Page number (0-based)',
- examples: [0],
- }),
- ),
- limit: Type.Optional(
- Type.Number({
- minimum: 1,
- maximum: 1000,
- default: 50,
- description: 'Maximum number of pools to return (max 1000)',
- examples: [50],
- }),
- ),
- query: Type.Optional(
- Type.String({
- description: 'Search query to match pools by name, tokens, or address',
- examples: ['SOL', 'USDC', 'SOL-USDC'],
- }),
- ),
- sortBy: Type.Optional(
- Type.String({
- description: 'Sort by field (volume, fees, tvl, apr) with optional time window',
- default: 'volume_24h:desc',
- examples: ['volume_24h:desc', 'tvl:desc', 'apr:desc'],
- }),
- ),
- includeUnverified: Type.Optional(
- Type.Boolean({
- description: 'Include pools with unverified tokens',
- default: true,
- }),
- ),
-});
-
-// Meteora CLMM Get Pool Info Request
-export const MeteoraClmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-// Meteora CLMM Get Position Info Request
-export const MeteoraClmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
-});
-
-// Meteora CLMM Get Positions Owned Request
-export const MeteoraClmmGetPositionsOwnedRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.String({
- description: 'Solana wallet address to check for positions',
- examples: [solanaChainConfig.defaultWallet],
- }),
-});
-
-export type MeteoraClmmGetPositionsOwnedRequestType = Static;
-
-// Meteora CLMM Quote Position Request
-export const MeteoraClmmQuotePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Meteora DLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
- strategyType: Type.Optional(
- Type.Number({
- description: 'Strategy type for the position',
- examples: [StrategyType.Spot],
- enum: Object.values(StrategyType).filter((x) => typeof x === 'number'),
- }),
- ),
-});
-
-// Meteora CLMM Create Pool Request
-export const MeteoraClmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create the pool',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- initialPrice: Type.Number({
- description: 'Initial price as quote per base (e.g. USDC per SOL). Encodes the pool active bin.',
- examples: [UPPER_PRICE_BOUND],
- }),
- binStep: Type.Number({
- description:
- 'Bin step in basis points (e.g. 1, 2, 4, 5, 10, 20, 25, 50, 100). Sets pool granularity; ' +
- 'cannot be changed after creation.',
- examples: [20],
- }),
- feeBps: Type.Number({
- description: 'Base swap fee in basis points (e.g. 20 = 0.20%). Must be compatible with binStep.',
- examples: [20],
- }),
-});
-
-// ========================================
-// DAMM v2 (AMM) Request Schemas
-// ========================================
-
-const DAMM_V2_POOL_ADDRESS_EXAMPLE = 'FH6mP2MUobhDnLERp9z5yv5t2zMUA9WDNXPixpbvYKMv';
-
-export const MeteoraAmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-export const MeteoraAmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
-});
-
-export const MeteoraAmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair (optional - resolved from the pool if omitted)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap (denominated in the base token)',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-export const MeteoraAmmExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair (optional - resolved from the pool if omitted)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap (denominated in the base token)',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-export const MeteoraAmmQuoteLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-export const MeteoraAmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- positionAddress: Type.Optional(
- Type.String({
- description:
- 'DAMM v2 positions are NFTs; a wallet may hold several per pool. Provide a position address ' +
- '(from position-info) to add to that specific position; omit to open a NEW position NFT.',
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: MeteoraConfig.config.slippagePct,
- examples: [MeteoraConfig.config.slippagePct],
- }),
- ),
-});
-
-export const MeteoraAmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Meteora DAMM v2 pool address',
- examples: [DAMM_V2_POOL_ADDRESS_EXAMPLE],
- }),
- positionAddress: Type.String({
- description:
- 'Address of the specific DAMM v2 position (NFT) to remove from. Required — a wallet may hold ' +
- 'several positions per pool; list them with position-info. This avoids silently draining only ' +
- 'the largest position when several exist.',
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of this position’s liquidity to remove',
- examples: [100],
- }),
-});
-
-export const MeteoraAmmGetPositionsOwnedRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.String({
- description: 'Solana wallet address to list DAMM v2 positions for',
- examples: [solanaChainConfig.defaultWallet],
- }),
-});
-export type MeteoraAmmGetPositionsOwnedRequestType = Static;
-
-export const MeteoraAmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...MeteoraConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create and seed the pool',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes pool token A)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes pool token B)',
- examples: [QUOTE_TOKEN],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to seed the pool with',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description:
- 'Amount of quote token to seed with. If provided, the base:quote ratio sets the initial price. ' +
- 'If omitted (and no initialPrice), the current market price is fetched from the swap router.',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base (e.g. SOL per UMBRA). Overrides quoteTokenAmount. ' +
- 'If both are omitted, the pool is seeded at the current market price so it is not immediately arbitraged.',
- }),
- ),
- configAddress: Type.Optional(
- Type.String({
- description:
- 'DAMM v2 config account that defines the fee tier and pool parameters. Required — many permissionless ' +
- 'configs are launch configs with very high starting fees, so Gateway does not auto-select one.',
- }),
- ),
-});
diff --git a/src/connectors/okx/README.md b/src/connectors/okx/README.md
index 2f8f674170..bb620a2da4 100644
--- a/src/connectors/okx/README.md
+++ b/src/connectors/okx/README.md
@@ -1,28 +1,31 @@
# OKX DEX Aggregator Router Connector
The [OKX DEX aggregator](https://web3.okx.com/dex-swap) (part of OKX OnchainOS) routes swaps
-across Solana DEX liquidity. This connector exposes it through Gateway's standard router
-endpoints:
+across Solana DEX liquidity. Like every router connector it is reached through the unified
+trading routes, naming `okx` as the `connector`:
-- `GET /connectors/okx/router/quote-swap`
-- `POST /connectors/okx/router/execute-quote`
-- `POST /connectors/okx/router/execute-swap`
+- `GET /trading/router/quote-swap`
+- `POST /trading/router/execute-quote`
+- `POST /trading/router/execute-swap`
Network support: `mainnet-beta` only (OKX `chainIndex` 501).
## Getting API credentials
OKX requires **three credentials** — an API key, a secret key, and a passphrase — used to
-HMAC-sign every request. All three are created in the OKX developer portal:
+HMAC-sign every request. Creating them is self-serve and free; only email and phone
+verification are needed to start.
1. Create an OKX account and sign in to the developer portal:
https://web3.okx.com/build/dev-portal
-2. Create a **project** (up to three projects per account).
-3. In the project, open the **API keys** page and click **Create API key** (up to three keys
+2. Verify email and phone. That alone puts the account on the **Trial** tier.
+3. Create a **project** (up to three projects per account).
+4. In the project, open the **API keys** page and click **Create API key** (up to three keys
per project). Enter a name and choose a **passphrase**.
-4. Save all three values — the **API key**, the system-generated **secret key**, and your
- **passphrase**. OKX cannot recover the passphrase; without it the key is unusable.
-5. Add them to `conf/connectors/okx.yml`:
+5. Save all three values — the **API key**, the system-generated **secret key** (shown only
+ at creation), and your **passphrase**. OKX cannot recover the passphrase; without it the
+ key is unusable.
+6. Add them to `conf/connectors/okx.yml`:
```yaml
apiKey: 'your-okx-api-key'
@@ -34,6 +37,21 @@ The connector fails fast with a clear error if any of the three is missing. Trea
credentials: keep them out of version control (`conf/` is gitignored) and rotate them if
exposed.
+### What a Trial key can actually do
+
+The trial is **60 days at 1 request/second**, raisable to 5 RPS on review. That ceiling,
+not the expiry, is what usually bites: a bot sweeping quotes across several connectors
+exceeds 1 RPS on its own. Continuing past 60 days means completing KYC in the developer
+portal to reach the **Start-up** tier, which is where usable rate limits are. Start-up has
+no per-call charge, but partners who take a fee on swaps enter a revenue-share where OKX
+retains 20% of it.
+
+Worth knowing before spending time on a 401: OKX's own client library sends a fifth header,
+`OK-ACCESS-PROJECT`, carrying the project ID. This connector does not, and has no config
+field for one — that library targets the v5 API, while this connector calls v6, whose quote
+reference lists only the four headers below. If signed requests are rejected once
+credentials are populated, add the project ID before investigating anything else.
+
## How requests are signed
Every request sends the headers `OK-ACCESS-KEY`, `OK-ACCESS-PASSPHRASE`,
@@ -69,5 +87,7 @@ the request path (see `okx.ts:signedHeaders`).
- DEX API reference: https://web3.okx.com/onchainos/dev-docs/trade/dex-api-reference
- Developer portal guide: https://web3.okx.com/onchainos/dev-docs/home/developer-portal
+- Authentication: https://web3.okx.com/onchainos/dev-docs/home/api-access-and-usage
+- Tiers and fees: https://web3.okx.com/build/dev-docs/dex-api/dex-api-fee
- Quote endpoint: https://web3.okx.com/build/dev-docs/wallet-api/dex-get-quote
- Swap endpoint: https://web3.okx.com/build/dev-docs/wallet-api/dex-swap
diff --git a/src/connectors/okx/okx.routes.ts b/src/connectors/okx/okx.routes.ts
deleted file mode 100644
index d0a2a8bbe4..0000000000
--- a/src/connectors/okx/okx.routes.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { okxRouterRoutes } from './router-routes';
-
-// OKX routes with 3 endpoints
-const okxRouterRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- // Decorate the instance with a hook to modify route options
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/okx'];
- }
- });
-
- await instance.register(okxRouterRoutes);
- });
-};
-
-// Export routes in the same pattern as Jupiter
-export const okxRoutes = {
- router: okxRouterRoutesWrapper,
-};
diff --git a/src/connectors/okx/okx.ts b/src/connectors/okx/okx.ts
index b29983c0df..ce044ff35c 100644
--- a/src/connectors/okx/okx.ts
+++ b/src/connectors/okx/okx.ts
@@ -4,6 +4,7 @@ import { VersionedTransaction } from '@solana/web3.js';
import bs58 from 'bs58';
import { Solana } from '../../chains/solana/solana';
+import { httpErrors } from '../../services/error-handler';
import { createHttpClient, HttpClient, HttpClientError } from '../../services/http-client';
import { logger } from '../../services/logger';
@@ -54,7 +55,11 @@ export class Okx {
this.solana = null;
if (!this.config.apiKey || !this.config.secretKey || !this.config.passphrase) {
- throw new Error(
+ // A missing credential is a configuration gap, not a Gateway fault. Thrown as a
+ // plain Error it reached callers as a 500, which reads as "retry later" for a
+ // condition no retry can fix — and OKX is advertised in /config/connectors, so
+ // anything enumerating providers hits it.
+ throw httpErrors.badRequest(
'OKX DEX API credentials are not configured. Set okx.apiKey, okx.secretKey and okx.passphrase ' +
'in conf/connectors/okx.yml (create them at https://web3.okx.com/build/dev-portal).',
);
diff --git a/src/connectors/okx/router-routes/executeQuote.ts b/src/connectors/okx/router-routes/executeQuote.ts
index a99b018951..603a9ad01e 100644
--- a/src/connectors/okx/router-routes/executeQuote.ts
+++ b/src/connectors/okx/router-routes/executeQuote.ts
@@ -1,12 +1,9 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { Okx } from '../okx';
-import { OkxExecuteQuoteRequest } from '../schemas';
export async function executeQuote(
walletAddress: string,
@@ -41,18 +38,18 @@ export async function executeQuote(
);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
+ undefined,
+ slippagePct,
);
// Remove quote from cache only after successful execution (confirmed)
@@ -65,33 +62,3 @@ export async function executeQuote(
return result as SwapExecuteResponseType;
}
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from the OKX DEX aggregator',
- tags: ['/connector/okx'],
- body: OkxExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, quoteId } = request.body as typeof OkxExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing OKX quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/okx/router-routes/executeSwap.ts b/src/connectors/okx/router-routes/executeSwap.ts
index 672a8c2183..b7632b9f0c 100644
--- a/src/connectors/okx/router-routes/executeSwap.ts
+++ b/src/connectors/okx/router-routes/executeSwap.ts
@@ -1,10 +1,5 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { OkxConfig } from '../okx.config';
-import { OkxExecuteSwapRequest } from '../schemas';
import { executeQuote } from './executeQuote';
import { quoteSwap } from './quoteSwap';
@@ -35,43 +30,3 @@ async function executeSwap(
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on the OKX DEX aggregator in one step',
- tags: ['/connector/okx'],
- body: OkxExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut } =
- request.body as typeof OkxExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing OKX swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/okx/router-routes/index.ts b/src/connectors/okx/router-routes/index.ts
deleted file mode 100644
index b3acb8e18c..0000000000
--- a/src/connectors/okx/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const okxRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default okxRouterRoutes;
diff --git a/src/connectors/okx/router-routes/quoteSwap.ts b/src/connectors/okx/router-routes/quoteSwap.ts
index e68860be1d..1d896d8470 100644
--- a/src/connectors/okx/router-routes/quoteSwap.ts
+++ b/src/connectors/okx/router-routes/quoteSwap.ts
@@ -1,18 +1,15 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage, sanitizeString } from '../../../services/sanitize';
-import { approximateBuyViaSellLeg } from '../../router-utils';
+import { approximateBuyViaSellLeg, attemptedRoute } from '../../router-utils';
import { Okx, OkxRouterResult } from '../okx';
import { OkxConfig } from '../okx.config';
-import { OkxQuoteSwapRequest, OkxQuoteSwapResponse } from '../schemas';
-
+import { OkxQuoteSwapResponse } from '../schemas';
function priceImpactPct(routerResult: OkxRouterResult): number {
return parseFloat(routerResult.priceImpactPercent ?? routerResult.priceImpactPercentage ?? '0');
}
@@ -74,8 +71,8 @@ export async function quoteSwap(
executableSwapMode = 'exactIn';
isApproximation = true;
} else {
- const tokenPair = `${sanitizeString(baseToken)} -> ${sanitizeString(quoteToken)}`;
- throw httpErrors.noRouteFound(`No route found for ${tokenPair} (${executableSwapMode}). ${errorMessage}`);
+ const route = attemptedRoute(side, sanitizeString(baseToken), sanitizeString(quoteToken), executableSwapMode);
+ throw httpErrors.noRouteFound(`No route found for ${route}. ${errorMessage}`);
}
}
@@ -128,42 +125,3 @@ export async function quoteSwap(
routerResult,
};
}
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get an executable swap quote from the OKX DEX aggregator',
- tags: ['/connector/okx'],
- querystring: OkxQuoteSwapRequest,
- response: { 200: OkxQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut } =
- request.query as typeof OkxQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error getting OKX quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/okx/schemas.ts b/src/connectors/okx/schemas.ts
index 7347033f39..2cb82f64a2 100644
--- a/src/connectors/okx/schemas.ts
+++ b/src/connectors/okx/schemas.ts
@@ -1,60 +1,8 @@
import { Type } from '@sinclair/typebox';
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { OkxConfig } from './okx.config';
-
// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.1;
-
-// OKX-specific quote-swap request (superset of base QuoteSwapRequest)
-export const OkxQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OkxConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OkxConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders when OKX cannot serve an exactOut quote: approximate via a sell-leg exactIn quote instead of failing',
- default: true,
- }),
- ),
-});
// OKX-specific quote-swap response (superset of base QuoteSwapResponse)
export const OkxQuoteSwapResponse = Type.Object({
@@ -95,74 +43,3 @@ export const OkxQuoteSwapResponse = Type.Object({
description: "OKX's native quote result (amounts, price impact, routing breakdown)",
}),
});
-
-// OKX-specific execute-quote request (superset of base ExecuteQuoteRequest)
-export const OkxExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OkxConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the OKX quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
-});
-
-// OKX-specific execute-swap request (superset of base ExecuteSwapRequest)
-export const OkxExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OkxConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OkxConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders when OKX cannot serve an exactOut quote: approximate via a sell-leg exactIn quote instead of failing',
- default: true,
- }),
- ),
-});
diff --git a/src/connectors/orca/clmm-routes/addLiquidity.ts b/src/connectors/orca/clmm-routes/addLiquidity.ts
index 24b388b11e..3050757ad1 100644
--- a/src/connectors/orca/clmm-routes/addLiquidity.ts
+++ b/src/connectors/orca/clmm-routes/addLiquidity.ts
@@ -5,20 +5,18 @@ import {
increaseLiquidityQuoteB,
type IncreaseLiquidityQuote,
} from '@orca-so/whirlpools-core';
-import { Static } from '@sinclair/typebox';
import { address } from '@solana/kit';
import { PublicKey } from '@solana/web3.js';
import { fetchAllMint } from '@solana-program/token-2022';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { AddLiquidityResponse, AddLiquidityResponseType } from '../../../schemas/clmm-schema';
+import { AddLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { getCurrentTransferFee } from '../orca.position';
import { buildOrcaTransaction, createOrcaAuthority } from '../orca.sdk';
-import { OrcaClmmAddLiquidityRequest } from '../schemas';
export async function addLiquidity(
network: string,
@@ -26,7 +24,7 @@ export async function addLiquidity(
positionAddress: string,
baseTokenAmount: number,
quoteTokenAmount: number,
- slippagePct: number,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
): Promise {
if ((!baseTokenAmount || baseTokenAmount <= 0) && (!quoteTokenAmount || quoteTokenAmount <= 0)) {
throw httpErrors.badRequest('At least one token amount must be provided and greater than 0');
@@ -100,7 +98,12 @@ export async function addLiquidity(
const result = await increaseLiquidityInstructions(
orca.solanaKitRpc,
position.data.positionMint,
- { tokenMaxA: quote.tokenMaxA, tokenMaxB: quote.tokenMaxB },
+ // The estimates, not the quote's ceilings — the same correction as openPosition.
+ // increaseLiquidityQuote* already applied slippageBps to produce tokenMax*, and this
+ // builder applies slippageToleranceBps again to derive the on-chain maximums, so
+ // passing tokenMax* deposits slippagePct more than was asked for. The log line above
+ // has always reported tokenEst*, which is what the transaction should be spending.
+ { tokenMaxA: quote.tokenEstA, tokenMaxB: quote.tokenEstB },
{
authority: createOrcaAuthority(walletAddress),
slippageToleranceBps: slippageBps,
@@ -128,52 +131,13 @@ export async function addLiquidity(
signature,
status: 1,
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.data.whirlpool.toString(),
fee,
baseTokenAmountAdded: Math.abs(balanceChanges[0]),
quoteTokenAmountAdded: Math.abs(balanceChanges[1]),
},
};
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to an Orca position',
- tags: ['/connector/orca'],
- body: OrcaClmmAddLiquidityRequest,
- response: { 200: AddLiquidityResponse },
- },
- },
- async (request) => {
- try {
- const {
- walletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct = 1,
- network,
- } = request.body;
- return await addLiquidity(
- network,
- walletAddress,
- positionAddress,
- baseTokenAmount || 0,
- quoteTokenAmount || 0,
- slippagePct,
- );
- } catch (error) {
- logger.error(error);
- if (error.statusCode) throw error;
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/orca/clmm-routes/closePosition.ts b/src/connectors/orca/clmm-routes/closePosition.ts
index 17cb745e6e..2e84266c53 100644
--- a/src/connectors/orca/clmm-routes/closePosition.ts
+++ b/src/connectors/orca/clmm-routes/closePosition.ts
@@ -1,25 +1,23 @@
import { closePositionInstructions } from '@orca-so/whirlpools';
import { fetchMaybePosition, fetchWhirlpool } from '@orca-so/whirlpools-client';
-import { Static } from '@sinclair/typebox';
import { address } from '@solana/kit';
import { getAssociatedTokenAddressSync } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
import { fetchMint } from '@solana-program/token-2022';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ClosePositionResponse, ClosePositionResponseType } from '../../../schemas/clmm-schema';
+import { ClosePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
import { buildOrcaTransaction, createOrcaAuthority } from '../orca.sdk';
import { extractInnerTransferAmounts } from '../orca.utils';
-import { OrcaClmmClosePositionRequest } from '../schemas';
export async function closePosition(
network: string,
walletAddress: string,
positionAddress: string,
+ slippagePct?: number,
): Promise {
const solana = await Solana.getInstance(network);
const orca = await Orca.getInstance(network);
@@ -45,7 +43,10 @@ export async function closePosition(
// and destination account setup/cleanup. Gateway remains the only signer.
const closeResult = await closePositionInstructions(orca.solanaKitRpc, position.data.positionMint, {
authority: createOrcaAuthority(walletAddress),
- slippageToleranceBps: Math.round(orca.config.slippagePct * 100),
+ // The caller's tolerance when they set one — an executor widening across retries is
+ // the case this exists for; a narrow in-range close can fail on slippage at the
+ // connector's configured value with no way to say "accept more to get out".
+ slippageToleranceBps: Math.round((slippagePct ?? orca.config.slippagePct) * 100),
whirlpoolDeployment: orca.deployment,
});
const rewardCount = closeResult.rewardsQuote.rewards.filter((reward) => reward.rewardsOwed > 0n).length;
@@ -54,10 +55,9 @@ export async function closePosition(
const transaction = buildOrcaTransaction(closeResult.instructions, walletAddress);
const { signature, fee } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
let positionRentRefunded = 0;
if (txData) {
@@ -113,6 +113,10 @@ export async function closePosition(
signature,
status: 1,
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.data.whirlpool.toString(),
fee,
positionRentRefunded,
baseTokenAmountRemoved,
@@ -122,34 +126,3 @@ export async function closePosition(
},
};
}
-
-export const closePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: ClosePositionResponseType;
- }>(
- '/close-position',
- {
- schema: {
- description: 'Close an Orca position',
- tags: ['/connector/orca'],
- body: OrcaClmmClosePositionRequest,
- response: {
- 200: ClosePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { walletAddress, positionAddress, network } = request.body;
- return await closePosition(network, walletAddress, positionAddress);
- } catch (error) {
- logger.error(error);
- if (error.statusCode) throw error;
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default closePositionRoute;
diff --git a/src/connectors/orca/clmm-routes/collectFees.ts b/src/connectors/orca/clmm-routes/collectFees.ts
index 68d7809cea..02f9ce01d6 100644
--- a/src/connectors/orca/clmm-routes/collectFees.ts
+++ b/src/connectors/orca/clmm-routes/collectFees.ts
@@ -1,17 +1,13 @@
import { harvestPositionInstructions } from '@orca-so/whirlpools';
import { fetchPosition, fetchWhirlpool } from '@orca-so/whirlpools-client';
-import { Static } from '@sinclair/typebox';
import { address } from '@solana/kit';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CollectFeesResponse, CollectFeesResponseType } from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { CollectFeesResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
import { buildOrcaTransaction, createOrcaAuthority } from '../orca.sdk';
-import { OrcaClmmCollectFeesRequest } from '../schemas';
export async function collectFees(
network: string,
@@ -53,38 +49,13 @@ export async function collectFees(
signature,
status: 1,
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.data.whirlpool.toString(),
fee,
baseFeeAmountCollected: Math.abs(balanceChanges[0]),
quoteFeeAmountCollected: Math.abs(balanceChanges[1]),
},
};
}
-
-export const collectFeesRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CollectFeesResponseType;
- }>(
- '/collect-fees',
- {
- schema: {
- description: 'Collect fees and rewards from an Orca position',
- tags: ['/connector/orca'],
- body: OrcaClmmCollectFeesRequest,
- response: { 200: CollectFeesResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, positionAddress, network } = request.body;
- return await collectFees(network, walletAddress, positionAddress);
- } catch (error) {
- logger.error(error);
- if (error.statusCode) throw error;
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default collectFeesRoute;
diff --git a/src/connectors/orca/clmm-routes/createPool.ts b/src/connectors/orca/clmm-routes/createPool.ts
index e2a06b0338..3d33e345c1 100644
--- a/src/connectors/orca/clmm-routes/createPool.ts
+++ b/src/connectors/orca/clmm-routes/createPool.ts
@@ -1,17 +1,14 @@
import { createConcentratedLiquidityPoolInstructions, orderMints } from '@orca-so/whirlpools';
-import { Static } from '@sinclair/typebox';
import { address, type Instruction } from '@solana/kit';
import { Keypair, PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Orca } from '../orca';
import { buildOrcaTransaction, createOrcaAuthority, replaceOrcaInstructionAccounts } from '../orca.sdk';
-import { OrcaClmmCreatePoolRequest } from '../schemas';
/** Resolves a token symbol or mint address to a PublicKey. */
async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
@@ -31,11 +28,11 @@ async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
// Probe with 1 base token — we only need the price ratio, not a real trade size.
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to initialize the pool (${e.message}). ` +
@@ -144,10 +141,9 @@ export async function createPool(
const transaction = buildOrcaTransaction(instructions, walletAddress);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress, extraSigners);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
return {
@@ -157,43 +153,8 @@ export async function createPool(
price: seedPrice,
data: {
fee: txData.meta.fee / 1e9,
- // Pool created + initialized only — no liquidity/position seeded.
- baseTokenAmountAdded: 0,
- quoteTokenAmountAdded: 0,
},
};
}
return { signature, status: 0, poolAddress, price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description:
- 'Create and initialize a new Orca (Whirlpools) CLMM pool at an initial price. Does not open or seed a position.',
- tags: ['/connector/orca'],
- body: OrcaClmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, initialPrice, tickSpacing } = request.body;
- return await createPool(network, walletAddress, baseToken, quoteToken, initialPrice, tickSpacing);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/orca/clmm-routes/executeSwap.ts b/src/connectors/orca/clmm-routes/executeSwap.ts
index 970f2c64e1..326112c7be 100644
--- a/src/connectors/orca/clmm-routes/executeSwap.ts
+++ b/src/connectors/orca/clmm-routes/executeSwap.ts
@@ -2,21 +2,17 @@ import { swapInstructions } from '@orca-so/whirlpools';
import { fetchWhirlpool } from '@orca-so/whirlpools-client';
import { address } from '@solana/kit';
import { fetchAllMint } from '@solana-program/token-2022';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { getSolanaChainConfig } from '../../../chains/solana/solana.config';
-import { ExecuteSwapResponseType, ExecuteSwapResponse } from '../../../schemas/clmm-schema';
+import { ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { buildOrcaTransaction, createOrcaAuthority } from '../orca.sdk';
-import { OrcaClmmExecuteSwapRequest, OrcaClmmExecuteSwapRequestType } from '../schemas';
import { resolveCounterToken } from './quoteSwap';
-const COMPUTE_BUDGET_PROGRAM_ID = address('ComputeBudget111111111111111111111111111111');
-
export async function executeSwap(
network: string,
walletAddress: string,
@@ -24,7 +20,7 @@ export async function executeSwap(
baseTokenIdentifier: string,
side: 'BUY' | 'SELL',
amount: number,
- slippagePct: number = 1,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
): Promise {
const solana = await Solana.getInstance(network);
const orca = await Orca.getInstance(network);
@@ -117,95 +113,7 @@ export async function executeSwap(
fee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: OrcaClmmExecuteSwapRequestType;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a token swap on Orca CLMM',
- tags: ['/connector/orca'],
- body: OrcaClmmExecuteSwapRequest,
- response: { 200: ExecuteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, amount, side, poolAddress, slippagePct } = request.body;
-
- // Use defaults if not provided
- const networkUsed = network || getSolanaChainConfig().defaultNetwork;
- const walletAddressUsed = walletAddress || getSolanaChainConfig().defaultWallet;
-
- let poolAddressUsed = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressUsed) {
- const solana = await Solana.getInstance(networkUsed);
-
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(`Token not found: ${!baseTokenInfo ? baseToken : quoteToken}`);
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'orca',
- networkUsed,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Orca`,
- );
- }
-
- poolAddressUsed = pool.address;
- }
- logger.info(`Received swap request: ${amount} ${baseToken} -> ${quoteToken} in pool ${poolAddressUsed}`);
-
- return await executeSwap(
- networkUsed,
- walletAddressUsed,
- poolAddressUsed,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Error executing swap:', e.message || e);
-
- if (e.statusCode) {
- // If it's already an HTTP error, throw it properly
- throw e;
- }
-
- // Check for specific error messages
- const errorMessage = e.message || e.toString();
- if (errorMessage.includes('503') || errorMessage.includes('Service Unavailable')) {
- throw httpErrors.serviceUnavailable('RPC service temporarily unavailable. Please try again.');
- }
-
- throw httpErrors.internalServerError(`Swap execution failed: ${errorMessage}`);
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/orca/clmm-routes/fetchPools.ts b/src/connectors/orca/clmm-routes/fetchPools.ts
index ba56259bd9..92d186b653 100644
--- a/src/connectors/orca/clmm-routes/fetchPools.ts
+++ b/src/connectors/orca/clmm-routes/fetchPools.ts
@@ -1,74 +1,57 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { FetchPoolsResponse } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { FetchPoolsResponseType } from '../../../schemas/clmm-schema';
import { Orca } from '../orca';
-import { OrcaClmmFetchPoolsRequest } from '../schemas';
-
-export const fetchPoolsRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: {
- network?: string;
- limit?: number;
- query?: string;
- sortBy?: string;
- sortDirection?: string;
- verifiedOnly?: boolean;
- };
- }>('/fetch-pools', {
- schema: {
- description: 'Fetch Orca pools from API with search and sorting',
- tags: ['/connector/orca'],
- querystring: OrcaClmmFetchPoolsRequest,
- response: {
- 200: FetchPoolsResponse,
- },
- },
- handler: async (request, _reply) => {
- try {
- const { network, limit = 50, query, sortBy, sortDirection, verifiedOnly } = request.query;
- const orca = await Orca.getInstance(network);
+export interface OrcaFetchPoolsArgs {
+ network: string;
+ limit?: number;
+ query?: string;
+ sortBy?: string;
+ sortDirection?: string;
+ verifiedOnly?: boolean;
+}
- const rawPools = await orca.fetchPoolsFromApi({
- limit,
- query,
- sortBy,
- sortDirection,
- verifiedOnly,
- });
+/**
+ * Fetch pools from Orca's own pool-discovery API and normalize them into the
+ * shared FetchPoolsResponse shape. Reached through GET /trading/clmm/fetch-pools.
+ *
+ * Orca's API returns a flat list with no total count and no pagination, so the
+ * response reports page 1 and a total equal to what came back.
+ */
+export async function fetchPools(args: OrcaFetchPoolsArgs): Promise {
+ const { network, limit = 50, query, sortBy, sortDirection, verifiedOnly } = args;
- // Map to standardized format (same as Meteora)
- const pools = rawPools.map((pool: any) => ({
- address: pool.address,
- name: `${pool.tokenA?.symbol || '?'}-${pool.tokenB?.symbol || '?'}`,
- baseTokenAddress: pool.tokenMintA,
- baseTokenSymbol: pool.tokenA?.symbol || '',
- quoteTokenAddress: pool.tokenMintB,
- quoteTokenSymbol: pool.tokenB?.symbol || '',
- binStep: pool.tickSpacing,
- baseFee: Number(pool.feeRate) / 10000, // Convert to percentage
- price: Number(pool.price),
- tvl: Number(pool.tvlUsdc) || 0,
- apr: pool.feeApr?.day ? Number(pool.feeApr.day) * 100 : undefined, // Convert to percentage
- apy: pool.totalApr?.day ? Number(pool.totalApr.day) * 100 : undefined,
- volume24h: pool.volume?.day ? Number(pool.volume.day) : undefined,
- fees24h: pool.fees?.day ? Number(pool.fees.day) : undefined,
- }));
+ const orca = await Orca.getInstance(network);
- return {
- pools,
- total: pools.length, // Orca API doesn't return total count
- page: 1,
- pageSize: limit,
- };
- } catch (e) {
- logger.error('Error in fetch-pools:', e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Error processing the request');
- }
- },
+ const rawPools = await orca.fetchPoolsFromApi({
+ limit,
+ query,
+ sortBy,
+ sortDirection,
+ verifiedOnly,
});
-};
-export default fetchPoolsRoute;
+ // Map to the shared format (same shape as Meteora)
+ const pools = rawPools.map((pool: any) => ({
+ address: pool.address,
+ name: `${pool.tokenA?.symbol || '?'}-${pool.tokenB?.symbol || '?'}`,
+ baseTokenAddress: pool.tokenMintA,
+ baseTokenSymbol: pool.tokenA?.symbol || '',
+ quoteTokenAddress: pool.tokenMintB,
+ quoteTokenSymbol: pool.tokenB?.symbol || '',
+ binStep: pool.tickSpacing,
+ baseFee: Number(pool.feeRate) / 10000, // Convert to percentage
+ price: Number(pool.price),
+ tvl: Number(pool.tvlUsdc) || 0,
+ apr: pool.feeApr?.day ? Number(pool.feeApr.day) * 100 : undefined, // Convert to percentage
+ apy: pool.totalApr?.day ? Number(pool.totalApr.day) * 100 : undefined,
+ volume24h: pool.volume?.day ? Number(pool.volume.day) : undefined,
+ fees24h: pool.fees?.day ? Number(pool.fees.day) : undefined,
+ }));
+
+ return {
+ pools,
+ total: pools.length, // Orca API doesn't return total count
+ page: 1,
+ pageSize: limit,
+ };
+}
diff --git a/src/connectors/orca/clmm-routes/index.ts b/src/connectors/orca/clmm-routes/index.ts
deleted file mode 100644
index 4198fb2b05..0000000000
--- a/src/connectors/orca/clmm-routes/index.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { addLiquidityRoute } from './addLiquidity';
-import { closePositionRoute } from './closePosition';
-import { collectFeesRoute } from './collectFees';
-import { createPoolRoute } from './createPool';
-import { executeSwapRoute } from './executeSwap';
-import { fetchPoolsRoute } from './fetchPools';
-import { openPositionRoute } from './openPosition';
-import { poolInfoRoute } from './poolInfo';
-import { positionInfoRoute } from './positionInfo';
-import { positionsOwnedRoute } from './positionsOwned';
-import { quotePositionRoute } from './quotePosition';
-import { quoteSwapRoute } from './quoteSwap';
-import { removeLiquidityRoute } from './removeLiquidity';
-
-export const orcaClmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(fetchPoolsRoute);
- await fastify.register(poolInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quotePositionRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(createPoolRoute);
- await fastify.register(openPositionRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(collectFeesRoute);
- await fastify.register(closePositionRoute);
-};
-
-export default orcaClmmRoutes;
diff --git a/src/connectors/orca/clmm-routes/openPosition.ts b/src/connectors/orca/clmm-routes/openPosition.ts
index a55ad0aa4c..1b1c66fb25 100644
--- a/src/connectors/orca/clmm-routes/openPosition.ts
+++ b/src/connectors/orca/clmm-routes/openPosition.ts
@@ -15,22 +15,20 @@ import {
priceToTickIndex,
type IncreaseLiquidityQuote,
} from '@orca-so/whirlpools-core';
-import { Static } from '@sinclair/typebox';
import { address, type Instruction } from '@solana/kit';
import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';
import { Keypair, PublicKey } from '@solana/web3.js';
import { fetchAllMint } from '@solana-program/token-2022';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { OpenPositionResponse, OpenPositionResponseType } from '../../../schemas/clmm-schema';
+import { OpenPositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { getCurrentTransferFee } from '../orca.position';
import { buildOrcaTransaction, createOrcaAuthority, replaceOrcaInstructionAccounts } from '../orca.sdk';
import { extractInnerTransferAmounts } from '../orca.utils';
-import { OrcaClmmOpenPositionRequest } from '../schemas';
export async function openPosition(
network: string,
@@ -61,7 +59,7 @@ export async function openPosition(
throw httpErrors.badRequest('Calculated tick indices are invalid (lower >= upper)');
}
- const slippageBps = Math.round((slippagePct || 1) * 100);
+ const slippageBps = Math.round((slippagePct ?? OrcaConfig.config.slippagePct ?? 1) * 100);
const baseAmount = BigInt(Math.floor((baseTokenAmount || 0) * 10 ** mintA.data.decimals));
const quoteAmount = BigInt(Math.floor((quoteTokenAmount || 0) * 10 ** mintB.data.decimals));
const shouldAddLiquidity = baseAmount > 0n || quoteAmount > 0n;
@@ -141,7 +139,14 @@ export async function openPosition(
const generated = await openPositionInstructionsWithTickBounds(
rpc,
whirlpool.address,
- { tokenMaxA: liquidityQuote.tokenMaxA, tokenMaxB: liquidityQuote.tokenMaxB },
+ // The estimates, not the quote's ceilings. increaseLiquidityQuote{A,B} already
+ // applied slippageBps to produce tokenMax*, and the builder applies
+ // slippageToleranceBps again below to derive the on-chain maximums — so passing
+ // tokenMax* here makes the ceiling the target and deposits slippagePct more than
+ // was asked for. A one-sided open showed it plainly: 1 USDC funded deposited
+ // 1.009999. A two-sided one hides it, because the pool ratio pins the deposit
+ // before the bound is reached.
+ { tokenMaxA: liquidityQuote.tokenEstA, tokenMaxB: liquidityQuote.tokenEstB },
lowerTickIndex,
upperTickIndex,
{
@@ -218,10 +223,9 @@ export async function openPosition(
const { signature, fee } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress, [
positionMintKeypair,
]);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
let positionRent = 0;
let baseTokenAmountAdded = liquidityQuote ? Number(liquidityQuote.tokenEstA) / 10 ** mintA.data.decimals : 0;
@@ -274,50 +278,3 @@ export async function openPosition(
},
};
}
-
-export const openPositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: OpenPositionResponseType;
- }>(
- '/open-position',
- {
- schema: {
- description: 'Open a new Orca position',
- tags: ['/connector/orca'],
- body: OrcaClmmOpenPositionRequest,
- response: { 200: OpenPositionResponse },
- },
- },
- async (request) => {
- try {
- const {
- walletAddress,
- poolAddress,
- lowerPrice,
- upperPrice,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- network,
- } = request.body;
- return await openPosition(
- network,
- walletAddress,
- poolAddress,
- lowerPrice,
- upperPrice,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (error) {
- logger.error(error);
- if (error.statusCode) throw error;
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default openPositionRoute;
diff --git a/src/connectors/orca/clmm-routes/poolInfo.ts b/src/connectors/orca/clmm-routes/poolInfo.ts
index e194c47a50..965fd79168 100644
--- a/src/connectors/orca/clmm-routes/poolInfo.ts
+++ b/src/connectors/orca/clmm-routes/poolInfo.ts
@@ -1,20 +1,13 @@
import { sqrtPriceToPrice } from '@orca-so/whirlpools-core';
import { PublicKey } from '@solana/web3.js';
import { fetchAllMint } from '@solana-program/token-2022';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
import { PoolInfo } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
import { Orca } from '../orca';
import { computeOrcaBinDistribution } from '../orca.utils';
-import {
- OrcaClmmGetPoolInfoRequest,
- OrcaClmmGetPoolInfoRequestType,
- OrcaPoolInfo,
- OrcaPoolInfoSchema,
-} from '../schemas';
-
+import { OrcaPoolInfo } from '../schemas';
export async function getPoolInfo(
fastify: FastifyInstance,
network: string,
@@ -100,36 +93,3 @@ export async function getPoolInfo(
return poolInfo;
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: OrcaClmmGetPoolInfoRequestType;
- Reply: OrcaPoolInfo;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get pool information for a Orca pool',
- tags: ['/connector/orca'],
- querystring: OrcaClmmGetPoolInfoRequest,
- response: {
- 200: OrcaPoolInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { poolAddress, binCount = 0, network } = request.query;
- return (await getPoolInfo(fastify, network, poolAddress, binCount)) as OrcaPoolInfo;
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/orca/clmm-routes/positionInfo.ts b/src/connectors/orca/clmm-routes/positionInfo.ts
index 1f3eb62827..c893a8e6c3 100644
--- a/src/connectors/orca/clmm-routes/positionInfo.ts
+++ b/src/connectors/orca/clmm-routes/positionInfo.ts
@@ -1,11 +1,9 @@
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { PositionInfo, PositionInfoSchema, GetPositionInfoRequestType } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { Orca } from '../orca';
-import { OrcaClmmGetPositionInfoRequest } from '../schemas';
export async function getPositionInfo(
fastify: FastifyInstance,
@@ -41,37 +39,3 @@ export async function getPositionInfo(
return positionInfo;
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get details for a specific Orca position',
- tags: ['/connector/orca'],
- querystring: OrcaClmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { positionAddress, walletAddress } = request.query;
- const network = request.query.network;
- return await getPositionInfo(fastify, network, positionAddress, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/orca/clmm-routes/positionsOwned.ts b/src/connectors/orca/clmm-routes/positionsOwned.ts
index c66e78bf53..e8ba8b4d52 100644
--- a/src/connectors/orca/clmm-routes/positionsOwned.ts
+++ b/src/connectors/orca/clmm-routes/positionsOwned.ts
@@ -1,14 +1,10 @@
-import { Type } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { getSolanaChainConfig } from '../../../chains/solana/solana.config';
-import { GetPositionsOwnedRequestType, PositionInfo, PositionInfoSchema } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
-import { OrcaClmmGetPositionsOwnedRequest } from '../schemas';
-
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
export async function getPositionsOwned(
fastify: FastifyInstance,
@@ -34,36 +30,3 @@ export async function getPositionsOwned(
logger.info(`Found ${positions.length} Orca position(s) for wallet ${walletAddressToUse.slice(0, 8)}...`);
return positions;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionsOwnedRequestType;
- Reply: PositionInfo[];
- }>(
- '/positions-owned',
- {
- schema: {
- description: "Retrieve all positions owned by a user's wallet across Orca CLMM pools",
- tags: ['/connector/orca'],
- querystring: OrcaClmmGetPositionsOwnedRequest,
- response: {
- 200: Type.Array(PositionInfoSchema),
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress } = request.query;
- return await getPositionsOwned(fastify, network, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/orca/clmm-routes/quotePosition.ts b/src/connectors/orca/clmm-routes/quotePosition.ts
index 98a94e45c4..bd0ccb9787 100644
--- a/src/connectors/orca/clmm-routes/quotePosition.ts
+++ b/src/connectors/orca/clmm-routes/quotePosition.ts
@@ -1,12 +1,8 @@
-import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
-
-import { QuotePositionResponseType, QuotePositionResponse } from '../../../schemas/clmm-schema';
+import { QuotePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { quotePosition as getQuotePosition } from '../orca.utils';
-import { OrcaClmmQuotePositionRequest } from '../schemas';
export async function quotePosition(
network: string,
@@ -15,7 +11,7 @@ export async function quotePosition(
poolAddress: string,
baseTokenAmount?: number,
quoteTokenAmount?: number,
- slippagePct: number = 1,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
): Promise {
const orca = await Orca.getInstance(network);
@@ -46,51 +42,3 @@ export async function quotePosition(
return quote;
}
-
-export const quotePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: Static;
- Reply: QuotePositionResponseType;
- }>(
- '/quote-position',
- {
- schema: {
- description: 'Quote amounts for a new Orca CLMM position',
- tags: ['/connector/orca'],
- querystring: OrcaClmmQuotePositionRequest,
- response: {
- 200: QuotePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.query;
-
- return await quotePosition(
- network,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Failed to quote position');
- }
- },
- );
-};
-
-export default quotePositionRoute;
diff --git a/src/connectors/orca/clmm-routes/quoteSwap.ts b/src/connectors/orca/clmm-routes/quoteSwap.ts
index e2c200d041..3a5ed2490e 100644
--- a/src/connectors/orca/clmm-routes/quoteSwap.ts
+++ b/src/connectors/orca/clmm-routes/quoteSwap.ts
@@ -1,12 +1,9 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapResponseType, QuoteSwapResponse } from '../../../schemas/clmm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { getOrcaSwapQuote } from '../orca.utils';
-import { OrcaClmmQuoteSwapRequest, OrcaClmmQuoteSwapRequestType } from '../schemas';
export async function getRawSwapQuote(
network: string,
@@ -15,7 +12,7 @@ export async function getRawSwapQuote(
amount: number,
side: 'BUY' | 'SELL',
poolAddress: string,
- slippagePct: number = 1,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
) {
const solana = await Solana.getInstance(network);
const orca = await Orca.getInstance(network);
@@ -50,7 +47,7 @@ async function formatSwapQuote(
amount: number,
side: 'BUY' | 'SELL',
poolAddress: string,
- slippagePct: number = 1,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
): Promise {
const quote = await getRawSwapQuote(
network,
@@ -76,86 +73,6 @@ async function formatSwapQuote(
};
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: OrcaClmmQuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Orca CLMM',
- tags: ['/connector/orca'],
- querystring: OrcaClmmQuoteSwapRequest,
- response: {
- 200: QuoteSwapResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, poolAddress, slippagePct } = request.query;
- const networkUsed = network;
-
- // Validate essential parameters
- if (!baseToken || !quoteToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, quoteToken, amount, and side are required');
- }
-
- const solana = await Solana.getInstance(networkUsed);
-
- let poolAddressToUse = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressToUse) {
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(`Token not found: ${!baseTokenInfo ? baseToken : quoteToken}`);
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'orca',
- networkUsed,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Orca`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- return await formatSwapQuote(
- networkUsed,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- poolAddressToUse,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Resolves the counter ("quote") token for an Orca whirlpool given the base token. The standardized
* swap wrappers take poolAddress + baseToken and derive the other side from the pool
diff --git a/src/connectors/orca/clmm-routes/removeLiquidity.ts b/src/connectors/orca/clmm-routes/removeLiquidity.ts
index 623b12e0a4..ca48806dd3 100644
--- a/src/connectors/orca/clmm-routes/removeLiquidity.ts
+++ b/src/connectors/orca/clmm-routes/removeLiquidity.ts
@@ -1,29 +1,27 @@
import { decreaseLiquidityInstructions } from '@orca-so/whirlpools';
import { fetchPosition, fetchWhirlpool } from '@orca-so/whirlpools-client';
-import { Static } from '@sinclair/typebox';
import { address } from '@solana/kit';
import { PublicKey } from '@solana/web3.js';
import { fetchAllMint } from '@solana-program/token-2022';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { RemoveLiquidityResponse, RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Orca } from '../orca';
+import { OrcaConfig } from '../orca.config';
import { buildOrcaTransaction, createOrcaAuthority } from '../orca.sdk';
-import { OrcaClmmRemoveLiquidityRequest } from '../schemas';
export async function removeLiquidity(
network: string,
walletAddress: string,
positionAddress: string,
- liquidityPct: number,
- slippagePct: number,
+ percentageToRemove: number,
+ slippagePct: number = OrcaConfig.config.slippagePct ?? 1,
): Promise {
- if (liquidityPct <= 0 || liquidityPct > 100) {
- throw httpErrors.badRequest('liquidityPct must be between 0 and 100');
+ if (percentageToRemove <= 0 || percentageToRemove > 100) {
+ throw httpErrors.badRequest('percentageToRemove must be between 0 and 100');
}
const solana = await Solana.getInstance(network);
@@ -33,7 +31,7 @@ export async function removeLiquidity(
const whirlpool = await fetchWhirlpool(orca.solanaKitRpc, position.data.whirlpool);
const [mintA, mintB] = await fetchAllMint(orca.solanaKitRpc, [whirlpool.data.tokenMintA, whirlpool.data.tokenMintB]);
const liquidityAmount = BigInt(
- new Decimal(position.data.liquidity.toString()).mul(liquidityPct).div(100).floor().toFixed(0),
+ new Decimal(position.data.liquidity.toString()).mul(percentageToRemove).div(100).floor().toFixed(0),
);
if (liquidityAmount <= 0n || liquidityAmount > position.data.liquidity) {
@@ -51,7 +49,7 @@ export async function removeLiquidity(
},
);
logger.info(
- `Removing ${liquidityPct}% liquidity, estimated: ` +
+ `Removing ${percentageToRemove}% liquidity, estimated: ` +
`${(Number(result.quote.tokenEstA) / 10 ** mintA.data.decimals).toFixed(6)} tokenA, ` +
`${(Number(result.quote.tokenEstB) / 10 ** mintB.data.decimals).toFixed(6)} tokenB`,
);
@@ -76,38 +74,13 @@ export async function removeLiquidity(
signature,
status: 1,
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.data.whirlpool.toString(),
fee,
baseTokenAmountRemoved: Math.abs(balanceChanges[0]),
quoteTokenAmountRemoved: Math.abs(balanceChanges[1]),
},
};
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from an Orca position',
- tags: ['/connector/orca'],
- body: OrcaClmmRemoveLiquidityRequest,
- response: { 200: RemoveLiquidityResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, positionAddress, liquidityPct = 100, slippagePct = 1, network } = request.body;
- return await removeLiquidity(network, walletAddress, positionAddress, liquidityPct, slippagePct);
- } catch (error) {
- logger.error(error);
- if (error.statusCode) throw error;
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/orca/orca.routes.ts b/src/connectors/orca/orca.routes.ts
deleted file mode 100644
index fd9fae7c94..0000000000
--- a/src/connectors/orca/orca.routes.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { orcaClmmRoutes } from './clmm-routes';
-
-// CLMM routes including swap endpoints
-const orcaClmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/orca'];
- }
- });
-
- await instance.register(orcaClmmRoutes);
- });
-};
-
-// Export the CLMM routes
-export const orcaRoutes = {
- clmm: orcaClmmRoutesWrapper,
-};
-
-export default orcaRoutes;
diff --git a/src/connectors/orca/orca.ts b/src/connectors/orca/orca.ts
index 444c94fa6d..ae7d5c354f 100644
--- a/src/connectors/orca/orca.ts
+++ b/src/connectors/orca/orca.ts
@@ -1,5 +1,5 @@
import { fetchPositionsForOwner, setNativeMintWrappingStrategy, type WhirlpoolDeployment } from '@orca-so/whirlpools';
-import { fetchWhirlpool, fetchPosition } from '@orca-so/whirlpools-client';
+import { fetchWhirlpool, fetchPosition, fetchMaybePosition } from '@orca-so/whirlpools-client';
import { address, createSolanaRpc, mainnet, devnet } from '@solana/kit';
import { PublicKey } from '@solana/web3.js';
@@ -369,12 +369,16 @@ export class Orca {
throw httpErrors.badRequest(`Invalid position address: ${positionAddress}`);
}
- try {
- const positionInfo = await getPositionDetails(this.solanaKitRpc, positionAddress, this.deployment);
- return positionInfo;
- } catch (error) {
- logger.error('Error getting position info:', error);
+ // null means "the position account does not exist" — a definitive on-chain
+ // answer that callers (position-info 404, close reconciliation in
+ // Hummingbot's LP executor) treat as "position closed". Anything else must
+ // throw: swallowing a transient RPC failure here serves "position closed"
+ // for a network blip, and an executor acting on that abandons a live,
+ // funded position while reporting success.
+ const maybePosition = await fetchMaybePosition(this.solanaKitRpc, address(positionAddress));
+ if (!maybePosition.exists) {
return null;
}
+ return await getPositionDetails(this.solanaKitRpc, positionAddress, this.deployment);
}
}
diff --git a/src/connectors/orca/schemas.ts b/src/connectors/orca/schemas.ts
index e6c69946ed..e5bc8d1c3b 100644
--- a/src/connectors/orca/schemas.ts
+++ b/src/connectors/orca/schemas.ts
@@ -1,22 +1,10 @@
import { Type, Static } from '@sinclair/typebox';
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
import { PoolInfoSchema } from '../../schemas/clmm-schema';
-import { OrcaConfig } from './orca.config';
-
// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.01;
-const BASE_TOKEN_AMOUNT = 0.01;
-const QUOTE_TOKEN_AMOUNT = 2;
-const LOWER_PRICE_BOUND = 200;
-const UPPER_PRICE_BOUND = 300;
-const CLMM_POOL_ADDRESS_EXAMPLE = 'Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE';
// Orca-specific extension
export const OrcaPoolInfoSchema = Type.Composite(
@@ -34,562 +22,4 @@ export const OrcaPoolInfoSchema = Type.Composite(
);
export type OrcaPoolInfo = Static;
-// Orca-specific extensions for quote-swap
-export const OrcaQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
- poolAddress: Type.Optional(Type.String()),
-});
-
-// Orca-specific extensions for quote-swap response
-export const OrcaQuoteSwapResponse = Type.Object({
- baseTokenAmount: Type.Number(),
- quoteTokenAmount: Type.Number(),
- exchangeRate: Type.Number(),
- priceImpactPct: Type.Number(),
- poolAddress: Type.String(),
- fee: Type.Number(),
- gasEstimate: Type.String(),
- computeUnits: Type.Number(),
-});
-
-// Orca CLMM-specific extensions
-export const OrcaClmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Orca CLMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair (optional - required if poolAddress not provided)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
-});
-
-// Export the type for QuoteSwapRequest
-export type OrcaClmmQuoteSwapRequestType = Static;
-
-export const OrcaClmmExecuteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Orca CLMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address (optional - required if poolAddress not provided)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
-});
-
-// Export the type for ExecuteSwapRequest
-export type OrcaClmmExecuteSwapRequestType = Static;
-
-// Orca CLMM Open Position Request
-export const OrcaClmmOpenPositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will open the position',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Orca CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
-});
-
-// Orca CLMM Create Pool Request
-export const OrcaClmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create and initialize the pool',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- tickSpacing: Type.Integer({
- description:
- 'Tick spacing (fee tier) for the new Whirlpool. A FeeTier account for this config+tickSpacing ' +
- 'must already exist on-chain. Common Orca values: 1, 2, 8, 16, 64, 128, 256.',
- minimum: 1,
- examples: [64],
- }),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. If omitted, the current market price is fetched from the ' +
- 'unified swap router so the pool opens on-market. No position is opened; only the pool is created.',
- examples: [QUOTE_TOKEN_AMOUNT / BASE_TOKEN_AMOUNT],
- }),
- ),
-});
-
-// Orca CLMM Add Liquidity Request
-export const OrcaClmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will add liquidity',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
-});
-
-// Orca CLMM Remove Liquidity Request
-export const OrcaClmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will remove liquidity',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- liquidityPct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- default: 100,
- examples: [100],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: 1,
- examples: [1],
- }),
- ),
-});
-
-// Orca CLMM Close Position Request
-export const OrcaClmmClosePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will close the position',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
-});
-
-// Orca CLMM Collect Fees Request
-export const OrcaClmmCollectFeesRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will collect fees',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
-});
-
-// Orca CLMM Fetch Pools Request
-export const OrcaClmmFetchPoolsRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- limit: Type.Optional(
- Type.Number({
- minimum: 1,
- maximum: 100,
- default: 50,
- description: 'Maximum number of pools to return',
- examples: [50],
- }),
- ),
- query: Type.Optional(
- Type.String({
- description: 'Search query to match pools by name, tokens, or address',
- examples: ['SOL', 'USDC', 'SOL-USDC'],
- }),
- ),
- sortBy: Type.Optional(
- Type.String({
- description: 'Sort by field',
- enum: ['volume', 'tvl', 'fees', 'rewards', 'yieldovertvl'],
- default: 'volume',
- }),
- ),
- sortDirection: Type.Optional(
- Type.String({
- description: 'Sort direction',
- enum: ['asc', 'desc'],
- default: 'desc',
- }),
- ),
- verifiedOnly: Type.Optional(
- Type.Boolean({
- description: 'Only return pools with verified tokens',
- default: false,
- }),
- ),
-});
-
-// Orca CLMM Get Pool Info Request
-export const OrcaClmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Orca CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- // binCount inherited from base GetPoolInfoRequest semantics — declared
- // explicitly here so the Orca network enum override stays a flat schema.
- binCount: Type.Optional(
- Type.Integer({
- description:
- 'If > 0, include a `bins` array (per-tickSpacing token amounts around the current tick). ' +
- 'Default 0 — pool-info skips the extra getProgramAccounts call.',
- default: 0,
- minimum: 0,
- maximum: 401,
- }),
- ),
-});
-export type OrcaClmmGetPoolInfoRequestType = Static;
-
-// Orca CLMM Get Position Info Request
-export const OrcaClmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position address',
- examples: [''],
- }),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
-});
-
-// Orca CLMM Get Positions Owned Request
-export const OrcaClmmGetPositionsOwnedRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address to check for positions',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
-});
-
-// Orca CLMM Quote Position Request
-export const OrcaClmmQuotePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...OrcaConfig.networks],
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Orca CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: OrcaConfig.config.slippagePct,
- examples: [OrcaConfig.config.slippagePct],
- }),
- ),
-});
-
// Orca position data structure (from @orca-so/whirlpools)
-const OrcaPositionDataSchema = Type.Object({
- discriminator: Type.Any(), // Uint8Array(8)
- whirlpool: Type.String(),
- positionMint: Type.String(),
- liquidity: Type.Any(), // bigint
- tickLowerIndex: Type.Number(),
- tickUpperIndex: Type.Number(),
- feeGrowthCheckpointA: Type.Any(), // bigint
- feeOwedA: Type.Any(), // bigint
- feeGrowthCheckpointB: Type.Any(), // bigint
- feeOwedB: Type.Any(), // bigint
- rewardInfos: Type.Array(Type.Any()), // Array of reward info objects
-});
-
-const OrcaPositionSchema = Type.Object({
- executable: Type.Boolean(),
- lamports: Type.Any(), // bigint
- programAddress: Type.String(),
- space: Type.Any(), // bigint
- address: Type.String(),
- data: OrcaPositionDataSchema,
- exists: Type.Boolean(),
- tokenProgram: Type.String(),
- isPositionBundle: Type.Boolean(),
-});
-
-export type OrcaPosition = Static;
diff --git a/src/connectors/pancakeswap-sol/README.md b/src/connectors/pancakeswap-sol/README.md
index d734a508c9..4bb57a756f 100644
--- a/src/connectors/pancakeswap-sol/README.md
+++ b/src/connectors/pancakeswap-sol/README.md
@@ -25,7 +25,7 @@ Key features:
### Read-Only Routes (Implemented)
#### 1. Pool Info
-- **Endpoint**: `GET /connectors/pancakeswap-sol/clmm/pool-info`
+- **Endpoint**: `GET /trading/clmm/pool-info` (with `connector=pancakeswap-sol`)
- **Description**: Fetch detailed information about a CLMM pool
- **Parameters**:
- `network`: Solana network (mainnet-beta or devnet)
@@ -33,7 +33,7 @@ Key features:
- **Returns**: Pool info including tokens, price, liquidity, fees, tick spacing, etc.
#### 2. Position Info
-- **Endpoint**: `GET /connectors/pancakeswap-sol/clmm/position-info`
+- **Endpoint**: `GET /trading/clmm/position-info` (with `connector=pancakeswap-sol`)
- **Description**: Fetch information about a specific position NFT
- **Parameters**:
- `network`: Solana network
@@ -41,7 +41,7 @@ Key features:
- **Returns**: Position details including price range, liquidity, fees earned, etc.
#### 3. Positions Owned
-- **Endpoint**: `GET /connectors/pancakeswap-sol/clmm/positions-owned`
+- **Endpoint**: `GET /trading/clmm/positions-owned` (with `connector=pancakeswap-sol`)
- **Description**: List all positions owned by a wallet in a specific pool
- **Parameters**:
- `network`: Solana network
@@ -53,7 +53,7 @@ Key features:
### Swap Routes (Implemented)
#### 4. Quote Swap
-- **Endpoint**: `GET /connectors/pancakeswap-sol/clmm/quote-swap`
+- **Endpoint**: `GET /trading/clmm/quote-swap` (with `connector=pancakeswap-sol`)
- **Description**: Get swap quote for a token pair (simplified - uses spot price)
- **Parameters**:
- `network`: Solana network
@@ -71,7 +71,7 @@ Key features:
- Suitable for small trades where price impact is minimal
#### 5. Execute Swap
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/execute-swap`
+- **Endpoint**: `POST /trading/clmm/execute-swap` (with `connector=pancakeswap-sol`)
- **Description**: Execute a swap on PancakeSwap Solana CLMM
- **Parameters**:
- `network`: Solana network
@@ -92,7 +92,7 @@ Key features:
### Position Management Routes (Implemented)
#### 6. Add Liquidity
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/add-liquidity`
+- **Endpoint**: `POST /trading/clmm/add` (with `connector=pancakeswap-sol`)
- **Description**: Add liquidity to an existing position
- **Parameters**:
- `network`: Solana network
@@ -104,7 +104,7 @@ Key features:
- **Implementation**: Uses increase_liquidity_v2 instruction with manual building
#### 7. Remove Liquidity
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/remove-liquidity`
+- **Endpoint**: `POST /trading/clmm/remove` (with `connector=pancakeswap-sol`)
- **Description**: Remove liquidity from a position by percentage
- **Parameters**:
- `network`: Solana network
@@ -115,7 +115,7 @@ Key features:
- **Implementation**: Uses decrease_liquidity_v2 instruction with tick array calculation
#### 8. Collect Fees
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/collect-fees`
+- **Endpoint**: `POST /trading/clmm/collect-fees` (with `connector=pancakeswap-sol`)
- **Description**: Collect accumulated fees from a position
- **Parameters**:
- `network`: Solana network
@@ -125,7 +125,7 @@ Key features:
- **Implementation**: Uses the clever approach of removing 1% liquidity to collect fees
#### 9. Close Position
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/close-position`
+- **Endpoint**: `POST /trading/clmm/close` (with `connector=pancakeswap-sol`)
- **Description**: Close an empty position (must have zero liquidity)
- **Parameters**:
- `network`: Solana network
@@ -135,7 +135,7 @@ Key features:
- **Implementation**: Uses close_position instruction, requires position to be emptied first
#### 10. Quote Position
-- **Endpoint**: `GET /connectors/pancakeswap-sol/clmm/quote-position`
+- **Endpoint**: `GET /trading/clmm/quote-liquidity` (with `connector=pancakeswap-sol`)
- **Description**: Quote token amounts for opening a position (simplified)
- **Parameters**:
- `network`: Solana network
@@ -148,7 +148,7 @@ Key features:
- **Note**: Simplified version using spot price, not full tick math
#### 11. Open Position
-- **Endpoint**: `POST /connectors/pancakeswap-sol/clmm/open-position`
+- **Endpoint**: `POST /trading/clmm/open` (with `connector=pancakeswap-sol`)
- **Description**: Open a new CLMM position with Token2022 NFT and metadata
- **Parameters**:
- `network`: Solana network
@@ -171,7 +171,7 @@ Key features:
All essential CLMM routes have been implemented:
- ✅ **Pool/Position Info** (3 routes): pool-info, position-info, positions-owned
- ✅ **Swap Operations** (2 routes): quote-swap, execute-swap
-- ✅ **Position Management** (6 routes): quote-position, open-position, add-liquidity, remove-liquidity, collect-fees, close-position
+- ✅ **Position Management** (6 routes): quote-liquidity, open, add, remove, collect-fees, close
**Total: 11 routes** providing complete CLMM functionality without SDK dependency.
@@ -179,35 +179,36 @@ All essential CLMM routes have been implemented:
### Get Pool Info
```bash
-curl "http://localhost:15888/connectors/pancakeswap-sol/clmm/pool-info?network=mainnet-beta&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
+curl "http://localhost:15888/trading/clmm/pool-info?chainNetwork=solana-mainnet-beta&connector=pancakeswap-sol&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
```
### Get Position Info
```bash
-curl "http://localhost:15888/connectors/pancakeswap-sol/clmm/position-info?network=mainnet-beta&positionAddress=F1xRqqbWdg3vdMEsn9YjRU7RnFVn67MZhDVXrWoobii5"
+curl "http://localhost:15888/trading/clmm/position-info?chainNetwork=solana-mainnet-beta&connector=pancakeswap-sol&positionAddress=F1xRqqbWdg3vdMEsn9YjRU7RnFVn67MZhDVXrWoobii5"
```
### Get Positions Owned
```bash
-curl "http://localhost:15888/connectors/pancakeswap-sol/clmm/positions-owned?network=mainnet-beta&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ&walletAddress="
+curl "http://localhost:15888/trading/clmm/positions-owned?chainNetwork=solana-mainnet-beta&connector=pancakeswap-sol&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ&walletAddress="
```
### Quote Swap
```bash
# SELL 0.01 SOL for USDC
-curl "http://localhost:15888/connectors/pancakeswap-sol/clmm/quote-swap?network=mainnet-beta&baseToken=SOL"eToken=USDC&amount=0.01&side=SELL&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
+curl "http://localhost:15888/trading/clmm/quote-swap?chainNetwork=solana-mainnet-beta&connector=pancakeswap-sol&baseToken=SOL"eToken=USDC&amount=0.01&side=SELL&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
# BUY 0.01 SOL with USDC
-curl "http://localhost:15888/connectors/pancakeswap-sol/clmm/quote-swap?network=mainnet-beta&baseToken=SOL"eToken=USDC&amount=0.01&side=BUY&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
+curl "http://localhost:15888/trading/clmm/quote-swap?chainNetwork=solana-mainnet-beta&connector=pancakeswap-sol&baseToken=SOL"eToken=USDC&amount=0.01&side=BUY&poolAddress=DJNtGuBGEQiUCWE8F981M2C3ZghZt2XLD8f2sQdZ6rsZ"
```
### Execute Swap
```bash
# SELL 0.01 SOL for USDC
-curl -X POST "http://localhost:15888/connectors/pancakeswap-sol/clmm/execute-swap" \
+curl -X POST "http://localhost:15888/trading/clmm/execute-swap" \
-H "Content-Type: application/json" \
-d '{
- "network": "mainnet-beta",
+ "chainNetwork": "solana-mainnet-beta",
+ "connector": "pancakeswap-sol",
"walletAddress": "",
"baseToken": "SOL",
"quoteToken": "USDC",
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/addLiquidity.ts b/src/connectors/pancakeswap-sol/clmm-routes/addLiquidity.ts
index e9c881a774..1573541c39 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/addLiquidity.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/addLiquidity.ts
@@ -1,16 +1,14 @@
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { AddLiquidityResponse, AddLiquidityResponseType } from '../../../schemas/clmm-schema';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { AddLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
import { PancakeswapSolConfig } from '../pancakeswap-sol.config';
import { buildAddLiquidityTransaction } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmAddLiquidityRequest } from '../schemas';
import { quotePosition } from './quotePosition';
@@ -111,78 +109,39 @@ export async function addLiquidity(
quoteToken.address,
]);
- const baseTokenChange = balanceChanges[0];
- const quoteTokenChange = balanceChanges[1];
+ // Adding to a position can still create accounts — a wrapped-SOL account the wallet
+ // did not have, a tick array this range is first to touch — and their rent rides on
+ // the native side of the balance change without being liquidity.
+ const { opened } = accountLifecycleSol(txData);
+ const baseTokenChange = liquidityWithoutRent(balanceChanges[0], new PublicKey(baseToken.address), opened);
+ const quoteTokenChange = liquidityWithoutRent(balanceChanges[1], new PublicKey(quoteToken.address), opened);
logger.info(`Liquidity added successfully. Signature: ${signature}`);
logger.info(
- `Added ${Math.abs(baseTokenChange).toFixed(4)} ${baseToken.symbol}, ${Math.abs(quoteTokenChange).toFixed(4)} ${quoteToken.symbol}`,
+ `Added ${baseTokenChange.toFixed(4)} ${baseToken.symbol}, ${quoteTokenChange.toFixed(4)} ${quoteToken.symbol}`,
);
return {
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: positionInfo.poolAddress,
fee: totalFee / 1e9,
- baseTokenAmountAdded: Math.abs(baseTokenChange),
- quoteTokenAmountAdded: Math.abs(quoteTokenChange),
+ baseTokenAmountAdded: baseTokenChange,
+ quoteTokenAmountAdded: quoteTokenChange,
},
};
}
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return {
signature,
status: 0, // PENDING
};
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to an existing PancakeSwap Solana CLMM position',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- walletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.body;
-
- return await addLiquidity(
- network,
- walletAddress!,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Add liquidity error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to add liquidity';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/closePosition.ts b/src/connectors/pancakeswap-sol/clmm-routes/closePosition.ts
index a945fc6bb6..ae78d18005 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/closePosition.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/closePosition.ts
@@ -1,17 +1,19 @@
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ClosePositionResponse, ClosePositionResponseType } from '../../../schemas/clmm-schema';
+import {
+ accountLifecycleSol,
+ liquidityWithoutRent,
+ transfersByProgramInstruction,
+} from '../../../chains/solana/solana.utils';
+import { ClosePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol, PANCAKESWAP_CLMM_PROGRAM_ID } from '../pancakeswap-sol';
import { buildDecreaseLiquidityV2Instruction, buildClosePositionInstruction } from '../pancakeswap-sol.instructions';
import { parsePositionData } from '../pancakeswap-sol.parser';
-import { buildTransactionWithInstructions } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmClosePositionRequest } from '../schemas';
+import { buildTransactionWithInstructions, buildUnwrapSolInstructions } from '../pancakeswap-sol.transactions';
export async function closePosition(
network: string,
@@ -66,8 +68,25 @@ export async function closePosition(
// Build transaction with both instructions (like successful manual transaction)
const instructions = [];
- // 1. If position has liquidity, remove it all first
+ // 1. Collect the fees on their own, THEN remove the liquidity.
+ //
+ // This program moves a position's fees and its principal in the same
+ // `decrease_liquidity_v2` transfer, so a single instruction leaves the two
+ // inseparable — which is why this route reported fees of 0 and a principal that
+ // silently contained them. A zero-liquidity decrease collects the fees and touches
+ // nothing else (it is exactly what the collect-fees route does), so the two land in
+ // different top-level instructions and the transaction says which is which.
if (hasLiquidity) {
+ const collectFeesIx = await buildDecreaseLiquidityV2Instruction(
+ solana,
+ positionNftMint,
+ walletPubkey,
+ new BN(0), // liquidity: fees only
+ new BN(0), // amount0Min
+ new BN(0), // amount1Min
+ );
+ instructions.push(collectFeesIx);
+
const removeLiquidityIx = await buildDecreaseLiquidityV2Instruction(
solana,
positionNftMint,
@@ -83,6 +102,11 @@ export async function closePosition(
const closePositionIx = await buildClosePositionInstruction(solana, positionNftMint, walletPubkey);
instructions.push(closePositionIx);
+ // 3. Unwrap what the withdrawal paid out in WSOL. Without this the SOL never reaches
+ // the native balance, and the only thing that moves it is the rent — which is exactly
+ // how this route came to report the rent as the liquidity withdrawn.
+ instructions.push(...buildUnwrapSolInstructions(solana, walletPubkey, [baseToken.address, quoteToken.address]));
+
// Build complete transaction
const transaction = await buildTransactionWithInstructions(
solana,
@@ -102,72 +126,65 @@ export async function closePosition(
const totalFee = txData.meta.fee;
// Extract balance changes
- const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
+ const { balanceChanges, txDetails } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
baseToken.address,
quoteToken.address,
]);
- const baseTokenChange = balanceChanges[0];
- const quoteTokenChange = balanceChanges[1];
+ // Closing gives back the rent of every account that closed — the position, its NFT
+ // account, the tick array if this was the last position in it, and the wrapped-SOL
+ // account the unwrap above closes. All of it arrives in the same native balance
+ // change as the withdrawal, and none of it is liquidity.
+ const { closed, rentRefunded } = accountLifecycleSol(txData);
+ const baseTokenChange = liquidityWithoutRent(balanceChanges[0], new PublicKey(baseToken.address), closed);
+ const quoteTokenChange = liquidityWithoutRent(balanceChanges[1], new PublicKey(quoteToken.address), closed);
+
+ // The fee-collecting instruction is the first of this program's instructions in the
+ // transaction, so its transfers are the fees and nothing else. Taken from the
+ // transaction rather than from a balance change, which cannot separate them.
+ //
+ // An unreadable transaction leaves this at zero and the amounts whole, which is what
+ // this route did for every close before now — a known shape, not a new silence.
+ const [collected = [0, 0]] = transfersByProgramInstruction(txDetails, PANCAKESWAP_CLMM_PROGRAM_ID.toBase58(), [
+ baseToken.address,
+ quoteToken.address,
+ ]);
+ const baseFeeCollected = hasLiquidity ? collected[0] : 0;
+ const quoteFeeCollected = hasLiquidity ? collected[1] : 0;
logger.info(`Position closed successfully. Signature: ${signature}`);
logger.info(
- `Removed ${Math.abs(baseTokenChange).toFixed(4)} ${baseToken.symbol}, ${Math.abs(quoteTokenChange).toFixed(4)} ${quoteToken.symbol}`,
+ `Removed ${baseTokenChange.toFixed(4)} ${baseToken.symbol}, ${quoteTokenChange.toFixed(4)} ${quoteToken.symbol}`,
);
return {
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: positionInfo.poolAddress,
fee: totalFee / 1e9,
- positionRentRefunded: 0, // Position rent refund (simplified)
- baseTokenAmountRemoved: Math.abs(baseTokenChange),
- quoteTokenAmountRemoved: Math.abs(quoteTokenChange),
- baseFeeAmountCollected: 0, // Included in balance changes
- quoteFeeAmountCollected: 0, // Included in balance changes
+ positionRentRefunded: rentRefunded,
+ // Principal is what came back less what the fee instruction paid out. Both
+ // arrive in the same balance change, so the subtraction is what keeps fee
+ // income out of the position's returned capital. Clamped at zero rather than
+ // publishing a negative quantity of tokens if the two measures ever disagree.
+ baseTokenAmountRemoved: Math.max(0, baseTokenChange - baseFeeCollected),
+ quoteTokenAmountRemoved: Math.max(0, quoteTokenChange - quoteFeeCollected),
+ baseFeeAmountCollected: baseFeeCollected,
+ quoteFeeAmountCollected: quoteFeeCollected,
},
};
}
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return {
signature,
status: 0, // PENDING
};
}
-
-export const closePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: ClosePositionResponseType;
- }>(
- '/close-position',
- {
- schema: {
- description: 'Close a PancakeSwap Solana CLMM position and remove all liquidity and fees if present',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmClosePositionRequest,
- response: {
- 200: ClosePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', walletAddress, positionAddress } = request.body;
-
- return await closePosition(network, walletAddress!, positionAddress);
- } catch (e: any) {
- logger.error('Close position error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to close position';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default closePositionRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/collectFees.ts b/src/connectors/pancakeswap-sol/clmm-routes/collectFees.ts
index b8bd781e1c..b9bddc4ffd 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/collectFees.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/collectFees.ts
@@ -1,84 +1,114 @@
-import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
+import { PublicKey } from '@solana/web3.js';
+import BN from 'bn.js';
-import { CollectFeesResponse, CollectFeesResponseType } from '../../../schemas/clmm-schema';
+import { Solana } from '../../../chains/solana/solana';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { CollectFeesResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
-import { PancakeswapSolClmmCollectFeesRequest } from '../schemas';
-
-import { removeLiquidity } from './removeLiquidity';
+import { PancakeswapSol } from '../pancakeswap-sol';
+import { buildRemoveLiquidityTransaction } from '../pancakeswap-sol.transactions';
+/**
+ * Collect accumulated fees from a position WITHOUT touching its liquidity.
+ *
+ * The PancakeSwap Solana CLMM program (a Raydium CLMM fork) has no owner-facing
+ * "collect fees" instruction — like Raydium, fees (and rewards) owed to a position are
+ * transferred by `decrease_liquidity_v2`. Calling it with `liquidity = 0` collects the
+ * owed fees while leaving the position's liquidity intact.
+ */
async function collectFees(
network: string,
walletAddress: string,
positionAddress: string,
): Promise {
- logger.info(`Collecting fees from position ${positionAddress} by removing 1% liquidity`);
+ const solana = await Solana.getInstance(network);
+ const pancakeswapSol = await PancakeswapSol.getInstance(network);
+
+ const positionInfo = await pancakeswapSol.getPositionInfo(positionAddress);
+ if (!positionInfo) {
+ throw httpErrors.notFound(`Position not found: ${positionAddress}`);
+ }
+
+ const baseToken = await solana.getToken(positionInfo.baseTokenAddress);
+ const quoteToken = await solana.getToken(positionInfo.quoteTokenAddress);
+ if (!baseToken || !quoteToken) {
+ throw httpErrors.notFound('Token information not found');
+ }
+
+ logger.info(`Collecting fees from position ${positionAddress} via zero-liquidity decrease`);
+
+ const wallet = await solana.getWallet(walletAddress);
+ const walletPubkey = new PublicKey(walletAddress);
+ const positionNftMint = new PublicKey(positionAddress);
+
+ // Get priority fee
+ const priorityFeeInLamports = await solana.estimateGasPrice();
+ const priorityFeePerCU = Math.floor(priorityFeeInLamports * 1e6);
+
+ // decrease_liquidity_v2 with liquidity = 0 transfers the owed fees (and rewards)
+ // without removing any liquidity.
+ const transaction = await buildRemoveLiquidityTransaction(
+ solana,
+ positionNftMint,
+ walletPubkey,
+ new BN(0), // liquidity: collect fees only
+ new BN(0), // amount0Min
+ new BN(0), // amount1Min
+ [baseToken.address, quoteToken.address], // unwrap a native-side fee rather than leaving it WSOL
+ 600000, // Compute units
+ priorityFeePerCU,
+ );
+
+ // Sign and send
+ transaction.sign([wallet]);
+ await solana.simulateWithErrorHandling(transaction);
- // Use the clever Raydium approach: remove 1% of liquidity to collect fees
- // This withdraws a tiny amount of liquidity + all accumulated fees
- const removeLiquidityResponse = await removeLiquidity(network, walletAddress, positionAddress, 1);
+ const { confirmed, signature, txData } = await solana.sendAndConfirmRawTransaction(transaction);
+
+ if (confirmed && txData) {
+ const totalFee = txData.meta.fee;
+
+ // No liquidity was removed, so the position tokens received are exactly the fees.
+ const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
+ baseToken.address,
+ quoteToken.address,
+ ]);
+
+ // Unwrapping closes the wrapped-SOL account, so its rent comes back in the same
+ // native balance change as the fee. Rent is not fee income.
+ const { closed } = accountLifecycleSol(txData);
+ const baseFeeCollected = liquidityWithoutRent(balanceChanges[0], new PublicKey(baseToken.address), closed);
+ const quoteFeeCollected = liquidityWithoutRent(balanceChanges[1], new PublicKey(quoteToken.address), closed);
+
+ logger.info(
+ `Fees collected from position ${positionAddress}: ${baseFeeCollected.toFixed(6)} ${baseToken.symbol}, ` +
+ `${quoteFeeCollected.toFixed(6)} ${quoteToken.symbol}`,
+ );
- if (removeLiquidityResponse.status !== 1 || !removeLiquidityResponse.data) {
return {
- signature: removeLiquidityResponse.signature,
- status: removeLiquidityResponse.status,
+ signature,
+ status: 1, // CONFIRMED
+ data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: positionInfo.poolAddress,
+ fee: totalFee / 1e9,
+ baseFeeAmountCollected: baseFeeCollected,
+ quoteFeeAmountCollected: quoteFeeCollected,
+ },
};
}
- // The fees are included in the amounts removed
- // Since we only removed 1%, most of the tokens received are fees
- const baseFeeCollected = removeLiquidityResponse.data.baseTokenAmountRemoved;
- const quoteFeeCollected = removeLiquidityResponse.data.quoteTokenAmountRemoved;
-
- logger.info(`Fees collected. Base: ${baseFeeCollected}, Quote: ${quoteFeeCollected}`);
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
return {
- signature: removeLiquidityResponse.signature,
- status: 1, // CONFIRMED
- data: {
- fee: removeLiquidityResponse.data.fee,
- baseFeeAmountCollected: baseFeeCollected,
- quoteFeeAmountCollected: quoteFeeCollected,
- },
+ signature,
+ status: 0, // PENDING
};
}
export { collectFees };
-
-export const collectFeesRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CollectFeesResponseType;
- }>(
- '/collect-fees',
- {
- schema: {
- description: 'Collect accumulated fees from a PancakeSwap Solana CLMM position (removes 1% liquidity)',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmCollectFeesRequest,
- response: {
- 200: CollectFeesResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', walletAddress, positionAddress } = request.body;
-
- return await collectFees(network, walletAddress!, positionAddress);
- } catch (e: any) {
- logger.error('Collect fees error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to collect fees';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default collectFeesRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/createPool.ts b/src/connectors/pancakeswap-sol/clmm-routes/createPool.ts
index 6660c7eb5f..db8d167acb 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/createPool.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/createPool.ts
@@ -1,11 +1,9 @@
-import { Static } from '@sinclair/typebox';
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
@@ -13,7 +11,6 @@ import { PancakeswapSol, PANCAKESWAP_CLMM_PROGRAM_ID } from '../pancakeswap-sol'
import { buildCreatePoolInstruction } from '../pancakeswap-sol.instructions';
import { priceToSqrtPriceX64 } from '../pancakeswap-sol.math';
import { buildTransactionWithInstructions } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmCreatePoolRequest } from '../schemas';
/** Lexicographic byte comparison (mirrors Buffer.compare) for canonical mint ordering. */
function compareBytes(a: Buffer, b: Buffer): number {
@@ -51,10 +48,10 @@ async function getMintProgram(solana: Solana, mint: PublicKey): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to initialize the pool (${e.message}). ` +
@@ -67,12 +64,44 @@ async function fetchMarketPrice(network: string, baseToken: string, quoteToken:
return quote.amountOut / quote.amountIn; // quote token per base token
}
+/**
+ * Derive the amm_config PDA for a fee-config index. The program (a Raydium CLMM
+ * fork) seeds it with ["amm_config", index] — index encoded big-endian, the same
+ * Raydium convention this connector's tick_array PDAs use. The little-endian
+ * (plain Anchor/borsh) form is tried as a fallback before failing.
+ */
+async function resolveAmmConfigByIndex(solana: Solana, ammConfigIndex: number): Promise {
+ if (!Number.isInteger(ammConfigIndex) || ammConfigIndex < 0 || ammConfigIndex > 0xffff) {
+ throw httpErrors.badRequest(`ammConfigIndex must be an integer in [0, 65535], got ${ammConfigIndex}`);
+ }
+ const candidates: PublicKey[] = [];
+ for (const endian of ['BE', 'LE'] as const) {
+ const indexBuffer = Buffer.alloc(2);
+ if (endian === 'BE') indexBuffer.writeUInt16BE(ammConfigIndex, 0);
+ else indexBuffer.writeUInt16LE(ammConfigIndex, 0);
+ const [pda] = PublicKey.findProgramAddressSync(
+ [Buffer.from('amm_config'), indexBuffer],
+ PANCAKESWAP_CLMM_PROGRAM_ID,
+ );
+ candidates.push(pda);
+ }
+ for (const pda of candidates) {
+ const info = await solana.connection.getAccountInfo(pda);
+ if (info && info.owner.equals(PANCAKESWAP_CLMM_PROGRAM_ID)) {
+ return pda;
+ }
+ }
+ throw httpErrors.badRequest(
+ `No amm_config account found on-chain for index ${ammConfigIndex} ` +
+ `(tried ${candidates.map((c) => c.toBase58()).join(', ')})`,
+ );
+}
+
/**
* Create and initialize (but do NOT seed a position for) a PancakeSwap Solana CLMM pool.
*
- * @param ammConfig Base58 address of an existing on-chain amm_config account for the desired fee tier.
- * Required — there is no API to enumerate amm_config accounts, so the caller supplies
- * the config for the fee tier they want (mirrors Meteora DAMM v2 configAddress).
+ * @param ammConfigIndex Fee-config index; resolves to the program's amm_config PDA
+ * (["amm_config", index]) and is validated on-chain. Default 0.
*/
export async function createPool(
network: string,
@@ -80,31 +109,13 @@ export async function createPool(
baseToken: string,
quoteToken: string,
initialPrice?: number,
- ammConfig?: string,
+ ammConfigIndex: number = 0,
): Promise {
const solana = await Solana.getInstance(network);
// Ensure the connector singleton is initialized (mirrors the other pancakeswap-sol routes).
await PancakeswapSol.getInstance(network);
- // Validate the required amm_config address and confirm it exists on-chain.
- if (!ammConfig) {
- throw httpErrors.badRequest('ammConfig is required: pass the address of an existing on-chain amm_config account');
- }
- let ammConfigPubkey: PublicKey;
- try {
- ammConfigPubkey = new PublicKey(ammConfig);
- } catch {
- throw httpErrors.badRequest(sanitizeErrorMessage('Invalid ammConfig address: {}', ammConfig));
- }
- const ammConfigInfo = await solana.connection.getAccountInfo(ammConfigPubkey);
- if (!ammConfigInfo) {
- throw httpErrors.badRequest(`amm_config account not found: ${ammConfigPubkey.toBase58()}`);
- }
- if (!ammConfigInfo.owner.equals(PANCAKESWAP_CLMM_PROGRAM_ID)) {
- throw httpErrors.badRequest(
- `amm_config ${ammConfigPubkey.toBase58()} is not owned by the PancakeSwap CLMM program`,
- );
- }
+ const ammConfigPubkey = await resolveAmmConfigByIndex(solana, ammConfigIndex);
// Resolve mints, decimals and token programs from authoritative on-chain data.
const baseMint = await resolveMint(solana, baseToken);
@@ -205,51 +216,13 @@ export async function createPool(
price: seedPrice,
data: {
fee: txData.meta.fee / 1e9,
- // Pool created + initialized only — no liquidity/position seeded.
- baseTokenAmountAdded: 0,
- quoteTokenAmountAdded: 0,
},
};
}
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return { signature, status: 0, poolAddress, price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description:
- 'Create and initialize a new PancakeSwap Solana CLMM pool at an initial price. Does not open or seed a position.',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- walletAddress,
- baseToken,
- quoteToken,
- initialPrice,
- ammConfig,
- } = request.body;
- return await createPool(network, walletAddress!, baseToken, quoteToken, initialPrice, ammConfig);
- } catch (e: any) {
- logger.error('Create pool error:', e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError(e.message || 'Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/executeSwap.ts b/src/connectors/pancakeswap-sol/clmm-routes/executeSwap.ts
index a291385bbe..87836e8a3c 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/executeSwap.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/executeSwap.ts
@@ -1,16 +1,12 @@
-import { Static } from '@sinclair/typebox';
-import { PublicKey, VersionedTransaction } from '@solana/web3.js';
+import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteSwapResponse, ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
+import { ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
-import { MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64 } from '../pancakeswap-sol.parser';
import { buildSwapTransaction } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmExecuteSwapRequest, PancakeswapSolClmmExecuteSwapRequestType } from '../schemas';
/**
* Execute a swap on PancakeSwap Solana CLMM
@@ -63,7 +59,6 @@ export async function executeSwap(
// Validate pool contains the requested tokens
const poolTokens = new Set([poolInfo.baseTokenAddress, poolInfo.quoteTokenAddress]);
- const requestedTokens = new Set([baseToken.address, quoteToken.address]);
if (!poolTokens.has(baseToken.address) || !poolTokens.has(quoteToken.address)) {
throw httpErrors.badRequest(
@@ -74,8 +69,6 @@ export async function executeSwap(
}
// Determine if baseToken matches pool's base or quote
- const isBaseTokenFirst = poolInfo.baseTokenAddress === baseToken.address;
- const currentPrice = isBaseTokenFirst ? poolInfo.price : 1 / poolInfo.price;
logger.info(
`Token addresses - base: ${baseToken.address}, quote: ${quoteToken.address}, pool base: ${poolInfo.baseTokenAddress}, pool quote: ${poolInfo.quoteTokenAddress}`,
@@ -165,7 +158,6 @@ export async function executeSwap(
walletAddress,
baseToken,
quoteToken,
- totalFee,
);
return {
@@ -179,89 +171,17 @@ export async function executeSwap(
fee: totalFee / 1e9,
baseTokenBalanceChange: baseTokenChange,
quoteTokenBalanceChange: quoteTokenChange,
+ slippagePct: quote.slippagePct,
},
};
} else {
- // Transaction pending
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return {
signature,
status: 0, // PENDING
};
}
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: PancakeswapSolClmmExecuteSwapRequestType;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on PancakeSwap Solana CLMM',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmExecuteSwapRequest,
- response: { 200: ExecuteSwapResponse },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- walletAddress,
- baseToken,
- quoteToken,
- amount,
- side,
- poolAddress,
- slippagePct,
- } = request.body;
-
- // executeSwap is standardized to require poolAddress; resolve it from the pair when absent.
- let poolAddressToUse = poolAddress;
- if (!poolAddressToUse) {
- const solana = await Solana.getInstance(network);
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(`Token not found: ${!baseTokenInfo ? baseToken : quoteToken}`);
- }
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
- const pool = await poolService.getPool(
- 'pancakeswap-sol',
- network,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
- if (!pool) {
- throw httpErrors.notFound(`No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol}`);
- }
- poolAddressToUse = pool.address;
- }
-
- return await executeSwap(
- network,
- walletAddress!,
- poolAddressToUse,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Execute swap error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to execute swap';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/index.ts b/src/connectors/pancakeswap-sol/clmm-routes/index.ts
deleted file mode 100644
index b25ba188fd..0000000000
--- a/src/connectors/pancakeswap-sol/clmm-routes/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import addLiquidityRoute from './addLiquidity';
-import closePositionRoute from './closePosition';
-import collectFeesRoute from './collectFees';
-import createPoolRoute from './createPool';
-import executeSwapRoute from './executeSwap';
-import openPositionRoute from './openPosition';
-import poolInfoRoute from './poolInfo';
-import positionInfoRoute from './positionInfo';
-import positionsOwnedRoute from './positionsOwned';
-import quotePositionRoute from './quotePosition';
-import quoteSwapRoute from './quoteSwap';
-import removeLiquidityRoute from './removeLiquidity';
-
-export const pancakeswapSolClmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(quotePositionRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(createPoolRoute);
- await fastify.register(openPositionRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(collectFeesRoute);
- await fastify.register(closePositionRoute);
-};
-
-export default pancakeswapSolClmmRoutes;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/openPosition.ts b/src/connectors/pancakeswap-sol/clmm-routes/openPosition.ts
index 699a811ced..4883bdaf36 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/openPosition.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/openPosition.ts
@@ -1,17 +1,15 @@
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { OpenPositionResponse, OpenPositionResponseType } from '../../../schemas/clmm-schema';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { OpenPositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
import { PancakeswapSolConfig } from '../pancakeswap-sol.config';
import { priceToTick, roundTickToSpacing, parsePoolTickSpacing } from '../pancakeswap-sol.parser';
import { buildOpenPositionTransaction } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmOpenPositionRequest } from '../schemas';
import { quotePosition } from './quotePosition';
@@ -105,17 +103,22 @@ export async function openPosition(
);
logger.info(`Quote Max: base=${quote.baseTokenAmountMax}, quote=${quote.quoteTokenAmountMax}`);
- // Use max amounts from quote - slippage already applied in quotePosition
+ // The ceilings — slippage already applied in quotePosition — and, separately, the
+ // liquidity to open. Sizing the position from the ceiling is what GW-28 was: the
+ // program would compute the deposit that liquidity requires, round it up in the
+ // pool's favour, and assert the result against the very number it started from, so a
+ // one-unit rounding failed the open and a wider slippagePct only bought a larger
+ // deposit. The quote already computes the liquidity from the amounts the caller asked
+ // for, which is what the add route has always sent.
const amount0Max = new BN((quote.baseTokenAmountMax * 10 ** baseToken.decimals).toFixed(0));
const amount1Max = new BN((quote.quoteTokenAmountMax * 10 ** quoteToken.decimals).toFixed(0));
+ const liquidity = new BN(quote.liquidity);
logger.info(`Amounts with slippage (${slippagePct ?? PancakeswapSolConfig.config.slippagePct}%):`);
logger.info(` amount0Max: ${amount0Max.toString()} (${baseToken.symbol})`);
logger.info(` amount1Max: ${amount1Max.toString()} (${quoteToken.symbol})`);
- // Determine base flag
- const baseFlag = quote.baseLimited;
- logger.info(`Base Flag: ${baseFlag} (${baseFlag ? 'amount0' : 'amount1'} is base)`);
+ logger.info(`Liquidity: ${liquidity.toString()} (from the quoted amounts, base-limited=${quote.baseLimited})`);
// Get priority fee
const priorityFeeInLamports = await solana.estimateGasPrice();
@@ -131,7 +134,8 @@ export async function openPosition(
amount0Max,
amount1Max,
true, // withMetadata - create NFT with metadata
- baseFlag,
+ null, // let the maxes be ceilings; the liquidity below is what sizes the position
+ liquidity,
800000,
priorityFeePerCU,
);
@@ -152,12 +156,17 @@ export async function openPosition(
quoteToken.address,
]);
- const baseTokenChange = balanceChanges[0];
- const quoteTokenChange = balanceChanges[1];
+ // Opening locks rent in five accounts here — the position, its NFT account, the
+ // wrapped-SOL account, the shared protocol position, and any tick array this range is
+ // first to touch. On a position this size that rent is larger than the deposit it is
+ // attached to, so reporting the wallet delta made the position read 2.4x its size.
+ const { opened, rentLocked } = accountLifecycleSol(txData);
+ const baseTokenChange = liquidityWithoutRent(balanceChanges[0], new PublicKey(baseToken.address), opened);
+ const quoteTokenChange = liquidityWithoutRent(balanceChanges[1], new PublicKey(quoteToken.address), opened);
logger.info(`Position opened successfully. NFT Mint: ${positionNftMint.publicKey.toString()}`);
logger.info(
- `Added ${Math.abs(baseTokenChange).toFixed(4)} ${baseToken.symbol}, ${Math.abs(quoteTokenChange).toFixed(4)} ${quoteToken.symbol}`,
+ `Added ${baseTokenChange.toFixed(4)} ${baseToken.symbol}, ${quoteTokenChange.toFixed(4)} ${quoteToken.symbol}`,
);
return {
@@ -166,70 +175,19 @@ export async function openPosition(
data: {
fee: totalFee / 1e9,
positionAddress: positionNftMint.publicKey.toString(),
- positionRent: 0, // Simplified - not extracting rent from transaction
- baseTokenAmountAdded: Math.abs(baseTokenChange),
- quoteTokenAmountAdded: Math.abs(quoteTokenChange),
+ positionRent: rentLocked,
+ baseTokenAmountAdded: baseTokenChange,
+ quoteTokenAmountAdded: quoteTokenChange,
},
};
}
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return {
signature,
status: 0, // PENDING
};
}
-
-export const openPositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: OpenPositionResponseType;
- }>(
- '/open-position',
- {
- schema: {
- description: 'Open a new PancakeSwap Solana CLMM position with Token2022 NFT',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmOpenPositionRequest,
- response: {
- 200: OpenPositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- walletAddress,
- poolAddress,
- lowerPrice,
- upperPrice,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.body;
-
- return await openPosition(
- network,
- walletAddress!,
- poolAddress,
- lowerPrice,
- upperPrice,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Open position error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to open position';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default openPositionRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/poolInfo.ts b/src/connectors/pancakeswap-sol/clmm-routes/poolInfo.ts
index 581fbf5a45..b55644bbea 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/poolInfo.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/poolInfo.ts
@@ -1,12 +1,16 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { PoolInfo } from '../../../schemas/clmm-schema';
import { PancakeswapSol } from '../pancakeswap-sol';
-import { PancakeswapSolClmmGetPoolInfoRequest } from '../schemas';
+import { computeBinDistribution } from '../pancakeswap-sol.bins';
-export async function getPoolInfo(fastify: FastifyInstance, network: string, poolAddress: string): Promise {
+export async function getPoolInfo(
+ fastify: FastifyInstance,
+ network: string,
+ poolAddress: string,
+ binCount: number = 0,
+): Promise {
const pancakeswap = await PancakeswapSol.getInstance(network);
if (!poolAddress) {
@@ -19,41 +23,23 @@ export async function getPoolInfo(fastify: FastifyInstance, network: string, poo
throw fastify.httpErrors.notFound(`Pool not found: ${poolAddress}`);
}
+ // Optionally include the per-bin distribution around the current tick — only
+ // fires the extra tick-array fetch when binCount > 0 so default latency is
+ // unchanged (same contract as orca/raydium).
+ if (binCount > 0) {
+ const solana = await Solana.getInstance(network);
+ poolInfo.bins = await computeBinDistribution({
+ connection: solana.connection,
+ poolAddress,
+ tickSpacing: poolInfo.binStep as number,
+ currentTick: poolInfo.activeBinId as number,
+ currentPrice: poolInfo.price,
+ liquidity: (poolInfo as any)._liquidity as bigint,
+ decimals0: (poolInfo as any)._mintDecimals0 as number,
+ decimals1: (poolInfo as any)._mintDecimals1 as number,
+ binCount,
+ });
+ }
+
return poolInfo;
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: PoolInfo;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get CLMM pool information from PancakeSwap Solana',
- tags: ['/connector/pancakeswap-sol'],
- querystring: PancakeswapSolClmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { network = 'mainnet-beta', poolAddress } = request.query;
- return await getPoolInfo(fastify, network, poolAddress);
- } catch (e: any) {
- logger.error('Pool info error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to fetch pool info';
- throw fastify.httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/positionInfo.ts b/src/connectors/pancakeswap-sol/clmm-routes/positionInfo.ts
index 4cef11e9a1..5a10289998 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/positionInfo.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/positionInfo.ts
@@ -1,10 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { Solana } from '../../../chains/solana/solana';
-import { GetPositionInfoRequestType, PositionInfo, PositionInfoSchema } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { PancakeswapSol } from '../pancakeswap-sol';
-import { PancakeswapSolClmmGetPositionInfoRequest } from '../schemas';
export async function getPositionInfo(
fastify: FastifyInstance,
@@ -24,39 +21,3 @@ export async function getPositionInfo(
return positionInfo;
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get CLMM position information from PancakeSwap Solana',
- tags: ['/connector/pancakeswap-sol'],
- querystring: PancakeswapSolClmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { network = 'mainnet-beta', positionAddress } = request.query;
- return await getPositionInfo(fastify, network, positionAddress);
- } catch (e: any) {
- logger.error('Position info error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to fetch position info';
- throw fastify.httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/positionsOwned.ts b/src/connectors/pancakeswap-sol/clmm-routes/positionsOwned.ts
index e14f0fceea..6dd651ea45 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/positionsOwned.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/positionsOwned.ts
@@ -1,18 +1,10 @@
-import { Type, Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { PositionInfo, PositionInfoSchema } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
-import { PancakeswapSolClmmGetPositionsOwnedRequest, PancakeswapSolClmmGetPositionsOwnedRequestType } from '../schemas';
-
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
-
-const GetPositionsOwnedResponse = Type.Array(PositionInfoSchema);
-
-type GetPositionsOwnedResponseType = Static;
export async function getPositionsOwned(
fastify: FastifyInstance,
@@ -111,39 +103,3 @@ async function fetchPositionsFromRPC(solana: Solana, walletAddress: string): Pro
logger.info(`Found ${positions.length} PancakeSwap position(s) for wallet ${walletAddress.slice(0, 8)}...`);
return positions;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: PancakeswapSolClmmGetPositionsOwnedRequestType;
- Reply: GetPositionsOwnedResponseType;
- }>(
- '/positions-owned',
- {
- schema: {
- description: "Retrieve all positions owned by a user's wallet across all PancakeSwap Solana CLMM pools",
- tags: ['/connector/pancakeswap-sol'],
- querystring: PancakeswapSolClmmGetPositionsOwnedRequest,
- response: {
- 200: GetPositionsOwnedResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', walletAddress, poolAddress } = request.query;
- return await getPositionsOwned(fastify, network, walletAddress, poolAddress);
- } catch (e: any) {
- logger.error('Positions owned error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to fetch positions';
- throw fastify.httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/quotePosition.ts b/src/connectors/pancakeswap-sol/clmm-routes/quotePosition.ts
index a0018de29c..6a31c6a285 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/quotePosition.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/quotePosition.ts
@@ -1,19 +1,11 @@
-import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { QuotePositionResponse, QuotePositionResponseType } from '../../../schemas/clmm-schema';
+import { QuotePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
import { PancakeswapSolConfig } from '../pancakeswap-sol.config';
-import {
- getLiquidityFromAmounts,
- getLiquidityFromSingleAmount,
- getAmountsFromLiquidity,
-} from '../pancakeswap-sol.math';
+import { getLiquidityFromSingleAmount, getAmountsFromLiquidity } from '../pancakeswap-sol.math';
import { priceToTick, roundTickToSpacing, tickToPrice } from '../pancakeswap-sol.parser';
-import { PancakeswapSolClmmQuotePositionRequest } from '../schemas';
/**
* Quote position with proper CLMM math
@@ -286,56 +278,3 @@ async function quotePosition(
}
export { quotePosition };
-
-export const quotePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: Static;
- Reply: QuotePositionResponseType;
- }>(
- '/quote-position',
- {
- schema: {
- description: 'Quote position amounts for PancakeSwap Solana CLMM (simplified)',
- tags: ['/connector/pancakeswap-sol'],
- querystring: PancakeswapSolClmmQuotePositionRequest,
- response: {
- 200: QuotePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.query;
-
- return await quotePosition(
- network,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Quote position error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to quote position';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default quotePositionRoute;
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/quoteSwap.ts b/src/connectors/pancakeswap-sol/clmm-routes/quoteSwap.ts
index 4b9d5013b3..693d495717 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/quoteSwap.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/quoteSwap.ts
@@ -1,12 +1,9 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapResponseType, QuoteSwapResponse } from '../../../schemas/clmm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol } from '../pancakeswap-sol';
import { PancakeswapSolConfig } from '../pancakeswap-sol.config';
-import { PancakeswapSolClmmQuoteSwapRequest, PancakeswapSolClmmQuoteSwapRequestType } from '../schemas';
/**
* Quote swap implementation using pool data with fee and price impact estimation.
@@ -144,58 +141,6 @@ export async function getRawSwapQuote(
return result;
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: PancakeswapSolClmmQuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description:
- 'Get swap quote for PancakeSwap Solana CLMM with fee and estimated price impact based on pool liquidity',
- tags: ['/connector/pancakeswap-sol'],
- querystring: PancakeswapSolClmmQuoteSwapRequest,
- response: { 200: QuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- baseToken,
- quoteToken,
- amount,
- side,
- poolAddress,
- slippagePct,
- } = request.query;
-
- return await getRawSwapQuote(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- poolAddress,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Quote swap error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to get swap quote';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Resolves the counter ("quote") token for a PancakeSwap Solana CLMM pool given the base token. The
* standardized swap wrappers take poolAddress + baseToken and derive the other side from the pool,
diff --git a/src/connectors/pancakeswap-sol/clmm-routes/removeLiquidity.ts b/src/connectors/pancakeswap-sol/clmm-routes/removeLiquidity.ts
index baaba8fa4e..89e0132c81 100644
--- a/src/connectors/pancakeswap-sol/clmm-routes/removeLiquidity.ts
+++ b/src/connectors/pancakeswap-sol/clmm-routes/removeLiquidity.ts
@@ -1,17 +1,15 @@
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import Decimal from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { RemoveLiquidityResponse, RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapSol, PANCAKESWAP_CLMM_PROGRAM_ID } from '../pancakeswap-sol';
import { parsePositionData } from '../pancakeswap-sol.parser';
import { buildRemoveLiquidityTransaction } from '../pancakeswap-sol.transactions';
-import { PancakeswapSolClmmRemoveLiquidityRequest } from '../schemas';
export async function removeLiquidity(
network: string,
@@ -76,6 +74,7 @@ export async function removeLiquidity(
liquidityToRemove,
new BN(0), // amount0Min
new BN(0), // amount1Min
+ [baseToken.address, quoteToken.address], // unwrap a native side rather than leaving it WSOL
600000, // Compute units
priorityFeePerCU,
);
@@ -95,64 +94,39 @@ export async function removeLiquidity(
quoteToken.address,
]);
- const baseTokenChange = balanceChanges[0];
- const quoteTokenChange = balanceChanges[1];
+ // Unwrapping closes the wrapped-SOL account, so its rent — and any WSOL the wallet
+ // was already holding in it — lands in the native balance change alongside the
+ // withdrawal. None of that is liquidity this position gave back.
+ const { closed } = accountLifecycleSol(txData);
+ const baseTokenChange = liquidityWithoutRent(balanceChanges[0], new PublicKey(baseToken.address), closed);
+ const quoteTokenChange = liquidityWithoutRent(balanceChanges[1], new PublicKey(quoteToken.address), closed);
logger.info(`Liquidity removed successfully. Signature: ${signature}`);
logger.info(
- `Removed ${Math.abs(baseTokenChange).toFixed(4)} ${baseToken.symbol}, ${Math.abs(quoteTokenChange).toFixed(4)} ${quoteToken.symbol}`,
+ `Removed ${baseTokenChange.toFixed(4)} ${baseToken.symbol}, ${quoteTokenChange.toFixed(4)} ${quoteToken.symbol}`,
);
return {
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: positionInfo.poolAddress,
fee: totalFee / 1e9,
- baseTokenAmountRemoved: Math.abs(baseTokenChange),
- quoteTokenAmountRemoved: Math.abs(quoteTokenChange),
+ baseTokenAmountRemoved: baseTokenChange,
+ quoteTokenAmountRemoved: quoteTokenChange,
},
};
}
+ // A landed-but-failed transaction is terminal: fail loudly instead of returning
+ // PENDING (callers would poll forever). Genuinely-not-landed keeps the pending shape.
+ await solana.throwIfLandedWithError(signature, txData);
+
return {
signature,
status: 0, // PENDING
};
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a PancakeSwap Solana CLMM position',
- tags: ['/connector/pancakeswap-sol'],
- body: PancakeswapSolClmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', walletAddress, positionAddress, percentageToRemove } = request.body;
-
- return await removeLiquidity(network, walletAddress!, positionAddress, percentageToRemove);
- } catch (e: any) {
- logger.error('Remove liquidity error:', e);
- // Re-throw httpErrors as-is
- if (e.statusCode) {
- throw e;
- }
- // Handle unknown errors
- const errorMessage = e.message || 'Failed to remove liquidity';
- throw httpErrors.internalServerError(errorMessage);
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.bins.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.bins.ts
new file mode 100644
index 0000000000..d2b5a881ff
--- /dev/null
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.bins.ts
@@ -0,0 +1,123 @@
+import { Connection, PublicKey } from '@solana/web3.js';
+import BN from 'bn.js';
+
+import { BinLiquidity } from '../../schemas/clmm-schema';
+import { logger } from '../../services/logger';
+
+import { getAmountsFromLiquidity } from './pancakeswap-sol.math';
+import { getTickArrayAddress, getTickArrayStartIndexFromTick, tickToPrice } from './pancakeswap-sol.parser';
+
+// TickArrayState layout (idl/clmm.json — identical to Raydium CLMM, which this
+// program forks): discriminator(8) + pool_id(32) + start_tick_index(i32, 4) +
+// ticks[60 x TickState] + initialized_tick_count(u8) + recent_epoch(u64) + padding.
+// TickState: tick(i32, 4) + liquidity_net(i128, 16) + liquidity_gross(u128, 16) +
+// fee_growth_outside_0_x64(16) + fee_growth_outside_1_x64(16) +
+// reward_growths_outside_x64(3 x 16) + padding(13 x u32, 52) = 168 bytes.
+const TICK_ARRAY_HEADER = 8 + 32 + 4;
+const TICK_STATE_SIZE = 168;
+
+function readI128LE(data: Buffer, offset: number): bigint {
+ let value = 0n;
+ for (let i = 0; i < 16; i++) {
+ value += BigInt(data[offset + i]) << BigInt(8 * i);
+ }
+ if (value >= 1n << 127n) {
+ value -= 1n << 128n;
+ }
+ return value;
+}
+
+function liquidityNetAt(arrays: Map, tickIndex: number, tickSpacing: number): bigint {
+ const startIndex = getTickArrayStartIndexFromTick(tickIndex, tickSpacing);
+ const data = arrays.get(startIndex);
+ if (!data) return 0n;
+ const slot = Math.floor((tickIndex - startIndex) / tickSpacing);
+ const base = TICK_ARRAY_HEADER + slot * TICK_STATE_SIZE;
+ if (base + TICK_STATE_SIZE > data.length) return 0n;
+ // A zeroed (uninitialized) slot fails the tick check; its liquidity_net would
+ // be 0 anyway, so either way the boundary contributes nothing.
+ if (data.readInt32LE(base) !== tickIndex) return 0n;
+ return readI128LE(data, base + 4);
+}
+
+/**
+ * Per-bin liquidity distribution around the current tick, mirroring the
+ * raydium/orca bin walk: propagate active liquidity outward across initialized
+ * tick boundaries, then convert each bin's L into token amounts.
+ */
+export async function computeBinDistribution(args: {
+ connection: Connection;
+ poolAddress: string;
+ tickSpacing: number;
+ currentTick: number;
+ currentPrice: number; // human units (quote per base)
+ liquidity: bigint; // active liquidity at the current tick
+ decimals0: number;
+ decimals1: number;
+ binCount: number;
+}): Promise {
+ const { connection, poolAddress, tickSpacing, currentTick, currentPrice, liquidity, decimals0, decimals1, binCount } =
+ args;
+ if (binCount <= 0) return [];
+
+ // Snap the bin grid so the current tick lands inside a bin.
+ const halfBins = Math.floor(binCount / 2);
+ const snapped = Math.floor(currentTick / tickSpacing) * tickSpacing;
+ const firstBinStart = snapped - halfBins * tickSpacing;
+ const boundaries: number[] = [];
+ for (let i = 0; i <= binCount; i++) {
+ boundaries.push(firstBinStart + i * tickSpacing);
+ }
+
+ // Fetch every tick array the boundaries touch in one RPC round-trip.
+ const poolPubkey = new PublicKey(poolAddress);
+ const startIndexes = [...new Set(boundaries.map((t) => getTickArrayStartIndexFromTick(t, tickSpacing)))];
+ const arrays = new Map();
+ try {
+ const accounts = await connection.getMultipleAccountsInfo(
+ startIndexes.map((s) => getTickArrayAddress(poolPubkey, s)),
+ );
+ accounts.forEach((account, i) => {
+ if (account) arrays.set(startIndexes[i], account.data);
+ });
+ } catch (e) {
+ logger.warn(`pancakeswap-sol bin fetch failed for ${poolAddress}: ${e}`);
+ return [];
+ }
+
+ // Propagate L outward from the current bin across boundary liquidity_net.
+ const curIdx = Math.floor((currentTick - firstBinStart) / tickSpacing);
+ const binLs: bigint[] = new Array(binCount);
+ binLs[curIdx] = liquidity;
+ for (let i = curIdx + 1; i < binCount; i++) {
+ binLs[i] = binLs[i - 1] + liquidityNetAt(arrays, boundaries[i], tickSpacing);
+ }
+ for (let i = curIdx - 1; i >= 0; i--) {
+ binLs[i] = binLs[i + 1] - liquidityNetAt(arrays, boundaries[i + 1], tickSpacing);
+ }
+
+ const decimalDiff = decimals0 - decimals1;
+ const bins: BinLiquidity[] = [];
+ for (let i = 0; i < binCount; i++) {
+ const tickStart = boundaries[i];
+ const priceLower = tickToPrice(tickStart, decimalDiff);
+ const priceUpper = tickToPrice(boundaries[i + 1], decimalDiff);
+ let baseTokenAmount = 0;
+ let quoteTokenAmount = 0;
+ const L = binLs[i];
+ if (L > 0n) {
+ const amounts = getAmountsFromLiquidity(
+ currentPrice,
+ priceLower,
+ priceUpper,
+ new BN(L.toString()),
+ decimals0,
+ decimals1,
+ );
+ baseTokenAmount = amounts.amount0;
+ quoteTokenAmount = amounts.amount1;
+ }
+ bins.push({ binId: tickStart, price: priceLower, baseTokenAmount, quoteTokenAmount });
+ }
+ return bins;
+}
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.fees.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.fees.ts
new file mode 100644
index 0000000000..4507ada9dd
--- /dev/null
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.fees.ts
@@ -0,0 +1,156 @@
+import { BorshCoder } from '@coral-xyz/anchor';
+import { AccountInfo, PublicKey } from '@solana/web3.js';
+
+import { getTickArrayAddress, getTickArrayStartIndexFromTick } from './pancakeswap-sol.parser';
+
+const clmmIdl = require('./idl/clmm.json');
+
+/**
+ * Uncollected fees for a CLMM position, from the same numbers the program uses.
+ *
+ * `position_info` used to answer 0 for both sides unconditionally, with a TODO saying a
+ * wrong number would be worse than no number. But zero *is* a number and it was being
+ * stored: nothing downstream could tell "this connector does not compute fees" from
+ * "this position earned nothing". A position that sat in range while the pool traded
+ * through it — composition moving from 0.009789 SOL / 0.910 USDC to 0.008894 / 0.988 in
+ * five minutes, which only happens if swaps crossed it — reported 0 throughout, while
+ * the collect-fees route harvested a real amount from the same position minutes later.
+ *
+ * The arithmetic is Uniswap v3's, which this program (a Raydium CLMM fork) implements:
+ * a tick records the fee growth accumulated on the *far* side of it, so the growth
+ * inside a range is the global growth less the part below the lower tick and the part
+ * above the upper tick, with which side of each tick is "outside" depending on where the
+ * price is now. Multiply the growth accrued since the position last checkpointed by its
+ * liquidity, and add whatever was already owed at that checkpoint.
+ *
+ * Everything is unsigned 128-bit and the program subtracts with wrapping arithmetic
+ * deliberately: fee growth accumulators are allowed to overflow, and only the difference
+ * between two readings is meaningful. Subtracting without wrapping produces an enormous
+ * positive number the moment an accumulator laps, which is exactly the "plausible but
+ * wrong" answer the old TODO was afraid of.
+ */
+
+const U128 = 1n << 128n;
+const Q64 = 1n << 64n;
+
+/** u128 subtraction that wraps, as the on-chain math does. */
+export function wrappingSub(a: bigint, b: bigint): bigint {
+ return (((a - b) % U128) + U128) % U128;
+}
+
+export interface TickFeeGrowth {
+ /** The tick's index. */
+ tick: number;
+ /** fee_growth_outside_0_x64 as stored. */
+ outside0: bigint;
+ /** fee_growth_outside_1_x64 as stored. */
+ outside1: bigint;
+}
+
+/**
+ * Fee growth accumulated inside a tick range, per unit of liquidity, in X64.
+ *
+ * `tickCurrent` decides what "outside" means for each boundary: below the lower tick the
+ * stored value is the growth *below* it, at or above it the growth is everything else.
+ */
+export function feeGrowthInside(
+ tickCurrent: number,
+ lower: TickFeeGrowth,
+ upper: TickFeeGrowth,
+ feeGrowthGlobal0: bigint,
+ feeGrowthGlobal1: bigint,
+): { inside0: bigint; inside1: bigint } {
+ const below0 = tickCurrent >= lower.tick ? lower.outside0 : wrappingSub(feeGrowthGlobal0, lower.outside0);
+ const below1 = tickCurrent >= lower.tick ? lower.outside1 : wrappingSub(feeGrowthGlobal1, lower.outside1);
+ const above0 = tickCurrent < upper.tick ? upper.outside0 : wrappingSub(feeGrowthGlobal0, upper.outside0);
+ const above1 = tickCurrent < upper.tick ? upper.outside1 : wrappingSub(feeGrowthGlobal1, upper.outside1);
+
+ return {
+ inside0: wrappingSub(wrappingSub(feeGrowthGlobal0, below0), above0),
+ inside1: wrappingSub(wrappingSub(feeGrowthGlobal1, below1), above1),
+ };
+}
+
+/**
+ * What a collect would pay out right now, in the token's smallest units.
+ *
+ * `owed` is what the position had banked at its last checkpoint; the rest is what has
+ * accrued since. A position with no liquidity accrues nothing and is owed whatever it
+ * banked, which is the case a just-emptied position is in.
+ */
+export function pendingFee(
+ owed: bigint,
+ liquidity: bigint,
+ feeGrowthInsideNow: bigint,
+ feeGrowthInsideLast: bigint,
+): bigint {
+ const accrued = (wrappingSub(feeGrowthInsideNow, feeGrowthInsideLast) * liquidity) / Q64;
+ return owed + accrued;
+}
+
+/**
+ * Read the two tick states a position's range is bounded by, and compute what a collect
+ * would pay out right now.
+ *
+ * The tick arrays are decoded with the program's own IDL rather than by counting bytes:
+ * a `TickState` is 168 bytes of mixed i128/u128/arrays sixty times over inside a
+ * `TickArrayState`, and a single wrong offset here would produce a confident, plausible,
+ * wrong fee figure — the exact failure the old hardcoded zero was chosen to avoid.
+ *
+ * Throws rather than guessing when a tick array is missing. A position's own tick arrays
+ * hold its liquidity, so their absence means something is wrong that a fabricated zero
+ * would hide.
+ */
+export async function readPendingFees(
+ connection: { getMultipleAccountsInfo: (keys: PublicKey[]) => Promise<(AccountInfo | null)[]> },
+ poolId: PublicKey,
+ tickSpacing: number,
+ tickCurrent: number,
+ feeGrowthGlobal0: bigint,
+ feeGrowthGlobal1: bigint,
+ position: {
+ tickLowerIndex: number;
+ tickUpperIndex: number;
+ liquidity: bigint;
+ feeGrowthInside0Last: bigint;
+ feeGrowthInside1Last: bigint;
+ tokenFeesOwed0: bigint;
+ tokenFeesOwed1: bigint;
+ },
+): Promise<{ fee0Raw: bigint; fee1Raw: bigint }> {
+ const lowerStart = getTickArrayStartIndexFromTick(position.tickLowerIndex, tickSpacing);
+ const upperStart = getTickArrayStartIndexFromTick(position.tickUpperIndex, tickSpacing);
+ const [lowerArray, upperArray] = await connection.getMultipleAccountsInfo([
+ getTickArrayAddress(poolId, lowerStart),
+ getTickArrayAddress(poolId, upperStart),
+ ]);
+
+ const readTick = (account: AccountInfo | null, tick: number, start: number): TickFeeGrowth => {
+ if (!account) {
+ throw new Error(
+ `Tick array at ${start} for pool ${poolId.toBase58()} not found: a position's own tick arrays ` +
+ 'hold its liquidity, so uncollected fees cannot be computed for it.',
+ );
+ }
+ const decoded: any = new BorshCoder(clmmIdl).accounts.decode('TickArrayState', account.data);
+ const state = decoded.ticks[(tick - start) / tickSpacing];
+ return {
+ tick,
+ outside0: BigInt(state.fee_growth_outside_0_x64.toString()),
+ outside1: BigInt(state.fee_growth_outside_1_x64.toString()),
+ };
+ };
+
+ const { inside0, inside1 } = feeGrowthInside(
+ tickCurrent,
+ readTick(lowerArray, position.tickLowerIndex, lowerStart),
+ readTick(upperArray, position.tickUpperIndex, upperStart),
+ feeGrowthGlobal0,
+ feeGrowthGlobal1,
+ );
+
+ return {
+ fee0Raw: pendingFee(position.tokenFeesOwed0, position.liquidity, inside0, position.feeGrowthInside0Last),
+ fee1Raw: pendingFee(position.tokenFeesOwed1, position.liquidity, inside1, position.feeGrowthInside1Last),
+ };
+}
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.instructions.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.instructions.ts
index 37a61adb5b..0f3d5a0d22 100644
--- a/src/connectors/pancakeswap-sol/pancakeswap-sol.instructions.ts
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.instructions.ts
@@ -3,20 +3,9 @@ import {
TOKEN_PROGRAM_ID,
TOKEN_2022_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID,
- NATIVE_MINT,
getAssociatedTokenAddressSync,
- createAssociatedTokenAccountInstruction,
} from '@solana/spl-token';
-import {
- PublicKey,
- TransactionInstruction,
- SystemProgram,
- SYSVAR_RENT_PUBKEY,
- ComputeBudgetProgram,
- TransactionMessage,
- VersionedTransaction,
- Keypair,
-} from '@solana/web3.js';
+import { PublicKey, TransactionInstruction, SystemProgram, SYSVAR_RENT_PUBKEY, Keypair } from '@solana/web3.js';
import BN from 'bn.js';
import { Solana } from '../../chains/solana/solana';
@@ -600,7 +589,19 @@ export async function buildOpenPositionWithToken22NftInstruction(
amount0Max: BN,
amount1Max: BN,
withMetadata: boolean,
- baseFlag: boolean,
+ /**
+ * Which side the *program* should size liquidity from, or null to use the `liquidity`
+ * argument and treat the maxes as the ceilings they are named for.
+ *
+ * null is what the open route sends. Handing the program a side makes that side's
+ * max both the amount to size from and the ceiling to check against, so the check has
+ * no headroom by construction: it computes the deposit that liquidity requires,
+ * rounds it up in the pool's favour, and asserts it against the number it started
+ * from. One unit of rounding fails the whole transaction, and a wider slippagePct
+ * cannot help — a larger bound is simply a larger deposit.
+ */
+ baseFlag: boolean | null,
+ liquidity: BN = new BN(0),
): Promise {
// Get pool data
const poolAccountInfo = await solana.connection.getAccountInfo(poolAddress);
@@ -694,11 +695,15 @@ export async function buildOpenPositionWithToken22NftInstruction(
tick_upper_index: tickUpperIndex,
tick_array_lower_start_index: tickArrayLowerStartIndex,
tick_array_upper_start_index: tickArrayUpperStartIndex,
- liquidity: new BN(0), // Let program calculate from amounts
+ liquidity,
amount_0_max: amount0Max,
amount_1_max: amount1Max,
with_metadata: withMetadata,
- base_flag: baseFlag ? { some: true } : { some: false },
+ // The plain value, not `{ some: ... }`. Borsh encodes an Option as "0x00" for null
+ // or "0x01" + the value, and its bool layout is `value ? 1 : 0` — so an object is
+ // truthy and `{ some: false }` encoded as Some(TRUE). Every request that meant
+ // "size from the quote side" told the program to size from the base side instead.
+ base_flag: baseFlag,
});
logger.info(`Instruction Data (hex): ${instructionData.toString('hex')}`);
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.math.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.math.ts
index 3150e800fb..80fac96bac 100644
--- a/src/connectors/pancakeswap-sol/pancakeswap-sol.math.ts
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.math.ts
@@ -1,5 +1,4 @@
import BN from 'bn.js';
-import Decimal from 'decimal.js';
/**
* CLMM (Concentrated Liquidity Market Maker) Math Utilities
@@ -106,13 +105,14 @@ export function getAmountsFromLiquidity(
let amount1Raw: number;
if (currentPrice < lowerPrice) {
- // Price below range - all liquidity in token1
- amount0Raw = 0;
- amount1Raw = liquidityNum * (sqrtPriceUpper - sqrtPriceLower);
- } else if (currentPrice >= upperPrice) {
- // Price above range - all liquidity in token0
+ // Price below range - all liquidity in token0: the range sits above the
+ // market, so the pool sells token0 as price rises through it.
amount0Raw = (liquidityNum * (sqrtPriceUpper - sqrtPriceLower)) / (sqrtPriceLower * sqrtPriceUpper);
amount1Raw = 0;
+ } else if (currentPrice >= upperPrice) {
+ // Price above range - all liquidity in token1 (token0 fully sold on the way up)
+ amount0Raw = 0;
+ amount1Raw = liquidityNum * (sqrtPriceUpper - sqrtPriceLower);
} else {
// Price in range
amount0Raw = (liquidityNum * (sqrtPriceUpper - sqrtPriceCurrent)) / (sqrtPriceCurrent * sqrtPriceUpper);
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.routes.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.routes.ts
deleted file mode 100644
index cabb2ecd87..0000000000
--- a/src/connectors/pancakeswap-sol/pancakeswap-sol.routes.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { pancakeswapSolClmmRoutes } from './clmm-routes';
-
-export const pancakeswapSolRoutes: FastifyPluginAsync = async (fastify) => {
- // Register CLMM routes under /clmm prefix
- await fastify.register(pancakeswapSolClmmRoutes, { prefix: '/clmm' });
-};
-
-export default pancakeswapSolRoutes;
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.transactions.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.transactions.ts
index 850ad38002..bc7a90ad2e 100644
--- a/src/connectors/pancakeswap-sol/pancakeswap-sol.transactions.ts
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.transactions.ts
@@ -1,16 +1,7 @@
-import { BorshCoder, Idl } from '@coral-xyz/anchor';
-import {
- TOKEN_PROGRAM_ID,
- TOKEN_2022_PROGRAM_ID,
- ASSOCIATED_TOKEN_PROGRAM_ID,
- NATIVE_MINT,
- getAssociatedTokenAddressSync,
- createAssociatedTokenAccountInstruction,
-} from '@solana/spl-token';
+import { NATIVE_MINT, getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
import {
PublicKey,
TransactionInstruction,
- SYSVAR_RENT_PUBKEY,
ComputeBudgetProgram,
TransactionMessage,
VersionedTransaction,
@@ -28,16 +19,7 @@ import {
buildIncreaseLiquidityV2Instruction,
buildOpenPositionWithToken22NftInstruction,
} from './pancakeswap-sol.instructions';
-import {
- getTokenProgramForMint,
- getTickArrayStartIndexFromTick,
- getTickArrayAddress,
- parsePositionData,
- parsePoolTickSpacing,
- MEMO_PROGRAM_ID,
-} from './pancakeswap-sol.parser';
-
-const clmmIdl = require('./idl/clmm.json') as Idl;
+import { getTokenProgramForMint, parsePositionData } from './pancakeswap-sol.parser';
export async function buildSwapTransaction(
solana: Solana,
@@ -188,6 +170,32 @@ export async function buildClosePositionTransaction(
return new VersionedTransaction(messageV0);
}
+/**
+ * The instruction that turns a withdrawal's wrapped SOL back into SOL.
+ *
+ * Every route here that takes tokens *out* of a pool — decreasing liquidity, closing a
+ * position, collecting fees — receives the native side as WSOL in the wallet's associated
+ * token account, because that is what the program transfers to. Nothing used to unwrap it,
+ * so a caller closing a SOL position saw their SOL balance move by the rent alone while
+ * the withdrawal sat wrapped in an account no response field mentioned. Every close left
+ * another balance parked there, and the account's own rent with it.
+ *
+ * Closing the account is the unwrap: the lamports, both the wrapped balance and the
+ * account's rent, go back to the owner. The swap path in this same file has always done
+ * this for a native output; the liquidity paths simply never did.
+ *
+ * Returns nothing when neither side of the pool is native, which is the common case.
+ * WSOL is always a legacy SPL mint, so the token program is never in question here.
+ */
+export function buildUnwrapSolInstructions(
+ solana: Solana,
+ walletPubkey: PublicKey,
+ mints: string[],
+): TransactionInstruction[] {
+ const hasNativeSide = mints.some((mint) => mint === NATIVE_MINT.toBase58());
+ return hasNativeSide ? [solana.unwrapSOL(walletPubkey)] : [];
+}
+
export async function buildTransactionWithInstructions(
solana: Solana,
walletPubkey: PublicKey,
@@ -231,6 +239,7 @@ export async function buildRemoveLiquidityTransaction(
liquidityToRemove: BN,
amount0Min: BN,
amount1Min: BN,
+ poolMints: string[],
computeUnits: number = 600000,
priorityFeePerCU?: number,
): Promise {
@@ -259,6 +268,9 @@ export async function buildRemoveLiquidityTransaction(
// Add remove liquidity instruction
instructions.push(removeLiqIx);
+ // What the program just paid out in WSOL, back to SOL.
+ instructions.push(...buildUnwrapSolInstructions(solana, walletPubkey, poolMints));
+
// Get recent blockhash
const { blockhash } = await solana.connection.getLatestBlockhash('confirmed');
@@ -389,7 +401,8 @@ export async function buildOpenPositionTransaction(
amount0Max: BN,
amount1Max: BN,
withMetadata: boolean,
- baseFlag: boolean,
+ baseFlag: boolean | null,
+ liquidity: BN,
computeUnits: number = 800000,
priorityFeePerCU?: number,
): Promise<{ transaction: VersionedTransaction; positionNftMint: Keypair }> {
@@ -470,10 +483,18 @@ export async function buildOpenPositionTransaction(
amount1Max,
withMetadata,
baseFlag,
+ liquidity,
);
instructions.push(openPositionIx);
+ // The deposit now lands below the wrapped maximum rather than exactly on it, so the
+ // difference stays wrapped unless this closes the account. Same instruction the swap
+ // path uses for a native output; it also returns the account's own rent.
+ instructions.push(
+ ...buildUnwrapSolInstructions(solana, walletPubkey, [token0Mint.toBase58(), token1Mint.toBase58()]),
+ );
+
const { blockhash } = await solana.connection.getLatestBlockhash('confirmed');
const messageV0 = new TransactionMessage({
diff --git a/src/connectors/pancakeswap-sol/pancakeswap-sol.ts b/src/connectors/pancakeswap-sol/pancakeswap-sol.ts
index acf01502dc..1bc87d6c57 100644
--- a/src/connectors/pancakeswap-sol/pancakeswap-sol.ts
+++ b/src/connectors/pancakeswap-sol/pancakeswap-sol.ts
@@ -10,6 +10,7 @@ import { logger } from '../../services/logger';
import clmmIdl from './idl/clmm.json';
import { PancakeswapSolConfig } from './pancakeswap-sol.config';
+import { readPendingFees } from './pancakeswap-sol.fees';
import { getAmountsFromLiquidity } from './pancakeswap-sol.math';
import { tickToPrice } from './pancakeswap-sol.parser';
@@ -145,8 +146,13 @@ export class PancakeswapSol {
const tickSpacing = data.readUInt16LE(offset);
offset += 2;
- // Read liquidity (16 bytes, u128) - not currently used but part of data structure
- // const liquidity = data.readBigUInt64LE(offset);
+ // Read liquidity (16 bytes, u128) - the active liquidity at the current tick,
+ // needed for the bin distribution walk
+ const liquidityBytes = data.slice(offset, offset + 16);
+ let liquidityValue = BigInt(0);
+ for (let i = 0; i < 16; i++) {
+ liquidityValue += BigInt(liquidityBytes[i]) << BigInt(i * 8);
+ }
offset += 16;
// Read sqrt_price_x64 (16 bytes, u128)
@@ -260,6 +266,11 @@ export class PancakeswapSol {
(poolInfo as any)._feeGrowthGlobal0 = feeGrowthGlobal0;
(poolInfo as any)._feeGrowthGlobal1 = feeGrowthGlobal1;
(poolInfo as any)._rewardGrowthGlobalX64 = rewardGrowthGlobalX64;
+ // Raw pool state for the bin distribution walk (poolInfo.binStep/activeBinId
+ // carry tickSpacing/tickCurrent already; these carry the rest)
+ (poolInfo as any)._liquidity = liquidityValue;
+ (poolInfo as any)._mintDecimals0 = mintDecimals0;
+ (poolInfo as any)._mintDecimals1 = mintDecimals1;
return poolInfo;
} catch (error) {
@@ -535,11 +546,35 @@ export class PancakeswapSol {
const baseTokenAmount = amounts.amount0;
const quoteTokenAmount = amounts.amount1;
- // TODO: Fix fee and reward calculations for PancakeSwap-Sol
- // Setting to 0 for now to avoid showing incorrect information
- const baseFeeAmount = 0;
- const quoteFeeAmount = 0;
- const cakeRewardAmount = 0;
+ // What a collect would pay out right now. This returned a hardcoded 0 for both
+ // sides, with a TODO reasoning that a wrong number is worse than none — but zero IS
+ // a number and it was being stored, so nothing downstream could tell "this connector
+ // does not compute fees" from "this position earned nothing". A position that sat in
+ // range while the pool traded through it reported 0 throughout, while the
+ // collect-fees route harvested a real amount from it minutes later.
+ //
+ // Everything the calculation needs was already read here and written to logger.debug
+ // before being discarded: the position's checkpoint, the pool's global growth, and
+ // the two boundary ticks (fetched below, decoded with the program's own IDL).
+ const { fee0Raw, fee1Raw } = await readPendingFees(
+ this.solana.connection,
+ manualPoolId,
+ poolInfo.binStep, // tick spacing
+ poolInfo.activeBinId, // current tick
+ poolFeeGrowthGlobal0,
+ poolFeeGrowthGlobal1,
+ {
+ tickLowerIndex,
+ tickUpperIndex,
+ liquidity: BigInt(liquidity.toString()),
+ feeGrowthInside0Last,
+ feeGrowthInside1Last,
+ tokenFeesOwed0,
+ tokenFeesOwed1,
+ },
+ );
+ const baseFeeAmount = Number(fee0Raw) / 10 ** baseTokenInfo.decimals;
+ const quoteFeeAmount = Number(fee1Raw) / 10 ** quoteTokenInfo.decimals;
return {
address: positionAddress,
diff --git a/src/connectors/pancakeswap-sol/schemas.ts b/src/connectors/pancakeswap-sol/schemas.ts
deleted file mode 100644
index bcf2b1924a..0000000000
--- a/src/connectors/pancakeswap-sol/schemas.ts
+++ /dev/null
@@ -1,428 +0,0 @@
-import { Static, Type } from '@sinclair/typebox';
-
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { PancakeswapSolConfig } from './pancakeswap-sol.config';
-
-// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
-
-// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.01;
-const BASE_TOKEN_AMOUNT = 0.01;
-const QUOTE_TOKEN_AMOUNT = 2;
-const LOWER_PRICE_BOUND = 150;
-const UPPER_PRICE_BOUND = 250;
-const CLMM_POOL_ADDRESS_EXAMPLE = '4QU2NpRaqmKMvPSwVKQDeW4V6JFEKJdkzbzdauumD9qN';
-const POSITION_ADDRESS_EXAMPLE = '';
-
-// CLMM Pool Info Request
-export const PancakeswapSolClmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'PancakeSwap CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-export type PancakeswapSolClmmGetPoolInfoRequestType = Static;
-
-// CLMM Open Position Request
-export const PancakeswapSolClmmOpenPositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'PancakeSwap CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapSolConfig.config.slippagePct,
- examples: [PancakeswapSolConfig.config.slippagePct],
- }),
- ),
-});
-
-export type PancakeswapSolClmmOpenPositionRequestType = Static;
-
-// CLMM Create Pool Request
-export const PancakeswapSolClmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create and initialize the pool',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. If omitted, the current market price is fetched from the ' +
- 'unified swap router so the pool opens on-market. No position is opened; only the pool is created.',
- examples: [QUOTE_TOKEN_AMOUNT / BASE_TOKEN_AMOUNT],
- }),
- ),
- ammConfig: Type.String({
- description:
- 'Base58 address of an existing on-chain amm_config account for the desired fee tier. ' +
- 'There is no API to enumerate amm_config accounts, so this must be supplied explicitly. ' +
- 'The pool_state PDA is derived from this config plus the (canonically ordered) token mints.',
- examples: ['E64NGkDLLCdQ2yFNPcavaKptrEgmiQaNykUuLC1Qgwyp'],
- }),
-});
-
-export type PancakeswapSolClmmCreatePoolRequestType = Static;
-
-// CLMM Position Info Request
-export const PancakeswapSolClmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [POSITION_ADDRESS_EXAMPLE],
- }),
-});
-
-export type PancakeswapSolClmmGetPositionInfoRequestType = Static;
-
-// CLMM Get Positions Owned Request
-export const PancakeswapSolClmmGetPositionsOwnedRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.String({
- description: 'Solana wallet address to check for positions',
- examples: [solanaChainConfig.defaultWallet],
- }),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Optional pool address to filter positions by specific pool',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
-});
-
-export type PancakeswapSolClmmGetPositionsOwnedRequestType = Static;
-
-// CLMM Quote Swap Request
-export const PancakeswapSolClmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'CLMM pool address (optional - can be looked up from tokens)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapSolConfig.config.slippagePct,
- examples: [PancakeswapSolConfig.config.slippagePct],
- }),
- ),
-});
-
-export type PancakeswapSolClmmQuoteSwapRequestType = Static;
-
-// CLMM Execute Swap Request
-export const PancakeswapSolClmmExecuteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'CLMM pool address (optional)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapSolConfig.config.slippagePct,
- examples: [PancakeswapSolConfig.config.slippagePct],
- }),
- ),
-});
-
-export type PancakeswapSolClmmExecuteSwapRequestType = Static;
-
-// CLMM Close Position Request
-export const PancakeswapSolClmmClosePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address to close',
- examples: [POSITION_ADDRESS_EXAMPLE],
- }),
-});
-
-export type PancakeswapSolClmmClosePositionRequestType = Static;
-
-// CLMM Remove Liquidity Request
-export const PancakeswapSolClmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address to remove liquidity from',
- examples: [POSITION_ADDRESS_EXAMPLE],
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- examples: [100],
- }),
-});
-
-export type PancakeswapSolClmmRemoveLiquidityRequestType = Static;
-
-// CLMM Collect Fees Request
-export const PancakeswapSolClmmCollectFeesRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [POSITION_ADDRESS_EXAMPLE],
- }),
-});
-
-export type PancakeswapSolClmmCollectFeesRequestType = Static;
-
-// CLMM Add Liquidity Request
-export const PancakeswapSolClmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [POSITION_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapSolConfig.config.slippagePct,
- examples: [PancakeswapSolConfig.config.slippagePct],
- }),
- ),
-});
-
-export type PancakeswapSolClmmAddLiquidityRequestType = Static;
-
-// CLMM Quote Position Request
-export const PancakeswapSolClmmQuotePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...PancakeswapSolConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'PancakeSwap CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapSolConfig.config.slippagePct,
- examples: [PancakeswapSolConfig.config.slippagePct],
- }),
- ),
-});
-
-export type PancakeswapSolClmmQuotePositionRequestType = Static;
diff --git a/src/connectors/pancakeswap/amm-routes/addLiquidity.ts b/src/connectors/pancakeswap/amm-routes/addLiquidity.ts
index b992bfef1a..fc616a158b 100644
--- a/src/connectors/pancakeswap/amm-routes/addLiquidity.ts
+++ b/src/connectors/pancakeswap/amm-routes/addLiquidity.ts
@@ -1,19 +1,17 @@
import { Contract } from '@ethersproject/contracts';
import { Percent } from '@pancakeswap/sdk';
-import { Static } from '@sinclair/typebox';
-import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
+import { BigNumber } from 'ethers';
import { Ethereum } from '../../../chains/ethereum/ethereum';
import { wrapEthereum } from '../../../chains/ethereum/routes/wrap';
-import { AddLiquidityResponseType, AddLiquidityResponse } from '../../../schemas/amm-schema';
+import { AddLiquidityResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
import { IPancakeswapV2Router02ABI } from '../pancakeswap.contracts';
import { formatTokenAmount, getPancakeswapPoolInfo } from '../pancakeswap.utils';
-import { PancakeswapAmmAddLiquidityRequest } from '../schemas';
import { getPancakeswapAmmLiquidityQuote } from './quoteLiquidity';
@@ -30,8 +28,6 @@ async function addLiquidityInternal(
baseTokenAmount: number,
quoteTokenAmount: number,
slippagePct: number = PancakeswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
const networkToUse = network;
@@ -180,8 +176,7 @@ async function addLiquidityInternal(
// Add liquidity Token + ETH
// Convert gasPrice from wei to gwei if provided
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_ADD_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_ADD_LIQUIDITY_GAS_LIMIT);
gasOptions.value = quote.rawQuoteTokenAmount;
tx = await router.addLiquidityETH(
@@ -242,8 +237,7 @@ async function addLiquidityInternal(
// Add liquidity Token + Token
// Convert gasPrice from wei to gwei if provided
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_ADD_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_ADD_LIQUIDITY_GAS_LIMIT);
tx = await router.addLiquidity(
quote.baseTokenObj.address,
@@ -259,19 +253,17 @@ async function addLiquidityInternal(
}
// Wait for transaction confirmation
- const receipt = await ethereum.handleTransactionExecution(tx);
-
- // Calculate gas fee
- const gasFee = formatTokenAmount(
- receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(),
- 18, // ETH has 18 decimals
- );
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the quoted amounts were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ fee: outcome.fee,
baseTokenAmountAdded: quote.baseTokenAmount,
quoteTokenAmountAdded: quote.quoteTokenAmount,
...(baseWrapTxHash && { baseWrapTxHash }),
@@ -291,8 +283,6 @@ export async function addLiquidity(
baseTokenAmount: number,
quoteTokenAmount: number,
slippagePct: number = PancakeswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
const poolInfo = await getPancakeswapPoolInfo(poolAddress, network, 'amm');
if (!poolInfo) throw httpErrors.notFound(`Pool not found: ${poolAddress}`);
@@ -306,92 +296,5 @@ export async function addLiquidity(
baseTokenAmount,
quoteTokenAmount,
slippagePct,
- gasPrice,
- maxGas,
);
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to a Pancakeswap V2 pool',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapAmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- walletAddress: requestedWalletAddress,
- gasPrice,
- maxGas,
- } = request.body;
-
- // Validate essential parameters
- if (!poolAddress || !baseTokenAmount || !quoteTokenAmount) {
- throw fastify.httpErrors.badRequest('Missing required parameters');
- }
-
- const networkToUse = network;
-
- // Get wallet address - either from request or first available
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no wallets found.');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- return await addLiquidity(
- networkToUse,
- walletAddress,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- gasPrice,
- maxGas,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
-
- // Handle specific user-actionable errors
- if (e.message && e.message.includes('Insufficient allowance')) {
- logger.error('Request error:', e);
- throw fastify.httpErrors.badRequest('Invalid request');
- }
-
- // Handle insufficient funds errors
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient ETH balance to pay for gas fees. Please add more ETH to your wallet.',
- );
- }
-
- throw fastify.httpErrors.internalServerError('Failed to add liquidity');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/createPool.ts b/src/connectors/pancakeswap/amm-routes/createPool.ts
index 148caefae9..87f59721d3 100644
--- a/src/connectors/pancakeswap/amm-routes/createPool.ts
+++ b/src/connectors/pancakeswap/amm-routes/createPool.ts
@@ -1,12 +1,11 @@
import { Contract } from '@ethersproject/contracts';
-import { Static } from '@sinclair/typebox';
import { Percent } from '@uniswap/sdk-core';
import { Decimal } from 'decimal.js';
import { BigNumber, constants, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum, TokenInfo } from '../../../chains/ethereum/ethereum';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { PancakeswapConfig } from '../pancakeswap.config';
@@ -18,7 +17,6 @@ import {
getPancakeswapV2RouterAddress,
} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapAmmCreatePoolRequest } from '../schemas';
// Default gas limit for AMM create-pool operations (pair creation + initial mint costs more than a plain add).
// Pancakeswap V2 pools all share a fixed 0.25% swap fee — there is no fee parameter to set.
@@ -54,10 +52,10 @@ async function fetchMarketPrice(
quoteToken: string,
amount: number,
): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
+ quote = await getSwapQuote(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to seed the pool (${e.message}). ` +
@@ -80,8 +78,6 @@ export async function createPool(
baseTokenAmount: number,
quoteTokenAmount?: number,
initialPrice?: number,
- gasPrice?: number,
- maxGas?: number,
slippagePct: number = PancakeswapConfig.config.slippagePct,
): Promise {
if (baseTokenAmount <= 0) {
@@ -178,10 +174,6 @@ export async function createPool(
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- // gasPrice arrives already in gwei (the unit prepareGasOptions expects). The connector's Fastify
- // route accepts gasPrice as a wei string (sibling shape) and converts it to gwei before calling.
- const gasPriceGwei = gasPrice;
-
let tx;
if (baseIsEth || quoteIsEth) {
// One side is ETH/WETH → addLiquidityETH. The ERC20 side needs an allowance to the router; the
@@ -204,7 +196,7 @@ export async function createPool(
);
}
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_CREATE_POOL_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_CREATE_POOL_GAS_LIMIT);
gasOptions.value = ethRawAmount;
tx = await router.addLiquidityETH(
@@ -248,7 +240,7 @@ export async function createPool(
);
}
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_CREATE_POOL_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_CREATE_POOL_GAS_LIMIT);
tx = await router.addLiquidity(
baseTokenInfo.address,
@@ -265,118 +257,32 @@ export async function createPool(
logger.info(`Creating Pancakeswap V2 pool ${baseTokenInfo.symbol}/${quoteTokenInfo.symbol} via tx ${tx.hash}`);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ // A revert throws out of here (400 TRANSACTION_FAILED) — it is never reported as PENDING.
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
// Read the (now-created) pair address from the factory — authoritative source of the pool address.
const pairAddress: string = await factory.getPair(baseTokenInfo.address, quoteTokenInfo.address);
- if (receipt && receipt.status === 1) {
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18); // ETH has 18 decimals
+ if (!outcome.confirmed) {
+ // Timed out but still broadcasting — report PENDING with the tx hash so the caller can
+ // reconcile it. The seed amounts below have not moved, so they are deliberately omitted.
return {
- signature: receipt.transactionHash,
- status: 1, // CONFIRMED
+ signature: outcome.signature,
+ status: TransactionStatus.PENDING,
poolAddress: pairAddress,
price: seedPrice,
- data: {
- fee: gasFee,
- baseTokenAmountAdded: baseTokenAmount,
- quoteTokenAmountAdded: effectiveQuoteAmount,
- },
};
}
- // Timed out (still broadcasting) or reverted — report as pending with the tx hash.
return {
- signature: receipt ? receipt.transactionHash : tx.hash,
- status: 0, // PENDING
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
poolAddress: pairAddress,
price: seedPrice,
+ data: {
+ fee: outcome.fee,
+ baseTokenAmountAdded: baseTokenAmount,
+ quoteTokenAmountAdded: effectiveQuoteAmount,
+ },
};
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description: 'Create a new Pancakeswap V2 (AMM) pool and seed it with initial liquidity (fixed 0.25% fee)',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapAmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- slippagePct,
- gasPrice,
- maxGas,
- walletAddress: requestedWalletAddress,
- } = request.body;
-
- if (!baseToken || !quoteToken || !baseTokenAmount) {
- throw fastify.httpErrors.badRequest('Missing required parameters');
- }
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no wallets found.');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- // Route accepts gasPrice as a wei string (matching sibling AMM requests); createPool expects gwei.
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
-
- return await createPool(
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- gasPriceGwei,
- maxGas,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
-
- if (e.message && e.message.includes('Insufficient allowance')) {
- throw fastify.httpErrors.badRequest(e.message);
- }
- if (e.message && e.message.includes('already exists')) {
- throw fastify.httpErrors.badRequest(e.message);
- }
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient native balance to pay for gas fees. Please add more funds to your wallet.',
- );
- }
-
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/executeSwap.ts b/src/connectors/pancakeswap/amm-routes/executeSwap.ts
index a0a2584c0a..f6e443e5d4 100644
--- a/src/connectors/pancakeswap/amm-routes/executeSwap.ts
+++ b/src/connectors/pancakeswap/amm-routes/executeSwap.ts
@@ -1,17 +1,15 @@
import { BigNumber, Contract, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
-import { Ethereum } from '../../../chains/ethereum/ethereum';
+import { Ethereum, EthereumTransactionOutcome } from '../../../chains/ethereum/ethereum';
import { EthereumLedger } from '../../../chains/ethereum/ethereum-ledger';
-import { getEthereumChainConfig } from '../../../chains/ethereum/ethereum.config';
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
import { getPancakeswapV2RouterAddress, IPancakeswapV2Router02ABI } from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapAmmExecuteSwapRequest } from '../schemas';
import { resolveSwapPair } from './poolTokens';
import { getPancakeswapAmmQuote } from './quoteSwap';
@@ -94,7 +92,7 @@ export async function executeAmmSwap(
// Prepare transaction parameters
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- let receipt;
+ let outcome: EthereumTransactionOutcome;
try {
if (isHardwareWallet) {
@@ -159,7 +157,7 @@ export async function executeAmmSwap(
logger.info(`Transaction sent: ${txResponse.hash}`);
// Wait for confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(txResponse);
+ outcome = await ethereum.handleTransactionConfirmation(txResponse);
} else {
// Regular wallet flow
let wallet;
@@ -216,19 +214,18 @@ export async function executeAmmSwap(
logger.info(`Transaction sent: ${tx.hash}`);
// Wait for transaction confirmation
- receipt = await ethereum.handleTransactionExecution(tx);
+ outcome = await ethereum.handleTransactionConfirmation(tx);
}
- // Check if the transaction was successful
- if (receipt.status === 0) {
- logger.error(`Transaction failed on-chain. Receipt: ${JSON.stringify(receipt)}`);
- throw httpErrors.internalServerError(
- 'Transaction reverted on-chain. This could be due to slippage, insufficient funds, or other blockchain issues.',
- );
+ // A revert threw out of the confirmation helper as a 400 TRANSACTION_FAILED. What is left
+ // is a transaction that is still pending after the extended poll: report it as PENDING
+ // with its hash rather than dereferencing a null receipt and losing the hash to a 500.
+ if (!outcome.confirmed) {
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
}
- logger.info(`Transaction confirmed: ${receipt.transactionHash}`);
- logger.info(`Gas used: ${receipt.gasUsed.toString()}`);
+ logger.info(`Transaction confirmed: ${outcome.signature}`);
+ logger.info(`Gas used: ${outcome.receipt.gasUsed.toString()}`);
// Calculate amounts using quote values
const amountIn = quote.estimatedAmountIn;
@@ -238,27 +235,22 @@ export async function executeAmmSwap(
const baseTokenBalanceChange = side === 'BUY' ? amountOut : -amountIn;
const quoteTokenBalanceChange = side === 'BUY' ? -amountIn : amountOut;
- // Calculate gas fee (formatTokenAmount already returns a number)
- const gasFee = formatTokenAmount(
- receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(),
- 18, // ETH has 18 decimals
- );
-
// Determine token addresses for computed fields
const tokenIn = quote.inputToken.address;
const tokenOut = quote.outputToken.address;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
tokenIn,
tokenOut,
amountIn,
amountOut,
- fee: gasFee,
+ fee: outcome.fee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
} catch (error) {
@@ -286,51 +278,6 @@ export async function executeAmmSwap(
}
}
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on Pancakeswap V2 AMM using Router02',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapAmmExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const ethereumConfig = getEthereumChainConfig();
- const {
- walletAddress = ethereumConfig.defaultWallet,
- network = ethereumConfig.defaultNetwork,
- baseToken,
- quoteToken,
- amount,
- side = 'SELL',
- slippagePct,
- } = request.body as typeof PancakeswapAmmExecuteSwapRequest._type;
-
- return await executeAmmSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken || '', // Handle optional quoteToken
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
/**
* Standard AMM execute-swap entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. The quote token is derived from the pool; `amount` is denominated in the base token.
@@ -347,5 +294,3 @@ export async function executeSwap(
const { baseAddress, quoteAddress } = await resolveSwapPair(network, poolAddress, baseToken);
return await executeAmmSwap(walletAddress, network, baseAddress, quoteAddress, amount, side, slippagePct);
}
-
-export default executeSwapRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/index.ts b/src/connectors/pancakeswap/amm-routes/index.ts
deleted file mode 100644
index 2819290e8d..0000000000
--- a/src/connectors/pancakeswap/amm-routes/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import addLiquidityRoute from './addLiquidity';
-import createPoolRoute from './createPool';
-import executeSwapRoute from './executeSwap';
-import poolInfoRoute from './poolInfo';
-import positionInfoRoute from './positionInfo';
-import quoteLiquidityRoute from './quoteLiquidity';
-import quoteSwapRoute from './quoteSwap';
-import removeLiquidityRoute from './removeLiquidity';
-
-export const pancakeswapAmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(quoteLiquidityRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(createPoolRoute);
-};
-
-export default pancakeswapAmmRoutes;
diff --git a/src/connectors/pancakeswap/amm-routes/poolInfo.ts b/src/connectors/pancakeswap/amm-routes/poolInfo.ts
index 29474d6d18..773a79aa8e 100644
--- a/src/connectors/pancakeswap/amm-routes/poolInfo.ts
+++ b/src/connectors/pancakeswap/amm-routes/poolInfo.ts
@@ -1,14 +1,11 @@
import { Contract } from '@ethersproject/contracts';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/amm-schema';
+import { PoolInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { IPancakeswapV2PairABI } from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapAmmGetPoolInfoRequest } from '../schemas';
/**
* Standard AMM pool-info accessor: given a network and a Pancakeswap V2 pool (pair) address, returns
@@ -57,48 +54,3 @@ export async function getPoolInfo(network: string, poolAddress: string): Promise
quoteTokenAmount,
};
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: Record;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get AMM pool information from Pancakeswap V2',
- tags: ['/connector/pancakeswap'],
- querystring: PancakeswapAmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, network } = request.query;
- return await getPoolInfo(network, poolAddress);
- } catch (e) {
- logger.error(`Error in pool-info route: ${e.message}`);
- if (e.stack) {
- logger.debug(`Stack trace: ${e.stack}`);
- }
-
- // Return appropriate error based on the error message
- if (e.statusCode) {
- throw e; // Already a formatted Fastify error
- } else if (e.message && e.message.includes('invalid address')) {
- throw fastify.httpErrors.badRequest(`Invalid pool address`);
- } else if (e.message && e.message.includes('not found')) {
- logger.error('Not found error:', e);
- throw fastify.httpErrors.notFound('Resource not found');
- } else {
- logger.error('Unexpected error fetching pool info:', e);
- throw fastify.httpErrors.internalServerError('Failed to fetch pool info');
- }
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/positionInfo.ts b/src/connectors/pancakeswap/amm-routes/positionInfo.ts
index d63e176926..bf268f92dd 100644
--- a/src/connectors/pancakeswap/amm-routes/positionInfo.ts
+++ b/src/connectors/pancakeswap/amm-routes/positionInfo.ts
@@ -1,16 +1,9 @@
import { Contract } from '@ethersproject/contracts';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- GetPositionInfoRequestType,
- GetPositionInfoRequest,
- PositionInfo,
- PositionInfoSchema,
-} from '../../../schemas/amm-schema';
+import { PositionInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { IPancakeswapV2PairABI } from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
@@ -97,142 +90,3 @@ export async function checkLPAllowance(
);
}
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get position information for a Pancakeswap V2 pool',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...GetPositionInfoRequest,
- properties: {
- network: { type: 'string', default: 'base' },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- poolAddress: {
- type: 'string',
- examples: [''],
- },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- },
- },
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, walletAddress: requestedWalletAddress } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (!poolAddress) {
- throw fastify.httpErrors.badRequest('Pool address is required');
- }
-
- // Get Pancakeswap and Ethereum instances
- const pancakeswap = await Pancakeswap.getInstance(networkToUse);
- const ethereum = await Ethereum.getInstance(networkToUse);
-
- // Get wallet address - either from request or first available
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- // Get the pair contract
- const pairContract = new Contract(poolAddress, IPancakeswapV2PairABI.abi, ethereum.provider);
-
- // Get LP token balance for the wallet
- const lpBalance = await pairContract.balanceOf(walletAddress);
-
- // Get token addresses from the pair
- const [token0, token1] = await Promise.all([pairContract.token0(), pairContract.token1()]);
-
- // Get token objects by address
- const baseTokenObj = await pancakeswap.getToken(token0);
- const quoteTokenObj = await pancakeswap.getToken(token1);
-
- if (!baseTokenObj || !quoteTokenObj) {
- throw fastify.httpErrors.badRequest('Token information not found for pool');
- }
-
- // If no position, return early
- if (lpBalance.isZero()) {
- return {
- poolAddress,
- walletAddress,
- baseTokenAddress: baseTokenObj.address,
- quoteTokenAddress: quoteTokenObj.address,
- lpTokenAmount: 0,
- baseTokenAmount: 0,
- quoteTokenAmount: 0,
- price: 0,
- };
- }
-
- // Get total supply and reserves
- const [totalSupply, reserves] = await Promise.all([pairContract.totalSupply(), pairContract.getReserves()]);
-
- // Determine which token is base and which is quote
- const token0IsBase = token0.toLowerCase() === baseTokenObj.address.toLowerCase();
-
- // Calculate token amounts
- const baseTokenReserve = token0IsBase ? reserves[0] : reserves[1];
- const quoteTokenReserve = token0IsBase ? reserves[1] : reserves[0];
-
- const userBaseTokenAmount = baseTokenReserve.mul(lpBalance).div(totalSupply);
- const userQuoteTokenAmount = quoteTokenReserve.mul(lpBalance).div(totalSupply);
-
- // Calculate price (quoteToken per baseToken)
- const baseTokenAmountFloat = formatTokenAmount(baseTokenReserve.toString(), baseTokenObj.decimals);
- const quoteTokenAmountFloat = formatTokenAmount(quoteTokenReserve.toString(), quoteTokenObj.decimals);
- const price = quoteTokenAmountFloat / baseTokenAmountFloat;
-
- // Format for response
- logger.info(`Raw LP balance: ${lpBalance.toString()}`);
- logger.info(`Total supply: ${totalSupply.toString()}`);
-
- const formattedLpAmount = formatTokenAmount(lpBalance.toString(), 18); // LP tokens have 18 decimals
- const formattedBaseAmount = formatTokenAmount(userBaseTokenAmount.toString(), baseTokenObj.decimals);
- const formattedQuoteAmount = formatTokenAmount(userQuoteTokenAmount.toString(), quoteTokenObj.decimals);
-
- logger.info(`Formatted LP amount: ${formattedLpAmount}`);
- logger.info(`Formatted base amount: ${formattedBaseAmount}`);
- logger.info(`Formatted quote amount: ${formattedQuoteAmount}`);
-
- return {
- poolAddress,
- walletAddress,
- baseTokenAddress: baseTokenObj.address,
- quoteTokenAddress: quoteTokenObj.address,
- lpTokenAmount: formattedLpAmount,
- baseTokenAmount: formattedBaseAmount,
- quoteTokenAmount: formattedQuoteAmount,
- price,
- };
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to get position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/quoteLiquidity.ts b/src/connectors/pancakeswap/amm-routes/quoteLiquidity.ts
index b58eea303a..0e8a2f80e6 100644
--- a/src/connectors/pancakeswap/amm-routes/quoteLiquidity.ts
+++ b/src/connectors/pancakeswap/amm-routes/quoteLiquidity.ts
@@ -1,18 +1,12 @@
import { Contract } from '@ethersproject/contracts';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- QuoteLiquidityRequestType,
- QuoteLiquidityRequest,
- QuoteLiquidityResponseType,
- QuoteLiquidityResponse,
-} from '../../../schemas/amm-schema';
+import { QuoteLiquidityResponseType } from '../../../schemas/amm-schema';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { IPancakeswapV2PairABI, getPancakeswapV2RouterAddress } from '../pancakeswap.contracts';
-import { formatTokenAmount, getPancakeswapPoolInfo } from '../pancakeswap.utils';
+import { formatTokenAmount } from '../pancakeswap.utils';
import { getAmmPoolTokens } from './poolTokens';
@@ -82,7 +76,7 @@ export async function getPancakeswapAmmLiquidityQuote(
const pairContract = new Contract(poolAddressToUse, IPancakeswapV2PairABI.abi, ethereum.provider);
// Get token addresses and reserves
- const [token0, token1, reserves] = await Promise.all([
+ const [token0, , reserves] = await Promise.all([
pairContract.token0(),
pairContract.token1(),
pairContract.getReserves(),
@@ -175,87 +169,6 @@ export async function getPancakeswapAmmLiquidityQuote(
};
}
-export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- fastify.get<{
- Querystring: QuoteLiquidityRequestType;
- Reply: QuoteLiquidityResponseType;
- }>(
- '/quote-liquidity',
- {
- schema: {
- description: 'Get liquidity quote for a Pancakeswap V2 pool',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...QuoteLiquidityRequest,
- properties: {
- ...QuoteLiquidityRequest.properties,
- network: { type: 'string', default: 'base' },
- poolAddress: {
- type: 'string',
- examples: [''],
- },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- baseTokenAmount: { type: 'number', examples: [0.001] },
- quoteTokenAmount: { type: 'number', examples: [2.5] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: {
- 200: QuoteLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct } = request.query;
-
- if (!poolAddress) {
- throw fastify.httpErrors.badRequest('Pool address is required');
- }
-
- // Get pool information to determine tokens
- const poolInfo = await getPancakeswapPoolInfo(poolAddress, network, 'amm');
- if (!poolInfo) {
- throw fastify.httpErrors.notFound(`Pool not found: ${poolAddress}`);
- }
-
- const baseToken = poolInfo.baseTokenAddress;
- const quoteToken = poolInfo.quoteTokenAddress;
-
- const quote = await getPancakeswapAmmLiquidityQuote(
- network,
- poolAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
-
- // Use standard gas limit for liquidity operations
- const computeUnits = 500000;
-
- return {
- baseLimited: quote.baseLimited,
- baseTokenAmount: quote.baseTokenAmount,
- quoteTokenAmount: quote.quoteTokenAmount,
- baseTokenAmountMax: quote.baseTokenAmountMax,
- quoteTokenAmountMax: quote.quoteTokenAmountMax,
- computeUnits,
- };
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to get liquidity quote');
- }
- },
- );
-};
-
/**
* Standard AMM quote-liquidity entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. Base/quote follow the pair's token0/token1 orientation.
@@ -285,5 +198,3 @@ export async function quoteLiquidity(
quoteTokenAmountMax: q.quoteTokenAmountMax,
};
}
-
-export default quoteLiquidityRoute;
diff --git a/src/connectors/pancakeswap/amm-routes/quoteSwap.ts b/src/connectors/pancakeswap/amm-routes/quoteSwap.ts
index 0533675f01..9b6bf02a94 100644
--- a/src/connectors/pancakeswap/amm-routes/quoteSwap.ts
+++ b/src/connectors/pancakeswap/amm-routes/quoteSwap.ts
@@ -1,20 +1,14 @@
import { Token, CurrencyAmount, Percent, TradeType } from '@pancakeswap/sdk';
import { Route as V2Route, Trade as V2Trade } from '@pancakeswap/v2-sdk';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- QuoteSwapRequestType,
- QuoteSwapResponseType,
- QuoteSwapRequest,
- QuoteSwapResponse,
-} from '../../../schemas/amm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
-import { formatTokenAmount, getPancakeswapPoolInfo } from '../pancakeswap.utils';
+import { formatTokenAmount } from '../pancakeswap.utils';
import { resolveSwapPair } from './poolTokens';
@@ -266,144 +260,6 @@ async function formatSwapQuote(
}
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- // Import the httpErrors plugin to ensure it's available
- await fastify.register(require('@fastify/sensible'));
-
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Pancakeswap V2 AMM',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...QuoteSwapRequest,
- properties: {
- ...QuoteSwapRequest.properties,
- network: { type: 'string', default: 'base' },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- amount: { type: 'number', examples: [0.001] },
- side: { type: 'string', enum: ['BUY', 'SELL'], examples: ['SELL'] },
- poolAddress: { type: 'string', examples: [''] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: { 200: QuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseToken, quoteToken, amount, side, slippagePct } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (!baseToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, amount, and side are required');
- }
-
- const pancakeswap = await Pancakeswap.getInstance(networkToUse);
-
- let poolAddressToUse = poolAddress;
- let baseTokenToUse: string;
- let quoteTokenToUse: string;
-
- if (poolAddressToUse) {
- // Pool address provided, get pool info to determine tokens
- const poolInfo = await getPancakeswapPoolInfo(poolAddressToUse, networkToUse, 'amm');
- if (!poolInfo) {
- throw httpErrors.notFound(`Pool not found: ${poolAddressToUse}`);
- }
-
- // Determine which token is base and which is quote based on the provided baseToken
- if (baseToken === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (baseToken === poolInfo.quoteTokenAddress) {
- // User specified the quote token as base, so swap them
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- // Try to resolve baseToken as symbol to address
- const resolvedToken = await pancakeswap.getToken(baseToken);
-
- if (resolvedToken) {
- if (resolvedToken.address === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (resolvedToken.address === poolInfo.quoteTokenAddress) {
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- }
- } else {
- // No pool address provided, need quoteToken to find pool
- if (!quoteToken) {
- throw httpErrors.badRequest('quoteToken is required when poolAddress is not provided');
- }
-
- baseTokenToUse = baseToken;
- quoteTokenToUse = quoteToken;
-
- // Find pool using findDefaultPool
- poolAddressToUse = await pancakeswap.findDefaultPool(baseTokenToUse, quoteTokenToUse, 'amm');
-
- if (!poolAddressToUse) {
- throw httpErrors.notFound(`No AMM pool found for pair ${baseTokenToUse}-${quoteTokenToUse}`);
- }
- }
-
- return await formatSwapQuote(
- networkToUse,
- poolAddressToUse,
- baseTokenToUse,
- quoteTokenToUse,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- logger.error(`Error in quote-swap route: ${e.message}`);
-
- // If it's already a Fastify HTTP error, re-throw it
- if (e.statusCode) {
- throw e;
- }
-
- // Check for specific error types
- if (e.message?.includes('Insufficient liquidity')) {
- logger.error('Request error:', e);
- throw httpErrors.badRequest('Invalid request');
- }
- if (e.message?.includes('Pool not found') || e.message?.includes('No AMM pool found')) {
- logger.error('Pool not found error:', e);
- throw httpErrors.notFound(e.message || 'Pool not found');
- }
- if (e.message?.includes('token not found')) {
- logger.error('Request error:', e);
- throw httpErrors.badRequest('Invalid request');
- }
-
- // Default to internal server error
- logger.error('Unexpected error getting swap quote:', e);
- logger.error('Error stack:', e.stack);
- throw httpErrors.internalServerError(e.message || 'Error getting swap quote');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Standard AMM quote-swap entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. `amount` is denominated in the base token; the quote token is derived from the pool.
diff --git a/src/connectors/pancakeswap/amm-routes/removeLiquidity.ts b/src/connectors/pancakeswap/amm-routes/removeLiquidity.ts
index f50da1bfd2..6830af646e 100644
--- a/src/connectors/pancakeswap/amm-routes/removeLiquidity.ts
+++ b/src/connectors/pancakeswap/amm-routes/removeLiquidity.ts
@@ -1,13 +1,10 @@
import { Contract } from '@ethersproject/contracts';
import { Percent } from '@pancakeswap/sdk';
-import { Static } from '@sinclair/typebox';
-import { utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { RemoveLiquidityResponseType, RemoveLiquidityResponse } from '../../../schemas/amm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
import {
@@ -16,7 +13,6 @@ import {
IPancakeswapV2PairABI,
} from '../pancakeswap.contracts';
import { formatTokenAmount, getPancakeswapPoolInfo } from '../pancakeswap.utils';
-import { PancakeswapAmmRemoveLiquidityRequest } from '../schemas';
import { checkLPAllowance } from './positionInfo';
@@ -33,8 +29,6 @@ export async function removeLiquidity(
poolAddress: string,
percentageToRemove: number,
slippagePct: number = PancakeswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
if (!poolAddress || !percentageToRemove) throw httpErrors.badRequest('Missing required parameters');
if (percentageToRemove <= 0 || percentageToRemove > 100) {
@@ -89,8 +83,7 @@ export async function removeLiquidity(
await checkLPAllowance(ethereum, wallet, poolAddress, routerAddress, liquidityToRemove);
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_REMOVE_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_REMOVE_LIQUIDITY_GAS_LIMIT);
let tx;
if (baseTokenObj.symbol === 'WETH') {
@@ -126,81 +119,22 @@ export async function removeLiquidity(
);
}
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the expected amounts were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
+
const baseTokenAmountRemoved = formatTokenAmount(expectedBaseTokenAmount.toString(), baseTokenObj.decimals);
const quoteTokenAmountRemoved = formatTokenAmount(expectedQuoteTokenAmount.toString(), quoteTokenObj.decimals);
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ fee: outcome.fee,
baseTokenAmountRemoved,
quoteTokenAmountRemoved,
},
};
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a Pancakeswap V2 pool',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapAmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- poolAddress,
- percentageToRemove,
- walletAddress: requestedWalletAddress,
- gasPrice,
- maxGas,
- } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- return await removeLiquidity(
- network,
- walletAddress,
- poolAddress,
- percentageToRemove,
- undefined,
- gasPrice,
- maxGas,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient ETH balance to pay for gas fees. Please add more ETH to your wallet.',
- );
- }
- throw fastify.httpErrors.internalServerError('Failed to remove liquidity');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/addLiquidity.ts b/src/connectors/pancakeswap/clmm-routes/addLiquidity.ts
index 430235e0c2..0e0c76e8e5 100644
--- a/src/connectors/pancakeswap/clmm-routes/addLiquidity.ts
+++ b/src/connectors/pancakeswap/clmm-routes/addLiquidity.ts
@@ -1,19 +1,20 @@
import { Contract } from '@ethersproject/contracts';
import { CurrencyAmount, Percent } from '@pancakeswap/sdk';
-import { Position, NonfungiblePositionManager } from '@pancakeswap/v3-sdk';
-import { Static } from '@sinclair/typebox';
+import { Position, NonfungiblePositionManager, computePoolAddress } from '@pancakeswap/v3-sdk';
import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { AddLiquidityResponseType, AddLiquidityResponse } from '../../../schemas/clmm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { AddLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
-import { getPancakeswapV3NftManagerAddress, POSITION_MANAGER_ABI } from '../pancakeswap.contracts';
+import {
+ getPancakeswapV3NftManagerAddress,
+ POSITION_MANAGER_ABI,
+ getPancakeswapV3PoolDeployerAddress,
+} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapClmmAddLiquidityRequest } from '../schemas';
// Default gas limit for CLMM add liquidity operations
const CLMM_ADD_LIQUIDITY_GAS_LIMIT = 600000;
@@ -43,6 +44,16 @@ export async function addLiquidity(
const token0 = await pancakeswap.getToken(position.token0);
const token1 = await pancakeswap.getToken(position.token1);
+
+ // The pool this position belongs to, derived from the same inputs position-info
+ // uses. The unified route is position-addressed and never receives a pool, so
+ // deriving it here is what lets the response name the venue it acted on.
+ const poolAddress = computePoolAddress({
+ deployerAddress: getPancakeswapV3PoolDeployerAddress(network),
+ tokenA: token0,
+ tokenB: token1,
+ fee: position.fee,
+ });
const fee = position.fee;
const tickLower = position.tickLower;
const tickUpper = position.tickUpper;
@@ -157,9 +168,12 @@ export async function addLiquidity(
const txParams = await ethereum.prepareGasOptions(undefined, CLMM_ADD_LIQUIDITY_GAS_LIMIT);
txParams.value = BigNumber.from(value.toString());
const tx = await positionManagerWithSigner.multicall([calldata], txParams);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the mint amounts below were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
const actualToken0Amount = formatTokenAmount(newPosition.mintAmounts.amount0.toString(), token0.decimals);
const actualToken1Amount = formatTokenAmount(newPosition.mintAmounts.amount1.toString(), token1.decimals);
@@ -167,69 +181,13 @@ export async function addLiquidity(
const actualQuoteAmount = isBaseToken0 ? actualToken1Amount : actualToken0Amount;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ poolAddress,
+ fee: outcome.fee,
baseTokenAmountAdded: actualBaseAmount,
quoteTokenAmountAdded: actualQuoteAmount,
},
};
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to an existing Pancakeswap V3 position',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapClmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress: requestedWalletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- const pancakeswap = await Pancakeswap.getInstance(network);
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- }
-
- return await addLiquidity(
- network,
- walletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Failed to add liquidity:', e);
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to add liquidity');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/closePosition.ts b/src/connectors/pancakeswap/clmm-routes/closePosition.ts
index 1fcbdd567b..080b222ce0 100644
--- a/src/connectors/pancakeswap/clmm-routes/closePosition.ts
+++ b/src/connectors/pancakeswap/clmm-routes/closePosition.ts
@@ -1,21 +1,21 @@
import { Contract } from '@ethersproject/contracts';
import { Percent, CurrencyAmount } from '@pancakeswap/sdk';
-import { NonfungiblePositionManager, Position } from '@pancakeswap/v3-sdk';
+import { NonfungiblePositionManager, Position, computePoolAddress } from '@pancakeswap/v3-sdk';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Address } from 'viem';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- ClosePositionRequestType,
- ClosePositionRequest,
- ClosePositionResponseType,
- ClosePositionResponse,
-} from '../../../schemas/clmm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { ClosePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { slippageBasisPoints } from '../../evm-slippage';
import { Pancakeswap } from '../pancakeswap';
-import { POSITION_MANAGER_ABI, getPancakeswapV3NftManagerAddress } from '../pancakeswap.contracts';
+import { PancakeswapConfig } from '../pancakeswap.config';
+import {
+ POSITION_MANAGER_ABI,
+ getPancakeswapV3NftManagerAddress,
+ getPancakeswapV3PoolDeployerAddress,
+} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
// Default gas limit for CLMM close position operations
@@ -25,6 +25,7 @@ export async function closePosition(
network: string,
walletAddress: string,
positionAddress: string,
+ slippagePct: number = PancakeswapConfig.config.slippagePct,
): Promise {
if (!positionAddress) {
throw httpErrors.badRequest('Missing required parameters');
@@ -54,6 +55,16 @@ export async function closePosition(
const token0 = await pancakeswap.getToken(position.token0);
const token1 = await pancakeswap.getToken(position.token1);
+ // The pool this position belongs to, derived from the same inputs position-info
+ // uses. The unified route is position-addressed and never receives a pool, so
+ // deriving it here is what lets the response name the venue it acted on.
+ const poolAddress = computePoolAddress({
+ deployerAddress: getPancakeswapV3PoolDeployerAddress(network),
+ tokenA: token0,
+ tokenB: token1,
+ fee: position.fee,
+ });
+
const isBaseToken0 =
token0.symbol === 'WETH' ||
(token1.symbol !== 'WETH' && token0.address.toLowerCase() < token1.address.toLowerCase());
@@ -82,7 +93,10 @@ export async function closePosition(
const amount0 = positionSDK.amount0;
const amount1 = positionSDK.amount1;
- const slippageTolerance = new Percent(100, 10000);
+ // The caller's tolerance, or the connector's configured one — not a literal. This was
+ // `new Percent(100, 10000)`, a flat 1% that ignored both, so an operator who had widened
+ // slippagePct for a volatile pair got 1% anyway and a revert that cost gas.
+ const slippageTolerance = new Percent(slippageBasisPoints(slippagePct), 10000);
const totalAmount0 = CurrencyAmount.fromRawAmount(token0, BigInt(amount0.quotient) + BigInt(feeAmount0.toString()));
const totalAmount1 = CurrencyAmount.fromRawAmount(token1, BigInt(amount1.quotient) + BigInt(feeAmount1.toString()));
@@ -119,9 +133,12 @@ export async function closePosition(
const txParams = await ethereum.prepareGasOptions(undefined, CLMM_CLOSE_POSITION_GAS_LIMIT);
txParams.value = BigNumber.from(value.toString());
const tx = await positionManagerWithSigner.multicall([calldata], txParams);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the amounts below were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
const token0AmountRemoved = formatTokenAmount(totalAmount0.quotient.toString(), token0.decimals);
const token1AmountRemoved = formatTokenAmount(totalAmount1.quotient.toString(), token1.decimals);
@@ -137,10 +154,11 @@ export async function closePosition(
const positionRentRefunded = 0;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ poolAddress,
+ fee: outcome.fee,
positionRentRefunded,
baseTokenAmountRemoved,
quoteTokenAmountRemoved,
@@ -149,46 +167,3 @@ export async function closePosition(
},
};
}
-
-export const closePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ClosePositionRequestType;
- Reply: ClosePositionResponseType;
- }>(
- '/close-position',
- {
- schema: {
- description: 'Close a Pancakeswap V3 position by removing all liquidity and collecting fees',
- tags: ['/connector/pancakeswap'],
- body: ClosePositionRequest,
- response: {
- 200: ClosePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress: requestedWalletAddress, positionAddress } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- const pancakeswap = await Pancakeswap.getInstance(network);
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- }
-
- return await closePosition(network, walletAddress, positionAddress);
- } catch (e: any) {
- logger.error('Failed to close position:', e);
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to close position');
- }
- },
- );
-};
-
-export default closePositionRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/collectFees.ts b/src/connectors/pancakeswap/clmm-routes/collectFees.ts
index 7366604a0b..42c2f91efd 100644
--- a/src/connectors/pancakeswap/clmm-routes/collectFees.ts
+++ b/src/connectors/pancakeswap/clmm-routes/collectFees.ts
@@ -1,21 +1,19 @@
import { Contract } from '@ethersproject/contracts';
import { CurrencyAmount } from '@pancakeswap/sdk';
-import { NonfungiblePositionManager } from '@pancakeswap/v3-sdk';
+import { NonfungiblePositionManager, computePoolAddress } from '@pancakeswap/v3-sdk';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Address } from 'viem';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- CollectFeesRequestType,
- CollectFeesRequest,
- CollectFeesResponseType,
- CollectFeesResponse,
-} from '../../../schemas/clmm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { CollectFeesResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
-import { POSITION_MANAGER_ABI, getPancakeswapV3NftManagerAddress } from '../pancakeswap.contracts';
+import {
+ POSITION_MANAGER_ABI,
+ getPancakeswapV3NftManagerAddress,
+ getPancakeswapV3PoolDeployerAddress,
+} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
// Default gas limit for CLMM collect fees operations
@@ -54,6 +52,16 @@ export async function collectFees(
const token0 = await pancakeswap.getToken(position.token0);
const token1 = await pancakeswap.getToken(position.token1);
+ // The pool this position belongs to, derived from the same inputs position-info
+ // uses. The unified route is position-addressed and never receives a pool, so
+ // deriving it here is what lets the response name the venue it acted on.
+ const poolAddress = computePoolAddress({
+ deployerAddress: getPancakeswapV3PoolDeployerAddress(network),
+ tokenA: token0,
+ tokenB: token1,
+ fee: position.fee,
+ });
+
const isBaseToken0 =
token0.symbol === 'WETH' ||
(token1.symbol !== 'WETH' && token0.address.toLowerCase() < token1.address.toLowerCase());
@@ -94,9 +102,12 @@ export async function collectFees(
const txParams = await ethereum.prepareGasOptions(undefined, CLMM_COLLECT_FEES_GAS_LIMIT);
txParams.value = BigNumber.from(value.toString());
const tx = await positionManagerWithSigner.multicall([calldata], txParams);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the fee amounts below were read before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
const token0FeeAmount = formatTokenAmount(feeAmount0.toString(), token0.decimals);
const token1FeeAmount = formatTokenAmount(feeAmount1.toString(), token1.decimals);
@@ -104,70 +115,13 @@ export async function collectFees(
const quoteFeeAmountCollected = isBaseToken0 ? token1FeeAmount : token0FeeAmount;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ poolAddress,
+ fee: outcome.fee,
baseFeeAmountCollected,
quoteFeeAmountCollected,
},
};
}
-
-export const collectFeesRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.post<{
- Body: CollectFeesRequestType;
- Reply: CollectFeesResponseType;
- }>(
- '/collect-fees',
- {
- schema: {
- description: 'Collect fees from a Pancakeswap V3 position',
- tags: ['/connector/pancakeswap'],
- body: {
- ...CollectFeesRequest,
- properties: {
- ...CollectFeesRequest.properties,
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- positionAddress: {
- type: 'string',
- description: 'Position NFT token ID',
- examples: ['1234'],
- },
- },
- },
- response: {
- 200: CollectFeesResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress: requestedWalletAddress, positionAddress } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- const pancakeswap = await Pancakeswap.getInstance(network);
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- }
-
- return await collectFees(network, walletAddress, positionAddress);
- } catch (e: any) {
- logger.error('Failed to collect fees:', e);
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to collect fees');
- }
- },
- );
-};
-
-export default collectFeesRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/createPool.ts b/src/connectors/pancakeswap/clmm-routes/createPool.ts
index 85e8bda09c..b593ad2766 100644
--- a/src/connectors/pancakeswap/clmm-routes/createPool.ts
+++ b/src/connectors/pancakeswap/clmm-routes/createPool.ts
@@ -1,13 +1,12 @@
import { Contract } from '@ethersproject/contracts';
-import { Static } from '@sinclair/typebox';
import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk';
import { Decimal } from 'decimal.js';
-import { BigNumber, constants, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
+import { BigNumber, constants } from 'ethers';
import JSBI from 'jsbi';
import { Ethereum, TokenInfo } from '../../../chains/ethereum/ethereum';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { CreatePoolResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import {
@@ -17,8 +16,6 @@ import {
getPancakeswapV3FactoryAddress,
getPancakeswapV3NftManagerAddress,
} from '../pancakeswap.contracts';
-import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapClmmCreatePoolRequest } from '../schemas';
// Pancakeswap V3 supported fee tiers (hundredths of a bip). 100=0.01%, 500=0.05%, 2500=0.25%, 10000=1.00%.
// NOTE: these differ from Uniswap V3 — Pancakeswap uses 2500 (0.25%) where Uniswap uses 3000 (0.30%).
@@ -55,10 +52,10 @@ async function fetchMarketPrice(
quoteToken: string,
amount: number,
): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
+ quote = await getSwapQuote(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to seed the pool (${e.message}). ` +
@@ -78,8 +75,6 @@ export async function createPool(
quoteToken: string,
initialPrice?: number,
fee?: number,
- gasPrice?: number,
- maxGas?: number,
): Promise {
// Validate the fee tier — V3 only accepts a fixed set of tiers, each mapped to a tick spacing.
if (fee === undefined) {
@@ -174,7 +169,7 @@ export async function createPool(
const nftManagerAddress = getPancakeswapV3NftManagerAddress(network);
const nftManager = new Contract(nftManagerAddress, INftManagerCreatePoolABI, wallet);
- const gasOptions = await ethereum.prepareGasOptions(gasPrice, maxGas || CLMM_CREATE_POOL_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, CLMM_CREATE_POOL_GAS_LIMIT);
const tx = await nftManager.createAndInitializePoolIfNecessary(
token0.address,
@@ -186,102 +181,29 @@ export async function createPool(
logger.info(`Creating Pancakeswap V3 pool via tx ${tx.hash}`);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ // A revert throws out of here (400 TRANSACTION_FAILED) — it is never reported as PENDING.
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
// Read the (now-created) pool address from the factory — the authoritative source.
const poolAddress: string = await factory.getPool(token0.address, token1.address, fee);
- if (receipt && receipt.status === 1) {
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18); // ETH has 18 decimals
+ if (!outcome.confirmed) {
+ // Timed out but still broadcasting — report PENDING with the tx hash so the caller can reconcile it.
return {
- signature: receipt.transactionHash,
- status: 1, // CONFIRMED
+ signature: outcome.signature,
+ status: TransactionStatus.PENDING,
poolAddress,
price: seedPrice,
- data: {
- fee: gasFee,
- baseTokenAmountAdded: 0, // create-pool only initializes price; no liquidity is seeded
- quoteTokenAmountAdded: 0,
- },
};
}
- // Timed out (still broadcasting) or reverted — report as pending with the tx hash.
return {
- signature: receipt ? receipt.transactionHash : tx.hash,
- status: 0, // PENDING
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
poolAddress,
price: seedPrice,
+ data: {
+ fee: outcome.fee,
+ },
};
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description: 'Create and initialize a new Pancakeswap V3 (CLMM) pool at an initial price (no liquidity seeded)',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapClmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- baseToken,
- quoteToken,
- fee,
- initialPrice,
- gasPrice,
- maxGas,
- walletAddress: requestedWalletAddress,
- } = request.body;
-
- if (!baseToken || !quoteToken) {
- throw fastify.httpErrors.badRequest('Missing required parameters');
- }
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no wallets found.');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- // Route accepts gasPrice as a wei string (matching sibling requests); createPool expects gwei.
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
-
- return await createPool(network, walletAddress, baseToken, quoteToken, initialPrice, fee, gasPriceGwei, maxGas);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
-
- if (e.message && e.message.includes('already exists')) {
- throw fastify.httpErrors.badRequest(e.message);
- }
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient native balance to pay for gas fees. Please add more funds to your wallet.',
- );
- }
-
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/executeSwap.ts b/src/connectors/pancakeswap/clmm-routes/executeSwap.ts
index 47fd5e91da..4bb1d08ab4 100644
--- a/src/connectors/pancakeswap/clmm-routes/executeSwap.ts
+++ b/src/connectors/pancakeswap/clmm-routes/executeSwap.ts
@@ -1,17 +1,16 @@
import { encodeSqrtRatioX96 } from '@uniswap/v3-sdk';
import { BigNumber, Contract, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
-import { Ethereum } from '../../../chains/ethereum/ethereum';
+import { Ethereum, EthereumTransactionOutcome } from '../../../chains/ethereum/ethereum';
import { EthereumLedger } from '../../../chains/ethereum/ethereum-ledger';
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
import { getPancakeswapV3SwapRouter02Address, ISwapRouter02ABI } from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-import { PancakeswapExecuteSwapRequest } from '../schemas';
import { getPancakeswapClmmQuote, resolveCounterToken } from './quoteSwap';
@@ -109,7 +108,7 @@ export async function executeClmmSwap(
).toString(),
};
- let receipt;
+ let outcome: EthereumTransactionOutcome;
try {
if (isHardwareWallet) {
@@ -186,7 +185,7 @@ export async function executeClmmSwap(
logger.info(`Transaction sent: ${txResponse.hash}`);
// Wait for confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(txResponse);
+ outcome = await ethereum.handleTransactionConfirmation(txResponse);
} else {
// Regular wallet flow
let wallet;
@@ -249,19 +248,18 @@ export async function executeClmmSwap(
logger.info(`Transaction sent: ${tx.hash}`);
// Wait for transaction confirmation
- receipt = await ethereum.handleTransactionExecution(tx);
+ outcome = await ethereum.handleTransactionConfirmation(tx);
}
- // Check if the transaction was successful
- if (receipt.status === 0) {
- logger.error(`Transaction failed on-chain. Receipt: ${JSON.stringify(receipt)}`);
- throw httpErrors.internalServerError(
- 'Transaction reverted on-chain. This could be due to slippage, insufficient funds, or other blockchain issues.',
- );
+ // A revert threw out of the confirmation helper as a 400 TRANSACTION_FAILED. What is left
+ // is a transaction that is still pending after the extended poll: report it as PENDING
+ // with its hash rather than dereferencing a null receipt and losing the hash to a 500.
+ if (!outcome.confirmed) {
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
}
- logger.info(`Transaction hash: ${receipt.transactionHash}`);
- logger.info(`Gas used: ${receipt.gasUsed.toString()}`);
+ logger.info(`Transaction hash: ${outcome.signature}`);
+ logger.info(`Gas used: ${outcome.receipt.gasUsed.toString()}`);
// Calculate amounts using quote values
const amountIn = quote.estimatedAmountIn;
@@ -271,27 +269,22 @@ export async function executeClmmSwap(
const baseTokenBalanceChange = side === 'BUY' ? amountOut : -amountIn;
const quoteTokenBalanceChange = side === 'BUY' ? -amountIn : amountOut;
- // Calculate gas fee (formatTokenAmount already returns a number)
- const gasFee = formatTokenAmount(
- receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(),
- 18, // ETH has 18 decimals
- );
-
// Determine token addresses for computed fields
const tokenIn = quote.inputToken.address;
const tokenOut = quote.outputToken.address;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
tokenIn,
tokenOut,
amountIn,
amountOut,
- fee: gasFee,
+ fee: outcome.fee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
} catch (error) {
@@ -325,52 +318,5 @@ export async function executeClmmSwap(
}
}
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on Pancakeswap V3 CLMM using SwapRouter02',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct } =
- request.body as typeof PancakeswapExecuteSwapRequest._type;
-
- // This route resolves the pool from the pair (no poolAddress in its request schema);
- // executeClmmSwap itself is standardized to require poolAddress.
- const pancakeswap = await Pancakeswap.getInstance(network);
- const poolAddress = await pancakeswap.findDefaultPool(baseToken, quoteToken, 'clmm');
- if (!poolAddress) {
- throw httpErrors.notFound(`No CLMM pool found for pair ${baseToken}-${quoteToken}`);
- }
-
- return await executeClmmSwap(
- network,
- walletAddress,
- poolAddress,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
// Export executeSwap alias for uniform chain route imports
export { executeClmmSwap as executeSwap };
-
-export default executeSwapRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/index.ts b/src/connectors/pancakeswap/clmm-routes/index.ts
deleted file mode 100644
index 8847547e3f..0000000000
--- a/src/connectors/pancakeswap/clmm-routes/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import addLiquidityRoute from './addLiquidity';
-import closePositionRoute from './closePosition';
-import collectFeesRoute from './collectFees';
-import createPoolRoute from './createPool';
-import executeSwapRoute from './executeSwap';
-import openPositionRoute from './openPosition';
-import poolInfoRoute from './poolInfo';
-import positionInfoRoute from './positionInfo';
-import positionsOwnedRoute from './positionsOwned';
-import quotePositionRoute from './quotePosition';
-import quoteSwapRoute from './quoteSwap';
-import removeLiquidityRoute from './removeLiquidity';
-
-export const pancakeswapClmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(quotePositionRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(openPositionRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(collectFeesRoute);
- await fastify.register(closePositionRoute);
- await fastify.register(createPoolRoute);
-};
-
-export default pancakeswapClmmRoutes;
diff --git a/src/connectors/pancakeswap/clmm-routes/openPosition.ts b/src/connectors/pancakeswap/clmm-routes/openPosition.ts
index 2574bbe477..5c83b30dc9 100644
--- a/src/connectors/pancakeswap/clmm-routes/openPosition.ts
+++ b/src/connectors/pancakeswap/clmm-routes/openPosition.ts
@@ -2,16 +2,11 @@ import { Contract } from '@ethersproject/contracts';
import { CurrencyAmount, Percent } from '@pancakeswap/sdk';
import { Position, NonfungiblePositionManager, MintOptions, nearestUsableTick } from '@pancakeswap/v3-sdk';
import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Address } from 'viem';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- OpenPositionRequestType,
- OpenPositionRequest,
- OpenPositionResponseType,
- OpenPositionResponse,
-} from '../../../schemas/clmm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { OpenPositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
@@ -239,11 +234,15 @@ export async function openPosition(
}
// Wait for transaction confirmation
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — there is no mint log to read yet, so no positionAddress and no amounts.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
// Find the NFT ID from the transaction logs
let positionId = '';
- for (const log of receipt.logs) {
+ for (const log of outcome.receipt.logs) {
if (
log.address.toLowerCase() === positionManagerAddress.toLowerCase() &&
log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' &&
@@ -254,8 +253,15 @@ export async function openPosition(
}
}
- // Calculate gas fee
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
+ if (!positionId) {
+ // The transaction confirmed but no NFT-mint Transfer log was found. Returning a CONFIRMED
+ // response with an empty positionAddress would have the caller record a position it can
+ // never address — fail loudly, naming the transaction so the position stays recoverable.
+ throw httpErrors.internalServerError(
+ `Position opened in transaction ${outcome.signature} but no position NFT mint was found in its logs. ` +
+ `Inspect the transaction to recover the position ID.`,
+ );
+ }
// For position rent, we're using the estimated gas cost since Ethereum doesn't have rent like Solana
const positionRent = 0;
@@ -269,10 +275,10 @@ export async function openPosition(
const quoteAmountUsed = isBaseToken0 ? actualToken1Amount : actualToken0Amount;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ fee: outcome.fee,
positionAddress: positionId,
positionRent,
baseTokenAmountAdded: baseAmountUsed,
@@ -280,93 +286,3 @@ export async function openPosition(
},
};
}
-
-export const openPositionRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.post<{
- Body: OpenPositionRequestType;
- Reply: OpenPositionResponseType;
- }>(
- '/open-position',
- {
- schema: {
- description: 'Open a new liquidity position in a Pancakeswap V3 pool',
- tags: ['/connector/pancakeswap'],
- body: {
- ...OpenPositionRequest,
- properties: {
- ...OpenPositionRequest.properties,
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- lowerPrice: { type: 'number', examples: [0.0008] },
- upperPrice: { type: 'number', examples: [0.001] },
- poolAddress: {
- type: 'string',
- default: '0x172fcd41e0913e95784454622d1c3724f546f849',
- examples: ['0x172fcd41e0913e95784454622d1c3724f546f849'],
- },
- baseTokenAmount: { type: 'number', examples: [10] },
- quoteTokenAmount: { type: 'number', examples: [0.01] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: {
- 200: OpenPositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress: requestedWalletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- const pancakeswap = await Pancakeswap.getInstance(network);
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- }
-
- return await openPosition(
- network,
- walletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e: any) {
- logger.error('Failed to open position:', e);
- if (e.statusCode) {
- throw e;
- }
- if (e.code === 'CALL_EXCEPTION') {
- throw httpErrors.badRequest(
- 'Transaction failed. Please check token balances, approvals, and position parameters.',
- );
- }
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw httpErrors.badRequest('Insufficient funds to complete the transaction');
- }
- throw httpErrors.internalServerError('Failed to open position');
- }
- },
- );
-};
-
-export default openPositionRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/poolInfo.ts b/src/connectors/pancakeswap/clmm-routes/poolInfo.ts
index 8efd314f11..347898ac17 100644
--- a/src/connectors/pancakeswap/clmm-routes/poolInfo.ts
+++ b/src/connectors/pancakeswap/clmm-routes/poolInfo.ts
@@ -1,13 +1,21 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { Contract as EthersProjectContract } from '@ethersproject/contracts';
+import { abi as IPancakeV3PoolABI } from '@pancakeswap/v3-core/artifacts/contracts/interfaces/IPancakeV3Pool.sol/IPancakeV3Pool.json';
+import { SqrtPriceMath, TickMath } from '@pancakeswap/v3-sdk';
+import { FastifyInstance } from 'fastify';
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { Ethereum } from '../../../chains/ethereum/ethereum';
+import { PoolInfo } from '../../../schemas/clmm-schema';
import { sanitizeErrorMessage } from '../../../services/sanitize';
+import { computeV3BinDistribution } from '../../clmm-v3-utils';
import { Pancakeswap } from '../pancakeswap';
import { formatTokenAmount, getPancakeswapPoolInfo } from '../pancakeswap.utils';
-import { PancakeswapClmmGetPoolInfoRequest } from '../schemas';
-export async function getPoolInfo(fastify: FastifyInstance, network: string, poolAddress: string): Promise {
+export async function getPoolInfo(
+ fastify: FastifyInstance,
+ network: string,
+ poolAddress: string,
+ binCount: number = 0,
+): Promise {
const pancakeswap = await Pancakeswap.getInstance(network);
if (!poolAddress) {
@@ -41,9 +49,18 @@ export async function getPoolInfo(fastify: FastifyInstance, network: string, poo
const price = isBaseToken0 ? parseFloat(price0) : parseFloat(price1);
- const liquidity = pool.liquidity;
- const token0Amount = formatTokenAmount(liquidity.toString(), token0.decimals);
- const token1Amount = formatTokenAmount(liquidity.toString(), token1.decimals);
+ // Read the pool contract's actual ERC20 balances. V3's `pool.liquidity` is the
+ // active virtual liquidity in sqrt-price space, not a token amount — using it
+ // reported the same figure for both sides, scaled by each token's decimals.
+ const ethereum = await Ethereum.getInstance(network);
+ const token0Contract = ethereum.getContract(token0.address, ethereum.provider);
+ const token1Contract = ethereum.getContract(token1.address, ethereum.provider);
+ const [token0Balance, token1Balance] = await Promise.all([
+ ethereum.getERC20BalanceByAddress(token0Contract, poolAddress, token0.decimals),
+ ethereum.getERC20BalanceByAddress(token1Contract, poolAddress, token1.decimals),
+ ]);
+ const token0Amount = formatTokenAmount(token0Balance.value.toString(), token0.decimals);
+ const token1Amount = formatTokenAmount(token1Balance.value.toString(), token1.decimals);
const baseTokenAmount = isBaseToken0 ? token0Amount : token1Amount;
const quoteTokenAmount = isBaseToken0 ? token1Amount : token0Amount;
@@ -52,7 +69,7 @@ export async function getPoolInfo(fastify: FastifyInstance, network: string, poo
const tickSpacing = pool.tickSpacing;
const activeBinId = pool.tickCurrent;
- return {
+ const result: PoolInfo = {
address: poolAddress,
baseTokenAddress: baseTokenObj.address,
quoteTokenAddress: quoteTokenObj.address,
@@ -63,38 +80,26 @@ export async function getPoolInfo(fastify: FastifyInstance, network: string, poo
quoteTokenAmount: quoteTokenAmount,
activeBinId: activeBinId,
};
-}
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: Record;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get CLMM pool information from Pancakeswap V3',
- tags: ['/connector/pancakeswap'],
- querystring: PancakeswapClmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress } = request.query;
- const network = request.query.network;
- return await getPoolInfo(fastify, network, poolAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to fetch pool info');
- }
- },
- );
-};
-
-export default poolInfoRoute;
+ // Optionally include the per-bin distribution around the current tick.
+ // Fires N parallel pool.ticks(tick) reads — only when binCount > 0 so the
+ // default pool-info latency is unaffected.
+ if (binCount > 0) {
+ const poolContract = new EthersProjectContract(poolAddress, IPancakeV3PoolABI, ethereum.provider);
+ result.bins = await computeV3BinDistribution({
+ poolContract,
+ tickSpacing,
+ currentTick: activeBinId,
+ currentSqrtPriceX96: BigInt(pool.sqrtRatioX96.toString()),
+ activeLiquidity: BigInt(pool.liquidity.toString()),
+ decimals0: token0.decimals,
+ decimals1: token1.decimals,
+ isBaseToken0,
+ binCount,
+ tickMath: TickMath,
+ sqrtPriceMath: SqrtPriceMath,
+ });
+ }
+
+ return result;
+}
diff --git a/src/connectors/pancakeswap/clmm-routes/positionInfo.ts b/src/connectors/pancakeswap/clmm-routes/positionInfo.ts
index 754fbde1e6..7baa4f9bdd 100644
--- a/src/connectors/pancakeswap/clmm-routes/positionInfo.ts
+++ b/src/connectors/pancakeswap/clmm-routes/positionInfo.ts
@@ -1,15 +1,9 @@
import { Contract } from '@ethersproject/contracts';
import { Position, tickToPrice, computePoolAddress } from '@pancakeswap/v3-sdk';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- GetPositionInfoRequestType,
- GetPositionInfoRequest,
- PositionInfo,
- PositionInfoSchema,
-} from '../../../schemas/clmm-schema';
-import { logger } from '../../../services/logger';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { Pancakeswap } from '../pancakeswap';
import {
POSITION_MANAGER_ABI,
@@ -103,48 +97,3 @@ export async function getPositionInfo(
price: parseFloat(price),
};
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get position information for a Pancakeswap V3 position',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...GetPositionInfoRequest,
- properties: {
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- positionAddress: {
- type: 'string',
- description: 'Position NFT token ID',
- examples: ['1234'],
- },
- },
- },
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { network, positionAddress } = request.query;
- return await getPositionInfo(fastify, network, positionAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to get position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/positionsOwned.ts b/src/connectors/pancakeswap/clmm-routes/positionsOwned.ts
index 85d4cbacb6..bb0645cc03 100644
--- a/src/connectors/pancakeswap/clmm-routes/positionsOwned.ts
+++ b/src/connectors/pancakeswap/clmm-routes/positionsOwned.ts
@@ -1,10 +1,9 @@
import { Contract } from '@ethersproject/contracts';
import { Position, tickToPrice, computePoolAddress } from '@pancakeswap/v3-sdk';
-import { Type } from '@sinclair/typebox';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { PositionInfo, PositionInfoSchema } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Pancakeswap } from '../pancakeswap';
import {
@@ -14,14 +13,6 @@ import {
} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
-// Define the request and response types
-const PositionsOwnedRequest = Type.Object({
- network: Type.Optional(Type.String({ examples: ['bsc'], default: 'bsc' })),
- walletAddress: Type.String({ examples: [''] }),
-});
-
-const PositionsOwnedResponse = Type.Array(PositionInfoSchema);
-
// Additional ABI methods needed for enumerating positions
const ENUMERABLE_ABI = [
{
@@ -142,46 +133,3 @@ export async function getPositionsOwned(
return positions;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.get<{
- Querystring: typeof PositionsOwnedRequest.static;
- Reply: typeof PositionsOwnedResponse.static;
- }>(
- '/positions-owned',
- {
- schema: {
- description: 'Get all Pancakeswap V3 positions owned by a wallet',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...PositionsOwnedRequest,
- properties: {
- ...PositionsOwnedRequest.properties,
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- },
- },
- response: {
- 200: PositionsOwnedResponse,
- },
- },
- },
- async (request) => {
- try {
- const { walletAddress } = request.query;
- const network = request.query.network;
- return await getPositionsOwned(fastify, network, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to fetch positions');
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/pancakeswap/clmm-routes/quotePosition.ts b/src/connectors/pancakeswap/clmm-routes/quotePosition.ts
index 801ec25937..2445d861ab 100644
--- a/src/connectors/pancakeswap/clmm-routes/quotePosition.ts
+++ b/src/connectors/pancakeswap/clmm-routes/quotePosition.ts
@@ -1,385 +1,13 @@
-import { Position, nearestUsableTick, tickToPrice } from '@pancakeswap/v3-sdk';
-import { utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
+import { Position, nearestUsableTick } from '@pancakeswap/v3-sdk';
import JSBI from 'jsbi';
-import {
- QuotePositionRequestType,
- QuotePositionRequest,
- QuotePositionResponseType,
- QuotePositionResponse,
-} from '../../../schemas/clmm-schema';
+import { QuotePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Pancakeswap } from '../pancakeswap';
import { getPancakeswapPoolInfo } from '../pancakeswap.utils';
// Constants for examples (BSC USDT-WBNB pool, current price ~0.00093)
-const BASE_TOKEN_AMOUNT = 10;
-const QUOTE_TOKEN_AMOUNT = 0.01;
-const LOWER_PRICE_BOUND = 0.0008;
-const UPPER_PRICE_BOUND = 0.001;
-const POOL_ADDRESS_EXAMPLE = '0x172fcd41e0913e95784454622d1c3724f546f849';
-
-export const quotePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuotePositionRequestType;
- Reply: QuotePositionResponseType;
- }>(
- '/quote-position',
- {
- schema: {
- description: 'Get a quote for opening a position on Pancakeswap V3',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...QuotePositionRequest,
- properties: {
- ...QuotePositionRequest.properties,
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- lowerPrice: { type: 'number', examples: [LOWER_PRICE_BOUND] },
- upperPrice: { type: 'number', examples: [UPPER_PRICE_BOUND] },
- poolAddress: {
- type: 'string',
- default: POOL_ADDRESS_EXAMPLE,
- examples: [POOL_ADDRESS_EXAMPLE],
- },
- baseTokenAmount: { type: 'number', examples: [BASE_TOKEN_AMOUNT] },
- quoteTokenAmount: { type: 'number', examples: [QUOTE_TOKEN_AMOUNT] },
- },
- },
- response: {
- 200: QuotePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, lowerPrice, upperPrice, poolAddress, baseTokenAmount, quoteTokenAmount } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (
- !lowerPrice ||
- !upperPrice ||
- !poolAddress ||
- (baseTokenAmount === undefined && quoteTokenAmount === undefined)
- ) {
- throw httpErrors.badRequest('Missing required parameters');
- }
-
- // Get Pancakeswap and Ethereum instances
- const pancakeswap = await Pancakeswap.getInstance(networkToUse);
-
- // Get pool information to determine tokens
- const poolInfo = await getPancakeswapPoolInfo(poolAddress, networkToUse, 'clmm');
- if (!poolInfo) {
- throw httpErrors.notFound(sanitizeErrorMessage('Pool not found: {}', poolAddress));
- }
-
- const baseTokenObj = await pancakeswap.getToken(poolInfo.baseTokenAddress);
- const quoteTokenObj = await pancakeswap.getToken(poolInfo.quoteTokenAddress);
-
- if (!baseTokenObj || !quoteTokenObj) {
- throw httpErrors.badRequest('Token information not found for pool');
- }
-
- // Get the V3 pool
- const pool = await pancakeswap.getV3Pool(baseTokenObj, quoteTokenObj, undefined, poolAddress);
- if (!pool) {
- throw httpErrors.notFound(`Pool not found for ${baseTokenObj.symbol}-${quoteTokenObj.symbol}`);
- }
-
- // Convert price range to ticks
- // In Pancakeswap, ticks are log base 1.0001 of price
- // We need to convert the user's desired price range to tick range
- const token0 = pool.token0;
- const token1 = pool.token1;
-
- // Determine if we need to invert the price depending on which token is token0
- const isBaseToken0 = baseTokenObj.address.toLowerCase() === token0.address.toLowerCase();
-
- // Convert prices to ticks
- let lowerTick, upperTick;
-
- // Calculate ticks based on price
- // Tick = log(price) / log(1.0001)
-
- console.log('DEBUG: isBaseToken0:', isBaseToken0);
- console.log('DEBUG: baseToken symbol:', baseTokenObj.symbol, 'address:', baseTokenObj.address);
- console.log('DEBUG: quoteToken symbol:', quoteTokenObj.symbol, 'address:', quoteTokenObj.address);
- console.log('DEBUG: token0:', token0.symbol, 'address:', token0.address);
- console.log('DEBUG: token1:', token1.symbol, 'address:', token1.address);
-
- // CRITICAL INSIGHT: The pool's negative tick is confusing us!
- // The pool tick of -197547 actually represents the current price correctly
- // but in a way that seems counterintuitive.
- //
- // The issue is that Pancakeswap stores the price and tick in a specific way:
- // - sqrtPriceX96 = sqrt(token1/token0) * 2^96
- // - tick = floor(log(token1/token0) / log(1.0001))
- //
- // For this pool:
- // - token0 = WETH (18 decimals)
- // - token1 = USDC (6 decimals)
- // - Human readable price = 2637 USDC per WETH
- // - But in raw amounts: 2637 * 10^6 USDC units per 10^18 WETH units
- // - So token1/token0 in raw units = (2637 * 10^6) / 10^18 = 2637 * 10^-12
- // - This is a very small number! Hence the negative tick.
-
- console.log('DEBUG: Current pool tick:', pool.tickCurrent);
- console.log('DEBUG: This tick represents token1/token0 in RAW UNITS (not human readable)');
-
- // When calculating ticks from human-readable prices, we need to account for decimals
- const priceToTickWithDecimals = (humanPrice: number): number => {
- // Convert human price (USDC per WETH) to raw price (USDC units per WETH unit)
- const rawPrice = humanPrice * Math.pow(10, token1.decimals - token0.decimals);
- return Math.floor(Math.log(rawPrice) / Math.log(1.0001));
- };
-
- lowerTick = priceToTickWithDecimals(lowerPrice);
- upperTick = priceToTickWithDecimals(upperPrice);
-
- const currentHumanPrice = 2637; // Approximate current price
- const expectedCurrentTick = priceToTickWithDecimals(currentHumanPrice);
- console.log('DEBUG: Expected current tick for price', currentHumanPrice, ':', expectedCurrentTick);
- console.log('DEBUG: Lower price', lowerPrice, '-> tick', lowerTick);
- console.log('DEBUG: Upper price', upperPrice, '-> tick', upperTick);
-
- console.log('DEBUG: Raw calculated lowerTick:', lowerTick);
- console.log('DEBUG: Raw calculated upperTick:', upperTick);
-
- // Ensure ticks are on valid tick spacing boundaries
- const tickSpacing = pool.tickSpacing;
- lowerTick = nearestUsableTick(lowerTick, tickSpacing);
- upperTick = nearestUsableTick(upperTick, tickSpacing);
-
- console.log('DEBUG: Adjusted lowerTick (after tick spacing):', lowerTick);
- console.log('DEBUG: Adjusted upperTick (after tick spacing):', upperTick);
- console.log('DEBUG: Pool tick spacing:', tickSpacing);
- console.log('DEBUG: Current pool tick:', pool.tickCurrent);
- console.log('DEBUG: Pool current price (sqrtPriceX96):', pool.sqrtRatioX96.toString());
-
- // Calculate the actual price from sqrtPriceX96
- const sqrtPriceX96 = JSBI.toNumber(JSBI.BigInt(pool.sqrtRatioX96.toString()));
- const price = Math.pow(sqrtPriceX96 / Math.pow(2, 96), 2);
- console.log('DEBUG: Pool current price (decimal):', price);
- console.log(
- 'DEBUG: Pool current price (token1/token0):',
- price * Math.pow(10, token0.decimals - token1.decimals),
- );
-
- // Use SDK to convert tick to price for verification
- const tickPrice = tickToPrice(token0, token1, pool.tickCurrent);
- console.log('DEBUG: Price from current tick:', tickPrice.toSignificant(6));
- console.log('DEBUG: Price from current tick (inverted):', tickPrice.invert().toSignificant(6));
-
- // Ensure lower < upper
- if (lowerTick >= upperTick) {
- throw httpErrors.badRequest('Lower price must be less than upper price');
- }
-
- // Check if the current price is within the position range
- const isInRange = pool.tickCurrent >= lowerTick && pool.tickCurrent <= upperTick;
- console.log('DEBUG: Is position in range?', isInRange);
- console.log('DEBUG: Position will require both tokens?', isInRange);
-
- if (!isInRange) {
- console.log('WARNING: Position is out of range!');
- console.log(
- ' Current tick:',
- pool.tickCurrent,
- 'is',
- pool.tickCurrent < lowerTick ? 'below' : 'above',
- 'the range',
- );
- console.log(
- ' This means the position will only contain',
- pool.tickCurrent < lowerTick ? baseTokenObj.symbol : quoteTokenObj.symbol,
- );
- }
-
- // Calculate optimal token amounts
- let position: Position;
- let baseLimited = false;
-
- console.log('DEBUG: Input amounts:');
- console.log(' - baseTokenAmount:', baseTokenAmount);
- console.log(' - quoteTokenAmount:', quoteTokenAmount);
-
- if (baseTokenAmount !== undefined && quoteTokenAmount !== undefined) {
- console.log('DEBUG: Using fromAmounts (both amounts provided)');
- // Both amounts provided - use fromAmounts to calculate optimal position
- // Use parseUnits to avoid scientific notation issues with large numbers
- const baseAmountRaw = JSBI.BigInt(
- utils.parseUnits(baseTokenAmount.toString(), baseTokenObj.decimals).toString(),
- );
- const quoteAmountRaw = JSBI.BigInt(
- utils.parseUnits(quoteTokenAmount.toString(), quoteTokenObj.decimals).toString(),
- );
-
- console.log('DEBUG: Raw amounts:');
- console.log(' - baseAmountRaw:', baseAmountRaw.toString());
- console.log(' - quoteAmountRaw:', quoteAmountRaw.toString());
- console.log(' - baseToken decimals:', baseTokenObj.decimals);
- console.log(' - quoteToken decimals:', quoteTokenObj.decimals);
-
- // Create position from both amounts
- if (isBaseToken0) {
- console.log('DEBUG: Creating position with base as token0');
- position = Position.fromAmounts({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount0: baseAmountRaw.toString(),
- amount1: quoteAmountRaw.toString(),
- useFullPrecision: true,
- });
- } else {
- console.log('DEBUG: Creating position with base as token1');
- position = Position.fromAmounts({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount0: quoteAmountRaw.toString(),
- amount1: baseAmountRaw.toString(),
- useFullPrecision: true,
- });
- }
-
- // Determine which token is limiting by comparing input vs required amounts
- const baseRequired = isBaseToken0 ? position.amount0 : position.amount1;
- const quoteRequired = isBaseToken0 ? position.amount1 : position.amount0;
-
- const baseRatio = parseFloat(baseAmountRaw.toString()) / parseFloat(baseRequired.quotient.toString());
- const quoteRatio = parseFloat(quoteAmountRaw.toString()) / parseFloat(quoteRequired.quotient.toString());
-
- baseLimited = baseRatio <= quoteRatio;
- } else if (baseTokenAmount !== undefined) {
- console.log('DEBUG: Using fromAmount (only base amount provided)');
- // Only base amount provided
- // Use parseUnits to avoid scientific notation issues with large numbers
- const baseAmountRaw = JSBI.BigInt(
- utils.parseUnits(baseTokenAmount.toString(), baseTokenObj.decimals).toString(),
- );
-
- console.log('DEBUG: baseAmountRaw:', baseAmountRaw.toString());
-
- if (isBaseToken0) {
- console.log('DEBUG: Creating position from amount0 (base is token0)');
- position = Position.fromAmount0({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount0: baseAmountRaw.toString(),
- useFullPrecision: true,
- });
- } else {
- console.log('DEBUG: Creating position from amount1 (base is token1)');
- position = Position.fromAmount1({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount1: baseAmountRaw.toString(),
- });
- }
- baseLimited = true;
- } else if (quoteTokenAmount !== undefined) {
- console.log('DEBUG: Using fromAmount (only quote amount provided)');
- // Only quote amount provided
- // Use parseUnits to avoid scientific notation issues with large numbers
- const quoteAmountRaw = JSBI.BigInt(
- utils.parseUnits(quoteTokenAmount.toString(), quoteTokenObj.decimals).toString(),
- );
-
- console.log('DEBUG: quoteAmountRaw:', quoteAmountRaw.toString());
-
- if (isBaseToken0) {
- console.log('DEBUG: Creating position from amount1 (quote is token1)');
- position = Position.fromAmount1({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount1: quoteAmountRaw.toString(),
- });
- } else {
- console.log('DEBUG: Creating position from amount0 (quote is token0)');
- position = Position.fromAmount0({
- pool,
- tickLower: lowerTick,
- tickUpper: upperTick,
- amount0: quoteAmountRaw.toString(),
- useFullPrecision: true,
- });
- }
- baseLimited = false;
- } else {
- throw httpErrors.badRequest('Either base or quote token amount must be provided');
- }
-
- // Calculate the optimal amounts
-
- // Get the actual token amounts from the position
- const actualToken0Amount = position.amount0;
- const actualToken1Amount = position.amount1;
-
- console.log('DEBUG: Position created with:');
- console.log(' - liquidity:', position.liquidity.toString());
- console.log(' - amount0 (raw):', actualToken0Amount.quotient.toString());
- console.log(' - amount1 (raw):', actualToken1Amount.quotient.toString());
- console.log(' - amount0 (formatted):', actualToken0Amount.toSignificant(18));
- console.log(' - amount1 (formatted):', actualToken1Amount.toSignificant(18));
- console.log(' - mintAmounts.amount0:', position.mintAmounts.amount0.toString());
- console.log(' - mintAmounts.amount1:', position.mintAmounts.amount1.toString());
-
- // Calculate actual amounts in human-readable form
- let actualBaseAmount, actualQuoteAmount;
-
- if (isBaseToken0) {
- actualBaseAmount = parseFloat(actualToken0Amount.toSignificant(18));
- actualQuoteAmount = parseFloat(actualToken1Amount.toSignificant(18));
- } else {
- actualBaseAmount = parseFloat(actualToken1Amount.toSignificant(18));
- actualQuoteAmount = parseFloat(actualToken0Amount.toSignificant(18));
- }
-
- console.log('DEBUG: Final amounts:');
- console.log(' - actualBaseAmount:', actualBaseAmount);
- console.log(' - actualQuoteAmount:', actualQuoteAmount);
- console.log(' - baseLimited:', baseLimited);
-
- // Calculate max amounts
- const baseTokenAmountMax = baseTokenAmount || actualBaseAmount;
- const quoteTokenAmountMax = quoteTokenAmount || actualQuoteAmount;
-
- // Calculate liquidity value
- const liquidity = position.liquidity.toString();
-
- // Use standard gas limit for position operations
- const computeUnits = 500000;
-
- return {
- baseLimited,
- baseTokenAmount: actualBaseAmount,
- quoteTokenAmount: actualQuoteAmount,
- baseTokenAmountMax,
- quoteTokenAmountMax,
- liquidity,
- computeUnits,
- };
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to quote position');
- }
- },
- );
-};
-
-export default quotePositionRoute;
// Export standalone function for use in unified routes
export async function quotePosition(
diff --git a/src/connectors/pancakeswap/clmm-routes/quoteSwap.ts b/src/connectors/pancakeswap/clmm-routes/quoteSwap.ts
index 6eba0401fc..80048ffa29 100644
--- a/src/connectors/pancakeswap/clmm-routes/quoteSwap.ts
+++ b/src/connectors/pancakeswap/clmm-routes/quoteSwap.ts
@@ -1,15 +1,9 @@
import { Token, CurrencyAmount, Percent, TradeType } from '@pancakeswap/sdk';
import { Route as V3Route, Trade as V3Trade } from '@pancakeswap/v3-sdk';
import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- QuoteSwapRequestType,
- QuoteSwapResponseType,
- QuoteSwapRequest,
- QuoteSwapResponse,
-} from '../../../schemas/clmm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
@@ -272,124 +266,6 @@ async function formatSwapQuote(
}
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- // Import the httpErrors plugin to ensure it's available
- await fastify.register(require('@fastify/sensible'));
-
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Pancakeswap V3 CLMM',
- tags: ['/connector/pancakeswap'],
- querystring: {
- ...QuoteSwapRequest,
- properties: {
- ...QuoteSwapRequest.properties,
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- baseToken: { type: 'string', examples: ['USDT'] },
- quoteToken: { type: 'string', examples: ['WBNB'] },
- amount: { type: 'number', examples: [10] },
- side: { type: 'string', enum: ['BUY', 'SELL'], examples: ['SELL'] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: { 200: QuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseToken, quoteToken, amount, side, slippagePct } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (!baseToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, amount, and side are required');
- }
-
- const pancakeswap = await Pancakeswap.getInstance(networkToUse);
-
- let poolAddressToUse = poolAddress;
- let baseTokenToUse: string;
- let quoteTokenToUse: string;
-
- if (poolAddressToUse) {
- // Pool address provided, get pool info to determine tokens
- const poolInfo = await getPancakeswapPoolInfo(poolAddressToUse, networkToUse, 'clmm');
- if (!poolInfo) {
- throw httpErrors.notFound(sanitizeErrorMessage('Pool not found: {}', poolAddressToUse));
- }
-
- // Determine which token is base and which is quote based on the provided baseToken
- if (baseToken === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (baseToken === poolInfo.quoteTokenAddress) {
- // User specified the quote token as base, so swap them
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- // Try to resolve baseToken as symbol to address
- const resolvedToken = await pancakeswap.getToken(baseToken);
-
- if (resolvedToken) {
- if (resolvedToken.address === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (resolvedToken.address === poolInfo.quoteTokenAddress) {
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- }
- } else {
- // No pool address provided, need quoteToken to find pool
- if (!quoteToken) {
- throw httpErrors.badRequest('quoteToken is required when poolAddress is not provided');
- }
-
- baseTokenToUse = baseToken;
- quoteTokenToUse = quoteToken;
-
- // Find pool using findDefaultPool
- poolAddressToUse = await pancakeswap.findDefaultPool(baseTokenToUse, quoteTokenToUse, 'clmm');
-
- if (!poolAddressToUse) {
- throw httpErrors.notFound(`No CLMM pool found for pair ${baseTokenToUse}-${quoteTokenToUse}`);
- }
- }
-
- return await formatSwapQuote(
- networkToUse,
- poolAddressToUse,
- baseTokenToUse,
- quoteTokenToUse,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- logger.error('Unexpected error getting swap quote:', e);
- throw httpErrors.internalServerError('Error getting swap quote');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Resolves the counter ("quote") token for a Pancakeswap V3 pool given the base token. The
* standardized swap wrappers take poolAddress + baseToken and derive the other side from the pool,
diff --git a/src/connectors/pancakeswap/clmm-routes/removeLiquidity.ts b/src/connectors/pancakeswap/clmm-routes/removeLiquidity.ts
index 9487cb9f68..130c5103d7 100644
--- a/src/connectors/pancakeswap/clmm-routes/removeLiquidity.ts
+++ b/src/connectors/pancakeswap/clmm-routes/removeLiquidity.ts
@@ -1,22 +1,22 @@
import { Contract } from '@ethersproject/contracts';
import { Percent, CurrencyAmount } from '@pancakeswap/sdk';
-import { NonfungiblePositionManager, Position } from '@pancakeswap/v3-sdk';
+import { NonfungiblePositionManager, Position, computePoolAddress } from '@pancakeswap/v3-sdk';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import JSBI from 'jsbi';
import { Address } from 'viem';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- RemoveLiquidityRequestType,
- RemoveLiquidityRequest,
- RemoveLiquidityResponseType,
- RemoveLiquidityResponse,
-} from '../../../schemas/clmm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
+import { slippageBasisPoints } from '../../evm-slippage';
import { Pancakeswap } from '../pancakeswap';
-import { POSITION_MANAGER_ABI, getPancakeswapV3NftManagerAddress } from '../pancakeswap.contracts';
+import { PancakeswapConfig } from '../pancakeswap.config';
+import {
+ POSITION_MANAGER_ABI,
+ getPancakeswapV3NftManagerAddress,
+ getPancakeswapV3PoolDeployerAddress,
+} from '../pancakeswap.contracts';
import { formatTokenAmount } from '../pancakeswap.utils';
// Default gas limit for CLMM remove liquidity operations
@@ -27,6 +27,7 @@ export async function removeLiquidity(
walletAddress: string,
positionAddress: string,
percentageToRemove: number,
+ slippagePct: number = PancakeswapConfig.config.slippagePct,
): Promise {
if (!positionAddress || percentageToRemove === undefined) {
throw httpErrors.badRequest('Missing required parameters');
@@ -60,6 +61,16 @@ export async function removeLiquidity(
const token0 = await pancakeswap.getToken(position.token0);
const token1 = await pancakeswap.getToken(position.token1);
+ // The pool this position belongs to, derived from the same inputs position-info
+ // uses. The unified route is position-addressed and never receives a pool, so
+ // deriving it here is what lets the response name the venue it acted on.
+ const poolAddress = computePoolAddress({
+ deployerAddress: getPancakeswapV3PoolDeployerAddress(network),
+ tokenA: token0,
+ tokenB: token1,
+ fee: position.fee,
+ });
+
const isBaseToken0 =
token0.symbol === 'WETH' ||
(token1.symbol !== 'WETH' && token0.address.toLowerCase() < token1.address.toLowerCase());
@@ -90,7 +101,10 @@ export async function removeLiquidity(
const amount0 = partialPosition.amount0;
const amount1 = partialPosition.amount1;
- const slippageTolerance = new Percent(100, 10000);
+ // The caller's tolerance, or the connector's configured one — not a literal. This was
+ // `new Percent(100, 10000)`, a flat 1% that ignored both, so an operator who had widened
+ // slippagePct for a volatile pair got 1% anyway and a revert that cost gas.
+ const slippageTolerance = new Percent(slippageBasisPoints(slippagePct), 10000);
const totalAmount0 = CurrencyAmount.fromRawAmount(
token0,
@@ -133,9 +147,12 @@ export async function removeLiquidity(
const txParams = await ethereum.prepareGasOptions(undefined, CLMM_REMOVE_LIQUIDITY_GAS_LIMIT);
txParams.value = BigNumber.from(value.toString());
const tx = await positionManagerWithSigner.multicall([calldata], txParams);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the amounts below were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
const token0AmountRemoved = formatTokenAmount(totalAmount0.quotient.toString(), token0.decimals);
const token1AmountRemoved = formatTokenAmount(totalAmount1.quotient.toString(), token1.decimals);
@@ -143,77 +160,13 @@ export async function removeLiquidity(
const quoteTokenAmountRemoved = isBaseToken0 ? token1AmountRemoved : token0AmountRemoved;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ poolAddress,
+ fee: outcome.fee,
baseTokenAmountRemoved,
quoteTokenAmountRemoved,
},
};
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.post<{
- Body: RemoveLiquidityRequestType;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a Pancakeswap V3 position',
- tags: ['/connector/pancakeswap'],
- body: {
- ...RemoveLiquidityRequest,
- properties: {
- ...RemoveLiquidityRequest.properties,
- network: { type: 'string', default: 'bsc', examples: ['bsc'] },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- positionAddress: {
- type: 'string',
- description: 'Position NFT token ID',
- examples: ['1234'],
- },
- percentageToRemove: {
- type: 'number',
- minimum: 0,
- maximum: 100,
- examples: [50],
- },
- },
- },
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress: requestedWalletAddress, positionAddress, percentageToRemove } = request.body;
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- const pancakeswap = await Pancakeswap.getInstance(network);
- walletAddress = await pancakeswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- }
-
- return await removeLiquidity(network, walletAddress, positionAddress, percentageToRemove);
- } catch (e: any) {
- logger.error('Failed to remove liquidity:', e);
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to remove liquidity');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/pancakeswap/pancakeswap.routes.ts b/src/connectors/pancakeswap/pancakeswap.routes.ts
deleted file mode 100644
index 2be31c8386..0000000000
--- a/src/connectors/pancakeswap/pancakeswap.routes.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import sensible from '@fastify/sensible';
-import { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { pancakeswapAmmRoutes } from './amm-routes';
-import { pancakeswapClmmRoutes } from './clmm-routes';
-import { pancakeswapRouterRoutes } from './router-routes';
-
-// Router routes (Universal Router with 4 endpoints)
-const pancakeswapRouterRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/pancakeswap'];
- }
- });
-
- await instance.register(pancakeswapRouterRoutes);
- });
-};
-
-// AMM routes (Pancakeswap V2)
-const pancakeswapAmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/pancakeswap'];
- }
- });
-
- await instance.register(pancakeswapAmmRoutes);
- });
-};
-
-// CLMM routes (Pancakeswap V3)
-const pancakeswapClmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/pancakeswap'];
- }
- });
-
- await instance.register(pancakeswapClmmRoutes);
- });
-};
-
-// Export routes in the same pattern as other connectors
-export const pancakeswapRoutes = {
- router: pancakeswapRouterRoutesWrapper,
- amm: pancakeswapAmmRoutesWrapper,
- clmm: pancakeswapClmmRoutesWrapper,
-};
-
-export default pancakeswapRoutes;
diff --git a/src/connectors/pancakeswap/pancakeswap.utils.ts b/src/connectors/pancakeswap/pancakeswap.utils.ts
index 85de802e8c..636bd49685 100644
--- a/src/connectors/pancakeswap/pancakeswap.utils.ts
+++ b/src/connectors/pancakeswap/pancakeswap.utils.ts
@@ -2,7 +2,6 @@ import { Contract } from '@ethersproject/contracts';
import { Token } from '@pancakeswap/sdk';
import { FeeAmount, Pool as V3Pool } from '@pancakeswap/v3-sdk';
import { FastifyInstance } from 'fastify';
-import { Address } from 'viem';
import { Ethereum } from '../../chains/ethereum/ethereum';
import { logger } from '../../services/logger';
diff --git a/src/connectors/pancakeswap/router-routes/executeQuote.ts b/src/connectors/pancakeswap/router-routes/executeQuote.ts
index cbb6ae95cf..23251c5d2b 100644
--- a/src/connectors/pancakeswap/router-routes/executeQuote.ts
+++ b/src/connectors/pancakeswap/router-routes/executeQuote.ts
@@ -1,14 +1,11 @@
import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
import { EthereumLedger } from '../../../chains/ethereum/ethereum-ledger';
-import { getEthereumChainConfig } from '../../../chains/ethereum/ethereum.config';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
-import { PancakeswapExecuteQuoteRequest } from '../schemas';
async function executeQuote(walletAddress: string, network: string, quoteId: string): Promise {
// Retrieve cached quote
@@ -18,7 +15,7 @@ async function executeQuote(walletAddress: string, network: string, quoteId: str
}
const { quote, request } = cached;
- const { inputToken, outputToken, side, amount } = request;
+ const { inputToken, outputToken, side, amount, slippagePct } = request;
const ethereum = await Ethereum.getInstance(network);
@@ -179,6 +176,8 @@ async function executeQuote(walletAddress: string, network: string, quoteId: str
expectedAmountIn,
expectedAmountOut,
side,
+ undefined,
+ slippagePct,
);
// Handle different transaction states
@@ -208,37 +207,3 @@ async function executeQuote(walletAddress: string, network: string, quoteId: str
}
export { executeQuote };
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from Pancakeswap Universal Router',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const {
- walletAddress = getEthereumChainConfig().defaultWallet,
- network = getEthereumChainConfig().defaultNetwork,
- quoteId,
- } = request.body as typeof PancakeswapExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/pancakeswap/router-routes/executeSwap.ts b/src/connectors/pancakeswap/router-routes/executeSwap.ts
index b5879d5531..f421f3f4cb 100644
--- a/src/connectors/pancakeswap/router-routes/executeSwap.ts
+++ b/src/connectors/pancakeswap/router-routes/executeSwap.ts
@@ -1,10 +1,6 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { logger } from '../../../services/logger';
import { PancakeswapConfig } from '../pancakeswap.config';
-import { PancakeswapExecuteSwapRequest } from '../schemas';
// Import the quote and execute functions
import { executeQuote } from './executeQuote';
@@ -31,42 +27,3 @@ async function executeSwap(
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on Pancakeswap Universal Router in one step',
- tags: ['/connector/pancakeswap'],
- body: PancakeswapExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct } =
- request.body as typeof PancakeswapExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/pancakeswap/router-routes/index.ts b/src/connectors/pancakeswap/router-routes/index.ts
deleted file mode 100644
index cef71a037c..0000000000
--- a/src/connectors/pancakeswap/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const pancakeswapRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default pancakeswapRouterRoutes;
diff --git a/src/connectors/pancakeswap/router-routes/quoteSwap.ts b/src/connectors/pancakeswap/router-routes/quoteSwap.ts
index d860a2c4ee..59d5a2dcd5 100644
--- a/src/connectors/pancakeswap/router-routes/quoteSwap.ts
+++ b/src/connectors/pancakeswap/router-routes/quoteSwap.ts
@@ -1,18 +1,14 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { getEthereumChainConfig } from '../../../chains/ethereum/ethereum.config';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Pancakeswap } from '../pancakeswap';
import { PancakeswapConfig } from '../pancakeswap.config';
-import { PancakeswapQuoteSwapRequest, PancakeswapQuoteSwapResponse } from '../schemas';
-
+import { PancakeswapQuoteSwapResponse } from '../schemas';
async function quoteSwap(
network: string,
walletAddress: string | undefined,
@@ -136,51 +132,3 @@ async function quoteSwap(
}
export { quoteSwap };
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- const chainConfig = getEthereumChainConfig();
-
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get an executable swap quote from Pancakeswap Universal Router',
- tags: ['/connector/pancakeswap'],
- querystring: PancakeswapQuoteSwapRequest,
- response: { 200: PancakeswapQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const {
- network = chainConfig.defaultNetwork,
- walletAddress = chainConfig.defaultWallet,
- baseToken,
- quoteToken,
- amount,
- side,
- slippagePct,
- } = request.query as typeof PancakeswapQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- walletAddress,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error getting quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/pancakeswap/schemas.ts b/src/connectors/pancakeswap/schemas.ts
index 7d01b9a1cf..fb764f5b79 100644
--- a/src/connectors/pancakeswap/schemas.ts
+++ b/src/connectors/pancakeswap/schemas.ts
@@ -1,213 +1,21 @@
import { Type } from '@sinclair/typebox';
-import { getEthereumChainConfig } from '../../chains/ethereum/ethereum.config';
-
-import { PancakeswapConfig } from './pancakeswap.config';
-
// Get chain config for defaults
-const ethereumChainConfig = getEthereumChainConfig();
-
// Constants for examples
-const BASE_TOKEN = 'USDT';
-const QUOTE_TOKEN = 'WBNB';
-const SWAP_AMOUNT = 10;
-const AMM_POOL_ADDRESS_EXAMPLE = '0x88A43bbDF9D098eEC7bCEda4e2494615dfD9bB9C'; // Pancakeswap V2 WETH-USDC pool on Base
-const CLMM_POOL_ADDRESS_EXAMPLE = '0x172fcd41e0913e95784454622d1c3724f546f849'; // Pancakeswap V3 USDT-WBNB pool on BSC
+// Pancakeswap V2 WETH-USDC pool on Base
// ========================================
// AMM Request Schemas
// ========================================
-export const PancakeswapAmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Pancakeswap V2 pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-// Pancakeswap AMM Create Pool Request (Pancakeswap V2 — Uniswap V2 fork, fixed 0.25% fee)
-export const PancakeswapAmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will create and seed the pool',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to seed the pool with',
- }),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description:
- 'Amount of quote token to seed with. If provided, the base:quote ratio sets the initial price. ' +
- 'If omitted (and no initialPrice), the current market price is fetched from the unified swap router.',
- }),
- ),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. Overrides quoteTokenAmount. If both are omitted, the pool is ' +
- 'seeded at the current market price so it is not immediately arbitraged.',
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
// ========================================
// CLMM Request Schemas
// ========================================
-export const PancakeswapClmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Pancakeswap V3 pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-// Pancakeswap CLMM Create Pool Request (Pancakeswap V3 — Uniswap V3 fork)
-export const PancakeswapClmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will create and initialize the pool',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- fee: Type.Number({
- description:
- 'Pancakeswap V3 fee tier in hundredths of a bip: 100 (0.01%), 500 (0.05%), 2500 (0.25%), or 10000 (1.00%)',
- enum: [100, 500, 2500, 10000],
- examples: [2500],
- }),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. If omitted, the current market price is fetched from the ' +
- 'unified swap router so the pool opens on-market and is not immediately arbitraged.',
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [600000],
- }),
- ),
-});
-
// ========================================
// Router Request Schemas
// ========================================
-// Pancakeswap-specific quote-swap request
-export const PancakeswapQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'First token in the trading pair',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Second token in the trading pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address for more accurate quotes (optional)',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
-});
-
// Pancakeswap-specific quote-swap response
export const PancakeswapQuoteSwapResponse = Type.Object({
quoteId: Type.String({
@@ -243,462 +51,3 @@ export const PancakeswapQuoteSwapResponse = Type.Object({
}),
),
});
-
-// Pancakeswap-specific execute-quote request
-export const PancakeswapExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- examples: [ethereumChainConfig.defaultWallet],
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The blockchain network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
-});
-
-// Pancakeswap AMM Add Liquidity Request
-export const PancakeswapAmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will add liquidity',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Address of the Pancakeswap V2 pool',
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap AMM Remove Liquidity Request
-export const PancakeswapAmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will remove liquidity',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Address of the Pancakeswap V2 pool',
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- }),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap AMM Execute Swap Request
-export const PancakeswapAmmExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Pool address (optional - can be looked up from tokens)',
- default: '',
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
-});
-
-// Pancakeswap-specific execute-swap request
-export const PancakeswapExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- examples: [ethereumChainConfig.defaultWallet],
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The blockchain network to use',
- default: ethereumChainConfig.defaultNetwork,
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other token in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- examples: [1],
- }),
- ),
-});
-
-// Pancakeswap CLMM Open Position Request
-export const PancakeswapClmmOpenPositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will open the position',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- }),
- poolAddress: Type.String({
- description: 'Address of the Pancakeswap V3 pool',
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap CLMM Add Liquidity Request
-export const PancakeswapClmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will add liquidity',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'NFT token ID of the position',
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap CLMM Remove Liquidity Request
-export const PancakeswapClmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will remove liquidity',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'NFT token ID of the position',
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- }),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap CLMM Close Position Request
-export const PancakeswapClmmClosePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will close the position',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'NFT token ID of the position to close',
- }),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap CLMM Collect Fees Request
-export const PancakeswapClmmCollectFeesRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will collect fees',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'NFT token ID of the position',
- }),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
-
-// Pancakeswap CLMM Execute Swap Request
-export const PancakeswapClmmExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Wallet address that will execute the swap',
- default: ethereumChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'The EVM network to use',
- default: 'bsc',
- examples: ['bsc'],
- enum: [...PancakeswapConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'Pool address (optional - can be looked up from tokens)',
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: PancakeswapConfig.config.slippagePct,
- }),
- ),
- gasPrice: Type.Optional(
- Type.String({
- description: 'Gas price in wei for the transaction',
- }),
- ),
- maxGas: Type.Optional(
- Type.Number({
- description: 'Maximum gas limit for the transaction',
- examples: [300000],
- }),
- ),
-});
diff --git a/src/connectors/raydium/amm-routes/addLiquidity.ts b/src/connectors/raydium/amm-routes/addLiquidity.ts
index 33ed4a8213..16ddb0ab4b 100644
--- a/src/connectors/raydium/amm-routes/addLiquidity.ts
+++ b/src/connectors/raydium/amm-routes/addLiquidity.ts
@@ -7,23 +7,16 @@ import {
TokenAmount,
toToken,
} from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { VersionedTransaction, Transaction, PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import {
- AddLiquidityResponse,
- AddLiquidityResponseType,
- QuoteLiquidityResponseType,
-} from '../../../schemas/amm-schema';
+import { AddLiquidityResponseType, QuoteLiquidityResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumAmmAddLiquidityRequest } from '../schemas';
import { quoteLiquidity } from './quoteLiquidity';
@@ -141,13 +134,7 @@ export async function addLiquidity(
slippagePct,
)) as QuoteLiquidityResponseType;
- const {
- baseLimited,
- baseTokenAmount: quotedBaseAmount,
- quoteTokenAmount: quotedQuoteAmount,
- baseTokenAmountMax,
- quoteTokenAmountMax,
- } = quoteResponse;
+ const { baseLimited, baseTokenAmount: quotedBaseAmount, quoteTokenAmount: quotedQuoteAmount } = quoteResponse;
const baseTokenAmountAdded = baseLimited ? baseTokenAmount : quotedBaseAmount;
const quoteTokenAmountAdded = baseLimited ? quotedQuoteAmount : quoteTokenAmount;
@@ -188,10 +175,9 @@ export async function addLiquidity(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
if (confirmed && txData) {
@@ -210,8 +196,13 @@ export async function addLiquidity(
status: 1, // CONFIRMED
data: {
fee: txData.meta.fee / 1e9,
- baseTokenAmountAdded: baseTokenBalanceChange,
- quoteTokenAmountAdded: quoteTokenBalanceChange,
+ // Magnitudes, not the raw wallet delta. A deposit moves tokens out, so the
+ // signed change is negative and a field named `…Added` would report a negative
+ // deposit — which is what every consumer summing these rows then has to guess
+ // about. Every other connector, and the whole removed side including Raydium's
+ // own, reports magnitudes.
+ baseTokenAmountAdded: Math.abs(baseTokenBalanceChange),
+ quoteTokenAmountAdded: Math.abs(quoteTokenBalanceChange),
},
};
} else {
@@ -221,37 +212,3 @@ export async function addLiquidity(
};
}
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- // const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to a Raydium AMM/CPMM pool',
- tags: ['/connector/raydium'],
- body: RaydiumAmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct } = request.body;
-
- return await addLiquidity(network, walletAddress, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/raydium/amm-routes/createPool.ts b/src/connectors/raydium/amm-routes/createPool.ts
index 39a9d54a4c..7e3f28f7a3 100644
--- a/src/connectors/raydium/amm-routes/createPool.ts
+++ b/src/connectors/raydium/amm-routes/createPool.ts
@@ -5,20 +5,17 @@ import {
DEV_CREATE_CPMM_POOL_PROGRAM,
DEV_CREATE_CPMM_POOL_FEE_ACC,
} from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
-import { RaydiumAmmCreatePoolRequest } from '../schemas';
/** Resolves a token symbol or mint address to a PublicKey. */
async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
@@ -53,10 +50,10 @@ async function fetchMarketPrice(
quoteToken: string,
amount: number,
): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, amount, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, amount, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to seed the pool (${e.message}). ` +
@@ -186,10 +183,9 @@ export async function createPool(
logger.info(`Creating Raydium CPMM pool ${poolAddress} (${baseToken}/${quoteToken})`);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, [
@@ -210,54 +206,3 @@ export async function createPool(
}
return { signature, status: 0, poolAddress, price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description: 'Create a new Raydium CPMM (CP-Swap) pool and seed it with initial liquidity',
- tags: ['/connector/raydium'],
- body: RaydiumAmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- feeConfigIndex,
- openTime,
- } = request.body;
- return await createPool(
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- feeConfigIndex,
- openTime,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/raydium/amm-routes/executeSwap.ts b/src/connectors/raydium/amm-routes/executeSwap.ts
index 273e56f1c4..c649d95c07 100644
--- a/src/connectors/raydium/amm-routes/executeSwap.ts
+++ b/src/connectors/raydium/amm-routes/executeSwap.ts
@@ -1,15 +1,13 @@
import { PublicKey, VersionedTransaction } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteSwapResponse, ExecuteSwapResponseType, ExecuteSwapRequestType } from '../../../schemas/amm-schema';
+import { ExecuteSwapResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumAmmExecuteSwapRequest } from '../schemas';
import { getRawSwapQuote } from './quoteSwap';
@@ -156,20 +154,19 @@ export async function executeSwap(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
// Handle confirmation status
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
side,
+ effectiveSlippage,
);
if (result.status === 1) {
@@ -180,94 +177,3 @@ export async function executeSwap(
return result as ExecuteSwapResponseType;
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on Raydium AMM or CPMM',
- tags: ['/connector/raydium'],
- body: {
- ...RaydiumAmmExecuteSwapRequest,
- properties: {
- ...RaydiumAmmExecuteSwapRequest.properties,
- network: { type: 'string', default: 'mainnet-beta' },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- baseToken: { type: 'string', examples: ['SOL'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- amount: { type: 'number', examples: [0.01] },
- side: { type: 'string', examples: ['SELL'] },
- poolAddress: { type: 'string', examples: [''] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: { 200: ExecuteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, amount, side, poolAddress, slippagePct } =
- request.body as typeof RaydiumAmmExecuteSwapRequest._type;
- const networkToUse = network;
-
- // If no pool address provided, find default pool
- let poolAddressToUse = poolAddress;
- if (!poolAddressToUse) {
- const solana = await Solana.getInstance(networkToUse);
-
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'raydium',
- networkToUse,
- 'amm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No AMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Raydium`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- return await executeSwap(
- networkToUse,
- walletAddress,
- poolAddressToUse,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Swap execution failed');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/raydium/amm-routes/index.ts b/src/connectors/raydium/amm-routes/index.ts
deleted file mode 100644
index a9071694b3..0000000000
--- a/src/connectors/raydium/amm-routes/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { addLiquidityRoute } from './addLiquidity';
-import { createPoolRoute } from './createPool';
-import { executeSwapRoute } from './executeSwap';
-import { poolInfoRoute } from './poolInfo';
-import { positionInfoRoute } from './positionInfo';
-import { quoteLiquidityRoute } from './quoteLiquidity';
-import { quoteSwapRoute } from './quoteSwap';
-import { removeLiquidityRoute } from './removeLiquidity';
-
-export const raydiumAmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quoteLiquidityRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(createPoolRoute);
-};
-
-export default raydiumAmmRoutes;
diff --git a/src/connectors/raydium/amm-routes/poolInfo.ts b/src/connectors/raydium/amm-routes/poolInfo.ts
index 23669b496c..c0c3a57953 100644
--- a/src/connectors/raydium/amm-routes/poolInfo.ts
+++ b/src/connectors/raydium/amm-routes/poolInfo.ts
@@ -1,10 +1,6 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/amm-schema';
+import { PoolInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { RaydiumAmmGetPoolInfoRequest } from '../schemas';
/**
* Standardized network-first pool-info fetcher for the Raydium AMM/CPMM connector.
@@ -20,34 +16,3 @@ export async function getPoolInfo(network: string, poolAddress: string): Promise
const { poolType, ...basePoolInfo } = poolInfo;
return basePoolInfo;
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: Record;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get AMM pool information from Raydium',
- tags: ['/connector/raydium'],
- querystring: RaydiumAmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, network } = request.query;
- return await getPoolInfo(network, poolAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Failed to fetch pool info');
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/raydium/amm-routes/positionInfo.ts b/src/connectors/raydium/amm-routes/positionInfo.ts
index 1b7de916fd..cc8b02274e 100644
--- a/src/connectors/raydium/amm-routes/positionInfo.ts
+++ b/src/connectors/raydium/amm-routes/positionInfo.ts
@@ -1,14 +1,9 @@
-import { BN } from '@coral-xyz/anchor';
import { PublicKey } from '@solana/web3.js';
-import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { PositionInfo, PositionInfoSchema, GetPositionInfoRequestType } from '../../../schemas/amm-schema';
+import { PositionInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { RaydiumAmmGetPositionInfoRequest } from '../schemas';
/**
* Calculate the LP token amount and corresponding token amounts
@@ -105,7 +100,7 @@ export async function getPositionInfo(
// Get pool info
const ammPoolInfo = await raydium.getAmmPoolInfo(poolAddress);
- const [poolInfo, poolKeys] = await raydium.getPoolfromAPI(poolAddress);
+ const [poolInfo] = await raydium.getPoolfromAPI(poolAddress);
if (!poolInfo) {
throw httpErrors.notFound('Pool not found');
}
@@ -130,36 +125,3 @@ export async function getPositionInfo(
price: poolInfo.price,
};
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get info about a Raydium AMM position',
- tags: ['/connector/raydium'],
- querystring: RaydiumAmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { poolAddress, walletAddress } = request.query;
- const network = request.query.network;
-
- return await getPositionInfo(network, poolAddress, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Failed to fetch position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/raydium/amm-routes/quoteLiquidity.ts b/src/connectors/raydium/amm-routes/quoteLiquidity.ts
index 50f886ee07..2d09f699d3 100644
--- a/src/connectors/raydium/amm-routes/quoteLiquidity.ts
+++ b/src/connectors/raydium/amm-routes/quoteLiquidity.ts
@@ -5,19 +5,13 @@ import {
TokenAmount,
} from '@raydium-io/raydium-sdk-v2';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import {
- QuoteLiquidityRequestType,
- QuoteLiquidityResponse,
- QuoteLiquidityResponseType,
-} from '../../../schemas/amm-schema';
+import { QuoteLiquidityResponseType } from '../../../schemas/amm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
import { isValidAmm, isValidCpmm } from '../raydium.utils';
-import { RaydiumAmmQuoteLiquidityRequest } from '../schemas';
interface AmmComputePairResult {
anotherAmount: TokenAmount;
@@ -64,7 +58,7 @@ export async function quoteLiquidity(
const solana = await Solana.getInstance(network);
const raydium = await Raydium.getInstance(network);
- const [poolInfo, poolKeys] = await raydium.getPoolfromAPI(poolAddress);
+ const [poolInfo] = await raydium.getPoolfromAPI(poolAddress);
const programId = poolInfo.programId;
if (!isValidAmm(programId) && !isValidCpmm(programId)) {
@@ -209,39 +203,3 @@ export async function quoteLiquidity(
throw error;
}
}
-
-export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteLiquidityRequestType;
- Reply: QuoteLiquidityResponseType | { error: string };
- }>(
- '/quote-liquidity',
- {
- schema: {
- description: 'Quote amounts for a new Raydium AMM liquidity position',
- tags: ['/connector/raydium'],
- querystring: RaydiumAmmQuoteLiquidityRequest,
- response: {
- 200: QuoteLiquidityResponse,
- 500: {
- type: 'object',
- properties: { error: { type: 'string' } },
- },
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct } = request.query;
-
- return await quoteLiquidity(network, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to quote position');
- }
- },
- );
-};
-
-export default quoteLiquidityRoute;
diff --git a/src/connectors/raydium/amm-routes/quoteSwap.ts b/src/connectors/raydium/amm-routes/quoteSwap.ts
index bd56d36f6a..de750d2170 100644
--- a/src/connectors/raydium/amm-routes/quoteSwap.ts
+++ b/src/connectors/raydium/amm-routes/quoteSwap.ts
@@ -2,17 +2,14 @@ import { ApiV3PoolInfoStandardItem, ApiV3PoolInfoStandardItemCpmm, CurveCalculat
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import Decimal from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
-import { estimateGasSolana } from '../../../chains/solana/routes/estimate-gas';
import { Solana } from '../../../chains/solana/solana';
-import { QuoteSwapResponseType, QuoteSwapResponse, QuoteSwapRequestType } from '../../../schemas/amm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumAmmQuoteSwapRequest } from '../schemas';
async function quoteAmmSwap(
raydium: Raydium,
@@ -25,14 +22,12 @@ async function quoteAmmSwap(
slippagePct: number = RaydiumConfig.config.slippagePct,
): Promise {
let poolInfo: ApiV3PoolInfoStandardItem;
- let poolKeys: any;
let rpcData: any;
if (network === 'mainnet-beta') {
// note: api doesn't support get devnet pool info, so in devnet else we go rpc method
- const [poolInfoData, poolKeysData] = await raydium.getPoolfromAPI(poolId);
+ const [poolInfoData] = await raydium.getPoolfromAPI(poolId);
poolInfo = poolInfoData as ApiV3PoolInfoStandardItem;
- poolKeys = poolKeysData;
rpcData = await raydium.raydiumSDK.liquidity.getRpcPoolInfo(poolId);
} else {
// note: getPoolInfoFromRpc method only returns required pool data for computing not all detail pool info
@@ -40,7 +35,6 @@ async function quoteAmmSwap(
poolId,
});
poolInfo = data.poolInfo;
- poolKeys = data.poolKeys;
rpcData = data.poolRpcData;
}
@@ -124,18 +118,15 @@ async function quoteCpmmSwap(
slippagePct: number = RaydiumConfig.config.slippagePct,
): Promise {
let poolInfo: ApiV3PoolInfoStandardItemCpmm;
- let poolKeys: any;
let rpcData: any;
if (network === 'mainnet-beta') {
- const [poolInfoData, poolKeysData] = await raydium.getPoolfromAPI(poolId);
+ const [poolInfoData] = await raydium.getPoolfromAPI(poolId);
poolInfo = poolInfoData as ApiV3PoolInfoStandardItemCpmm;
- poolKeys = poolKeysData;
rpcData = await raydium.raydiumSDK.cpmm.getRpcPoolInfo(poolInfo.id, true);
} else {
const data = await raydium.raydiumSDK.cpmm.getPoolInfoFromRpc(poolId);
poolInfo = data.poolInfo;
- poolKeys = data.poolKeys;
rpcData = data.rpcData;
}
@@ -462,7 +453,6 @@ async function formatSwapQuote(
const tokenOut = side === 'SELL' ? resolvedQuoteToken.address : resolvedBaseToken.address;
// Calculate fee and price impact
- const fee = quote.fee ? new Decimal(quote.fee.toString()).div(10 ** inputToken.decimals).toNumber() : 0;
const priceImpactPct = quote.priceImpact ? quote.priceImpact * 100 : 0;
return {
@@ -480,106 +470,6 @@ async function formatSwapQuote(
};
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Raydium AMM',
- tags: ['/connector/raydium'],
- querystring: RaydiumAmmQuoteSwapRequest,
- response: {
- 200: QuoteSwapResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseToken, quoteToken, amount, side, slippagePct } = request.query;
- const networkToUse = network;
-
- // Validate essential parameters
- if (!baseToken || !quoteToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, quoteToken, amount, and side are required');
- }
-
- const raydium = await Raydium.getInstance(networkToUse);
- const solana = await Solana.getInstance(networkToUse);
-
- let poolAddressToUse = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressToUse) {
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'raydium',
- networkToUse,
- 'amm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No AMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Raydium`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- const result = await quoteSwap(
- networkToUse,
- poolAddressToUse,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
-
- let gasEstimation = null;
- try {
- gasEstimation = await estimateGasSolana(networkToUse);
- } catch (error) {
- logger.warn(`Failed to estimate gas for swap quote: ${error.message}`);
- }
-
- return result;
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- if (e.message?.includes('Pool not found')) {
- throw httpErrors.notFound(e.message);
- }
- if (e.message?.includes('Token not found')) {
- throw httpErrors.badRequest(e.message);
- }
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Standardized network-first swap quote for the Raydium AMM/CPMM connector.
* `amount` is denominated in the base token; the counter ("quote") token is derived from the pool.
diff --git a/src/connectors/raydium/amm-routes/removeLiquidity.ts b/src/connectors/raydium/amm-routes/removeLiquidity.ts
index 806801bcc3..43d07e067b 100644
--- a/src/connectors/raydium/amm-routes/removeLiquidity.ts
+++ b/src/connectors/raydium/amm-routes/removeLiquidity.ts
@@ -5,19 +5,16 @@ import {
ApiV3PoolInfoStandardItemCpmm,
Percent,
} from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { VersionedTransaction, Transaction, PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { RemoveLiquidityResponse, RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumAmmRemoveLiquidityRequest } from '../schemas';
// Interfaces for SDK responses
interface TokenBurnInfo {
@@ -189,10 +186,9 @@ export async function removeLiquidity(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
if (confirmed && txData) {
@@ -227,37 +223,3 @@ export async function removeLiquidity(
};
}
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- // const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from a Raydium AMM/CPMM pool',
- tags: ['/connector/raydium'],
- body: RaydiumAmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, poolAddress, percentageToRemove } = request.body;
-
- return await removeLiquidity(network, walletAddress, poolAddress, percentageToRemove);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/raydium/clmm-routes/addLiquidity.ts b/src/connectors/raydium/clmm-routes/addLiquidity.ts
index f697aaef23..8af55f635e 100644
--- a/src/connectors/raydium/clmm-routes/addLiquidity.ts
+++ b/src/connectors/raydium/clmm-routes/addLiquidity.ts
@@ -1,16 +1,12 @@
import { TxVersion } from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { AddLiquidityResponse, AddLiquidityResponseType } from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { AddLiquidityResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumClmmAddLiquidityRequest } from '../schemas';
import { quotePosition } from './quotePosition';
@@ -34,7 +30,7 @@ export async function addLiquidity(
const position = await raydium.getClmmPosition(positionAddress);
if (!position) throw new Error('Position not found');
- const [poolInfo, poolKeys] = await raydium.getClmmPoolfromAPI(positionInfo.poolAddress);
+ const [poolInfo] = await raydium.getClmmPoolfromAPI(positionInfo.poolAddress);
// const clmmPool = await raydium.getClmmPoolfromRPC(positionInfo.poolAddress);
const baseToken = await solana.getToken(poolInfo.mintA.address);
@@ -49,7 +45,6 @@ export async function addLiquidity(
quoteTokenAmount,
slippagePct,
);
- console.log('quotePositionResponse', quotePositionResponse);
logger.info('Adding liquidity to Raydium CLMM position...');
// Use hardcoded compute units for add liquidity
@@ -81,10 +76,9 @@ export async function addLiquidity(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
if (confirmed && txData) {
@@ -112,7 +106,6 @@ export async function addLiquidity(
const { balanceChanges } = await solana.extractBalanceChangesAndFee(signature, walletAddress, tokenAddresses);
// Parse balance changes
- const solChangeIndex = 0;
const baseChangeIndex = isBaseSol ? 0 : 1;
const quoteChangeIndex = isQuoteSol ? 0 : isBaseSol ? 1 : 2;
@@ -123,9 +116,16 @@ export async function addLiquidity(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.poolId.toBase58(),
fee: totalFee / 1e9,
- baseTokenAmountAdded: baseTokenBalanceChange,
- quoteTokenAmountAdded: quoteTokenBalanceChange,
+ // Magnitudes, as everywhere else: a deposit's signed wallet delta is negative,
+ // and `…Added` naming a negative number is wrong at the source. Adding to an
+ // existing position locks no new rent, so there is nothing to back out.
+ baseTokenAmountAdded: Math.abs(baseTokenBalanceChange),
+ quoteTokenAmountAdded: Math.abs(quoteTokenBalanceChange),
},
};
} else {
@@ -136,43 +136,3 @@ export async function addLiquidity(
};
}
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to existing Raydium CLMM position',
- tags: ['/connector/raydium'],
- body: RaydiumClmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress, baseTokenAmount, quoteTokenAmount, slippagePct } =
- request.body;
-
- return await addLiquidity(
- network,
- walletAddress,
- positionAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/raydium/clmm-routes/closePosition.ts b/src/connectors/raydium/clmm-routes/closePosition.ts
index 8336fe294f..fc46d849be 100644
--- a/src/connectors/raydium/clmm-routes/closePosition.ts
+++ b/src/connectors/raydium/clmm-routes/closePosition.ts
@@ -1,14 +1,12 @@
import { TxVersion } from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ClosePositionResponse, ClosePositionResponseType } from '../../../schemas/clmm-schema';
+import { liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { ClosePositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { RaydiumClmmClosePositionRequest } from '../schemas';
import { removeLiquidity } from './removeLiquidity';
@@ -39,24 +37,34 @@ export async function closePosition(
if (removeLiquidityResponse.status === 1 && removeLiquidityResponse.data) {
// Use the new helper to extract balance changes including SOL handling
- const { baseTokenChange, quoteTokenChange, rent } = await solana.extractClmmBalanceChanges(
+ const { baseTokenChange, quoteTokenChange, rent, accountSol } = await solana.extractClmmBalanceChanges(
removeLiquidityResponse.signature,
walletAddress,
baseTokenInfo,
quoteTokenInfo,
- removeLiquidityResponse.data.fee * 1e9,
);
- // The total balance change includes both liquidity removal and fee collection
- // Since we know the liquidity amounts from removeLiquidity response,
- // we can calculate the fee amounts
- const baseFeeCollected = Math.abs(baseTokenChange) - removeLiquidityResponse.data.baseTokenAmountRemoved;
- const quoteFeeCollected = Math.abs(quoteTokenChange) - removeLiquidityResponse.data.quoteTokenAmountRemoved;
+ // The total balance change includes both liquidity removal and fee collection.
+ // Since we know the liquidity amounts from the removeLiquidity response, the fee
+ // is the difference — but only if both sides are measured the same way. The
+ // removal already took the closed accounts' lamports off its native side, so this
+ // one has to as well; measuring one net of rent against the other gross of it
+ // would book the rent as fee income.
+ const baseFeeCollected =
+ liquidityWithoutRent(baseTokenChange, new PublicKey(baseTokenInfo.address), accountSol) -
+ removeLiquidityResponse.data.baseTokenAmountRemoved;
+ const quoteFeeCollected =
+ liquidityWithoutRent(quoteTokenChange, new PublicKey(quoteTokenInfo.address), accountSol) -
+ removeLiquidityResponse.data.quoteTokenAmountRemoved;
return {
signature: removeLiquidityResponse.signature,
status: removeLiquidityResponse.status,
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.poolId.toBase58(),
fee: removeLiquidityResponse.data.fee,
positionRentRefunded: rent,
baseTokenAmountRemoved: removeLiquidityResponse.data.baseTokenAmountRemoved,
@@ -102,10 +110,9 @@ export async function closePosition(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(result.transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
if (!confirmed || !txData) {
@@ -123,6 +130,9 @@ export async function closePosition(
signature,
status: 1, // CONFIRMED
data: {
+ // Same pool as the branch above — this is the already-empty position path, which
+ // closes the account without a withdrawal, so it must name its venue too.
+ poolAddress: position.poolId.toBase58(),
fee,
positionRentRefunded: rentRefunded,
baseTokenAmountRemoved: 0,
@@ -136,40 +146,3 @@ export async function closePosition(
throw error;
}
}
-
-export const closePositionRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: ClosePositionResponseType;
- }>(
- '/close-position',
- {
- schema: {
- description: 'Close a Raydium CLMM position',
- tags: ['/connector/raydium'],
- body: RaydiumClmmClosePositionRequest,
- response: {
- 200: ClosePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress } = request.body;
- const networkToUse = network;
-
- return await closePosition(networkToUse, walletAddress, positionAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default closePositionRoute;
diff --git a/src/connectors/raydium/clmm-routes/collectFees.ts b/src/connectors/raydium/clmm-routes/collectFees.ts
index fd26cbe2a3..f11b301873 100644
--- a/src/connectors/raydium/clmm-routes/collectFees.ts
+++ b/src/connectors/raydium/clmm-routes/collectFees.ts
@@ -1,19 +1,22 @@
+import { TxVersion } from '@raydium-io/raydium-sdk-v2';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
+import BN from 'bn.js';
import { Solana } from '../../../chains/solana/solana';
-import {
- CollectFeesRequest,
- CollectFeesResponse,
- CollectFeesRequestType,
- CollectFeesResponseType,
-} from '../../../schemas/clmm-schema';
+import { CollectFeesResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { removeLiquidity } from './removeLiquidity';
-
+/**
+ * Collect accumulated fees from a position WITHOUT touching its liquidity.
+ *
+ * The Raydium CLMM program has no owner-facing "collect fees" instruction — fees owed
+ * to a position are transferred by decrease_liquidity. Calling it with liquidity = 0
+ * collects what is owed and leaves the position intact. This route used to remove 1%
+ * of the position and report the withdrawn principal as fees, which both mutated the
+ * position and mis-stated the amounts.
+ */
export async function collectFees(
network: string,
walletAddress: string,
@@ -23,8 +26,7 @@ export async function collectFees(
const raydium = await Raydium.getInstance(network);
// Set the SDK owner to the wallet's public key — works for every wallet type (local,
- // hardware). The actual liquidity removal (and signing/sending) is delegated to
- // removeLiquidity below.
+ // hardware). The tx is built unsigned; signing/sending is delegated below.
await raydium.setOwner(new PublicKey(walletAddress));
const position = await raydium.getClmmPosition(positionAddress);
@@ -32,94 +34,70 @@ export async function collectFees(
throw httpErrors.notFound(`Position not found: ${positionAddress}`);
}
- const [poolInfo] = await raydium.getClmmPoolfromAPI(position.poolId.toBase58());
+ const [poolInfo, poolKeys] = await raydium.getClmmPoolfromAPI(position.poolId.toBase58());
const tokenA = await solana.getToken(poolInfo.mintA.address);
const tokenB = await solana.getToken(poolInfo.mintB.address);
- logger.info(`Collecting fees from CLMM position ${positionAddress} by removing 1% liquidity`);
+ logger.info(`Collecting fees from CLMM position ${positionAddress} via zero-liquidity decrease`);
+
+ const COMPUTE_UNITS = 600000;
+ const priorityFeeInLamports = await solana.estimateGasPrice();
+ const priorityFeePerCU = Math.floor(priorityFeeInLamports * 1e6);
+
+ const { transaction } = await raydium.raydiumSDK.clmm.decreaseLiquidity({
+ poolInfo,
+ poolKeys,
+ ownerPosition: position,
+ ownerInfo: {
+ useSOLBalance: true,
+ closePosition: false,
+ },
+ liquidity: new BN(0), // collect fees only; principal untouched
+ amountMinA: new BN(0),
+ amountMinB: new BN(0),
+ txVersion: TxVersion.V0,
+ computeBudgetConfig: {
+ units: COMPUTE_UNITS,
+ microLamports: priorityFeePerCU,
+ },
+ });
- // Remove 1% of liquidity to collect fees
- const removeLiquidityResponse = await removeLiquidity(
- network,
- walletAddress,
- positionAddress,
- 1, // 1% of position
- false, // don't close position
- );
+ const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
- if (removeLiquidityResponse.status === 1 && removeLiquidityResponse.data) {
- // Use the new helper to extract balance changes including fees
+ if (txData) {
+ // No liquidity moved, so the whole balance change is fees.
const { baseTokenChange, quoteTokenChange } = await solana.extractClmmBalanceChanges(
- removeLiquidityResponse.signature,
+ signature,
walletAddress,
tokenA,
tokenB,
- removeLiquidityResponse.data.fee * 1e9,
);
- // The total balance change includes both liquidity removal and fee collection
- // Since we know the liquidity amounts from removeLiquidity response,
- // we can calculate the fee amounts
- const baseFeeCollected = Math.abs(baseTokenChange) - removeLiquidityResponse.data.baseTokenAmountRemoved;
- const quoteFeeCollected = Math.abs(quoteTokenChange) - removeLiquidityResponse.data.quoteTokenAmountRemoved;
-
logger.info(
- `Fees collected from position ${positionAddress}: ${Math.max(0, baseFeeCollected).toFixed(4)} ${tokenA.symbol}, ${Math.max(0, quoteFeeCollected).toFixed(4)} ${tokenB.symbol}`,
+ `Fees collected from position ${positionAddress}: ${Math.abs(baseTokenChange).toFixed(4)} ${tokenA.symbol}, ${Math.abs(quoteTokenChange).toFixed(4)} ${tokenB.symbol}`,
);
return {
- signature: removeLiquidityResponse.signature,
+ signature,
status: 1, // CONFIRMED
data: {
- fee: removeLiquidityResponse.data.fee,
- baseFeeAmountCollected: Math.max(0, baseFeeCollected),
- quoteFeeAmountCollected: Math.max(0, quoteFeeCollected),
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: position.poolId.toBase58(),
+ fee: txData.meta.fee / 1e9,
+ baseFeeAmountCollected: Math.abs(baseTokenChange),
+ quoteFeeAmountCollected: Math.abs(quoteTokenChange),
},
};
- } else {
- // Return pending status
- return {
- signature: removeLiquidityResponse.signature,
- status: removeLiquidityResponse.status,
- };
}
-}
-
-export const collectFeesRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
- fastify.post<{
- Body: CollectFeesRequestType;
- Reply: CollectFeesResponseType;
- }>(
- '/collect-fees',
- {
- schema: {
- description: 'Collect fees from a Raydium CLMM position by removing 1% of liquidity',
- tags: ['/connector/raydium'],
- body: {
- ...CollectFeesRequest,
- properties: {
- ...CollectFeesRequest.properties,
- network: { type: 'string', default: 'mainnet-beta' },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- },
- },
- response: { 200: CollectFeesResponse },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress } = request.body;
- return await collectFees(network, walletAddress, positionAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Failed to collect fees');
- }
- },
- );
-};
-
-export default collectFeesRoute;
+ return {
+ signature,
+ status: 0, // PENDING
+ };
+}
diff --git a/src/connectors/raydium/clmm-routes/createPool.ts b/src/connectors/raydium/clmm-routes/createPool.ts
index c6d4ed0344..5e1e6aca00 100644
--- a/src/connectors/raydium/clmm-routes/createPool.ts
+++ b/src/connectors/raydium/clmm-routes/createPool.ts
@@ -5,19 +5,16 @@ import {
CLMM_PROGRAM_ID,
DEVNET_PROGRAM_ID,
} from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint } from '@solana/spl-token';
import { Keypair, PublicKey } from '@solana/web3.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
-import { RaydiumClmmCreatePoolRequest } from '../schemas';
/** Resolves a token symbol or mint address to a PublicKey. */
async function resolveMint(solana: Solana, tokenOrAddress: string): Promise {
@@ -62,11 +59,11 @@ function toApiV3Token(mint: PublicKey, decimals: number, programId: PublicKey):
* route exists.
*/
async function fetchMarketPrice(network: string, baseToken: string, quoteToken: string): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
// Probe with 1 base token — we only need the price ratio, not a real trade size.
- quote = await getUnifiedQuoteSwap(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
+ quote = await getSwapQuote(`solana-${network}`, baseToken, quoteToken, 1, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to initialize the pool (${e.message}). ` +
@@ -184,10 +181,9 @@ export async function createPool(
walletAddress,
(sdkSigners as Keypair[]) ?? [],
);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
if (txData) {
return {
@@ -197,43 +193,8 @@ export async function createPool(
price: seedPrice,
data: {
fee: txData.meta.fee / 1e9,
- // Pool created + initialized only — no liquidity/position seeded.
- baseTokenAmountAdded: 0,
- quoteTokenAmountAdded: 0,
},
};
}
return { signature, status: 0, poolAddress, price: seedPrice }; // PENDING
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description:
- 'Create and initialize a new Raydium CLMM pool at an initial price. Does not open or seed a position.',
- tags: ['/connector/raydium'],
- body: RaydiumClmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, initialPrice, ammConfigIndex } = request.body;
- return await createPool(network, walletAddress, baseToken, quoteToken, initialPrice, ammConfigIndex);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/raydium/clmm-routes/executeSwap.ts b/src/connectors/raydium/clmm-routes/executeSwap.ts
index beeb39a39b..0bd3e83027 100644
--- a/src/connectors/raydium/clmm-routes/executeSwap.ts
+++ b/src/connectors/raydium/clmm-routes/executeSwap.ts
@@ -1,15 +1,13 @@
import { ReturnTypeComputeAmountOutFormat, ReturnTypeComputeAmountOutBaseOut } from '@raydium-io/raydium-sdk-v2';
import { PublicKey, VersionedTransaction } from '@solana/web3.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteSwapResponse, ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
+import { ExecuteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumClmmExecuteSwapRequest, RaydiumClmmExecuteSwapRequestType } from '../schemas';
import { getSwapQuote, resolveCounterToken } from './quoteSwap';
@@ -154,20 +152,19 @@ export async function executeSwap(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
// Handle confirmation status
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
side,
+ slippagePct,
);
if (result.status === 1) {
@@ -178,80 +175,3 @@ export async function executeSwap(
return result as ExecuteSwapResponseType;
}
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: RaydiumClmmExecuteSwapRequestType;
- Reply: ExecuteSwapResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on Raydium CLMM',
- tags: ['/connector/raydium'],
- body: RaydiumClmmExecuteSwapRequest,
- response: { 200: ExecuteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, baseToken, quoteToken, amount, side, poolAddress, slippagePct } = request.body;
- const networkToUse = network;
-
- // If no pool address provided, find default pool
- let poolAddressToUse = poolAddress;
- if (!poolAddressToUse) {
- const solana = await Solana.getInstance(networkToUse);
-
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'raydium',
- networkToUse,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Raydium`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- return await executeSwap(
- networkToUse,
- walletAddress,
- poolAddressToUse,
- baseToken,
- side as 'BUY' | 'SELL',
- amount,
- slippagePct,
- );
- } catch (e) {
- // Preserve the original error if it's a FastifyError
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to get swap quote');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/raydium/clmm-routes/index.ts b/src/connectors/raydium/clmm-routes/index.ts
deleted file mode 100644
index d5b2724ac9..0000000000
--- a/src/connectors/raydium/clmm-routes/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { addLiquidityRoute } from './addLiquidity';
-import { closePositionRoute } from './closePosition';
-import { collectFeesRoute } from './collectFees';
-import { createPoolRoute } from './createPool';
-import { executeSwapRoute } from './executeSwap';
-import { openPositionRoute } from './openPosition';
-import { poolInfoRoute } from './poolInfo';
-import { positionInfoRoute } from './positionInfo';
-import { positionsOwnedRoute } from './positionsOwned';
-import { quotePositionRoute } from './quotePosition';
-import { quoteSwapRoute } from './quoteSwap';
-import { removeLiquidityRoute } from './removeLiquidity';
-
-export const raydiumClmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionsOwnedRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quotePositionRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(openPositionRoute);
- await fastify.register(createPoolRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(removeLiquidityRoute);
- await fastify.register(collectFeesRoute);
- await fastify.register(closePositionRoute);
-};
-
-export default raydiumClmmRoutes;
diff --git a/src/connectors/raydium/clmm-routes/openPosition.ts b/src/connectors/raydium/clmm-routes/openPosition.ts
index 5f046e2903..1015ff6856 100644
--- a/src/connectors/raydium/clmm-routes/openPosition.ts
+++ b/src/connectors/raydium/clmm-routes/openPosition.ts
@@ -1,17 +1,15 @@
import { TxVersion, TickUtils } from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { Keypair, PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { OpenPositionResponse, OpenPositionResponseType } from '../../../schemas/clmm-schema';
+import { liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { OpenPositionResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumClmmOpenPositionRequest } from '../schemas';
import { quotePosition } from './quotePosition';
@@ -112,10 +110,9 @@ export async function openPosition(
walletAddress,
(sdkSigners as Keypair[]) ?? [],
);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
// Return with status
@@ -124,12 +121,11 @@ export async function openPosition(
const totalFee = txData.meta.fee;
// Use the new helper method to extract balance changes
- const { baseTokenChange, quoteTokenChange, rent } = await solana.extractClmmBalanceChanges(
+ const { baseTokenChange, quoteTokenChange, rent, accountSol } = await solana.extractClmmBalanceChanges(
signature,
walletAddress,
baseTokenInfo,
quoteTokenInfo,
- totalFee,
);
return {
@@ -139,8 +135,16 @@ export async function openPosition(
fee: totalFee / 1e9,
positionAddress: extInfo.nftMint.toBase58(),
positionRent: rent,
- baseTokenAmountAdded: baseTokenChange,
- quoteTokenAmountAdded: quoteTokenChange,
+ // Opening a position locks rent in the accounts it creates, and when one side is
+ // SOL that outflow sits inside its balance change — so the raw delta is both
+ // negative and larger than the deposit. The same helper the DAMM v2 open uses
+ // takes the magnitude and backs the accounts' lamports off the native side only.
+ baseTokenAmountAdded: liquidityWithoutRent(baseTokenChange, new PublicKey(baseTokenInfo.address), accountSol),
+ quoteTokenAmountAdded: liquidityWithoutRent(
+ quoteTokenChange,
+ new PublicKey(quoteTokenInfo.address),
+ accountSol,
+ ),
},
};
} else {
@@ -151,58 +155,3 @@ export async function openPosition(
};
}
}
-
-export const openPositionRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Solana.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: OpenPositionResponseType;
- }>(
- '/open-position',
- {
- schema: {
- description: 'Open a new Raydium CLMM position',
- tags: ['/connector/raydium'],
- body: RaydiumClmmOpenPositionRequest,
- response: {
- 200: OpenPositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- walletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.body;
- const networkToUse = network;
-
- return await openPosition(
- networkToUse,
- walletAddress,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default openPositionRoute;
diff --git a/src/connectors/raydium/clmm-routes/poolInfo.ts b/src/connectors/raydium/clmm-routes/poolInfo.ts
index 72ce5d5f99..d385bf48bd 100644
--- a/src/connectors/raydium/clmm-routes/poolInfo.ts
+++ b/src/connectors/raydium/clmm-routes/poolInfo.ts
@@ -1,11 +1,10 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { PoolInfo, PoolInfoSchema } from '../../../schemas/clmm-schema';
+import { PoolInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { computeRaydiumBinDistribution } from '../raydium.utils';
-import { RaydiumClmmGetPoolInfoRequest, RaydiumClmmGetPoolInfoRequestType } from '../schemas';
export async function getPoolInfo(
fastify: FastifyInstance,
@@ -57,34 +56,3 @@ export async function getPoolInfo(
return poolInfo;
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: RaydiumClmmGetPoolInfoRequestType;
- Reply: Record;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get CLMM pool information from Raydium',
- tags: ['/connector/raydium'],
- querystring: RaydiumClmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, binCount = 0, network } = request.query;
- return await getPoolInfo(fastify, network, poolAddress, binCount);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to fetch pool info');
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/raydium/clmm-routes/positionInfo.ts b/src/connectors/raydium/clmm-routes/positionInfo.ts
index 8310c10caf..24735f6170 100644
--- a/src/connectors/raydium/clmm-routes/positionInfo.ts
+++ b/src/connectors/raydium/clmm-routes/positionInfo.ts
@@ -1,8 +1,7 @@
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
-import { PositionInfo, PositionInfoSchema, GetPositionInfoRequestType } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { Raydium } from '../raydium';
-import { RaydiumClmmGetPositionInfoRequest } from '../schemas';
export async function getPositionInfo(
fastify: FastifyInstance,
@@ -23,33 +22,3 @@ export async function getPositionInfo(
return positionInfo;
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get info about a Raydium CLMM position',
- tags: ['/connector/raydium'],
- querystring: RaydiumClmmGetPositionInfoRequest,
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { network = 'mainnet-beta', positionAddress } = request.query;
- return await getPositionInfo(fastify, network, positionAddress);
- } catch (e) {
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Failed to fetch position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/raydium/clmm-routes/positionsOwned.ts b/src/connectors/raydium/clmm-routes/positionsOwned.ts
index fb683007d1..357b986b85 100644
--- a/src/connectors/raydium/clmm-routes/positionsOwned.ts
+++ b/src/connectors/raydium/clmm-routes/positionsOwned.ts
@@ -1,19 +1,12 @@
-import { Type, Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
-import { FastifyPluginAsync, FastifyInstance } from 'fastify';
+import { FastifyInstance } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { PositionInfoSchema, PositionInfo } from '../../../schemas/clmm-schema';
+import { PositionInfo } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { RaydiumClmmGetPositionsOwnedRequest, RaydiumClmmGetPositionsOwnedRequestType } from '../schemas';
// Using Fastify's native error handling
-const INVALID_SOLANA_ADDRESS_MESSAGE = (address: string) => `Invalid Solana address: ${address}`;
-
-const GetPositionsOwnedResponse = Type.Array(PositionInfoSchema);
-
-type GetPositionsOwnedResponseType = Static;
export async function getPositionsOwned(
fastify: FastifyInstance,
@@ -84,38 +77,3 @@ async function fetchPositionsFromRPC(_solana: Solana, network: string, walletAdd
logger.info(`Found ${allPositions.length} Raydium position(s) for wallet ${walletAddress.slice(0, 8)}...`);
return allPositions;
}
-
-export const positionsOwnedRoute: FastifyPluginAsync = async (fastify) => {
- // Remove wallet address example population code
-
- fastify.get<{
- Querystring: RaydiumClmmGetPositionsOwnedRequestType;
- Reply: GetPositionsOwnedResponseType;
- }>(
- '/positions-owned',
- {
- schema: {
- description: "Retrieve all positions owned by a user's wallet across all Raydium CLMM pools",
- tags: ['/connector/raydium'],
- querystring: RaydiumClmmGetPositionsOwnedRequest,
- response: {
- 200: GetPositionsOwnedResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress } = request.query;
- return await getPositionsOwned(fastify, network, walletAddress);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e; // Re-throw HttpErrors with original message
- }
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default positionsOwnedRoute;
diff --git a/src/connectors/raydium/clmm-routes/quotePosition.ts b/src/connectors/raydium/clmm-routes/quotePosition.ts
index 32268df249..90dab1dba1 100644
--- a/src/connectors/raydium/clmm-routes/quotePosition.ts
+++ b/src/connectors/raydium/clmm-routes/quotePosition.ts
@@ -1,16 +1,12 @@
import { TickUtils, PoolUtils } from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import BN from 'bn.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import { QuotePositionResponseType, QuotePositionResponse } from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { QuotePositionResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumClmmQuotePositionRequest } from '../schemas';
export async function quotePosition(
network: string,
@@ -44,12 +40,12 @@ export async function quotePosition(
const rpcData = await raydium.getClmmPoolfromRPC(poolAddressToUse);
poolInfo.price = rpcData.currentPrice;
- const { tick: lowerTick, price: tickLowerPrice } = TickUtils.getPriceAndTick({
+ const { tick: lowerTick } = TickUtils.getPriceAndTick({
poolInfo,
price: new Decimal(lowerPrice),
baseIn: true,
});
- const { tick: upperTick, price: tickUpperPrice } = TickUtils.getPriceAndTick({
+ const { tick: upperTick } = TickUtils.getPriceAndTick({
poolInfo,
price: new Decimal(upperPrice),
baseIn: true,
@@ -157,53 +153,3 @@ export async function quotePosition(
throw error;
}
}
-
-export const quotePositionRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: Static;
- Reply: QuotePositionResponseType;
- }>(
- '/quote-position',
- {
- schema: {
- description: 'Quote amounts for a new Raydium CLMM position',
- tags: ['/connector/raydium'],
- querystring: RaydiumClmmQuotePositionRequest,
- response: {
- 200: QuotePositionResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network = 'mainnet-beta',
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- } = request.query;
-
- return await quotePosition(
- network,
- lowerPrice,
- upperPrice,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- undefined, // baseToken not needed anymore
- undefined, // quoteToken not needed anymore
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw httpErrors.internalServerError('Failed to quote position');
- }
- },
- );
-};
-
-export default quotePositionRoute;
diff --git a/src/connectors/raydium/clmm-routes/quoteSwap.ts b/src/connectors/raydium/clmm-routes/quoteSwap.ts
index a41c2d0b72..c4390defbf 100644
--- a/src/connectors/raydium/clmm-routes/quoteSwap.ts
+++ b/src/connectors/raydium/clmm-routes/quoteSwap.ts
@@ -6,22 +6,14 @@ import {
} from '@raydium-io/raydium-sdk-v2';
import { PublicKey } from '@solana/web3.js';
import { Decimal } from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
-import { estimateGasSolana } from '../../../chains/solana/routes/estimate-gas';
import { Solana } from '../../../chains/solana/solana';
-import {
- QuoteSwapResponseType,
- QuoteSwapResponse,
- QuoteSwapRequestType,
- QuoteSwapRequest,
-} from '../../../schemas/clmm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/clmm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { sanitizeErrorMessage } from '../../../services/sanitize';
import { Raydium } from '../raydium';
import { RaydiumConfig } from '../raydium.config';
-import { RaydiumClmmQuoteSwapRequest } from '../schemas';
export async function getSwapQuote(
network: string,
@@ -252,103 +244,6 @@ async function formatSwapQuote(
}
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Raydium CLMM',
- tags: ['/connector/raydium'],
- querystring: RaydiumClmmQuoteSwapRequest,
- response: { 200: QuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, poolAddress, slippagePct } =
- request.query as typeof RaydiumClmmQuoteSwapRequest._type;
- const networkToUse = network;
-
- // Validate essential parameters
- if (!baseToken || !quoteToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, quoteToken, amount, and side are required');
- }
-
- const solana = await Solana.getInstance(networkToUse);
-
- let poolAddressToUse = poolAddress;
-
- // If poolAddress is not provided, look it up by token pair
- if (!poolAddressToUse) {
- // Resolve token symbols to get proper symbols for pool lookup
- const baseTokenInfo = await solana.getToken(baseToken);
- const quoteTokenInfo = await solana.getToken(quoteToken);
-
- if (!baseTokenInfo || !quoteTokenInfo) {
- throw httpErrors.badRequest(
- sanitizeErrorMessage('Token not found: {}', !baseTokenInfo ? baseToken : quoteToken),
- );
- }
-
- // Use PoolService to find pool by token pair
- const { PoolService } = await import('../../../services/pool-service');
- const poolService = PoolService.getInstance();
-
- const pool = await poolService.getPool(
- 'raydium',
- networkToUse,
- 'clmm',
- baseTokenInfo.symbol,
- quoteTokenInfo.symbol,
- );
-
- if (!pool) {
- throw httpErrors.notFound(
- `No CLMM pool found for ${baseTokenInfo.symbol}-${quoteTokenInfo.symbol} on Raydium`,
- );
- }
-
- poolAddressToUse = pool.address;
- }
-
- const result = await formatSwapQuote(
- networkToUse,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- poolAddressToUse,
- slippagePct,
- );
-
- let gasEstimation = null;
- try {
- gasEstimation = await estimateGasSolana(networkToUse);
- } catch (error) {
- logger.warn(`Failed to estimate gas for swap quote: ${error.message}`);
- }
-
- return {
- poolAddress: poolAddressToUse,
- ...result,
- };
- } catch (e) {
- logger.error(e);
- // Preserve the original error if it's a FastifyError
- if (e.statusCode) {
- throw e;
- }
- throw httpErrors.internalServerError('Failed to get swap quote');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Resolves the counter ("quote") token for a Raydium CLMM pool given the base token. The
* standardized swap wrappers take poolAddress + baseToken and derive the other side from the pool
diff --git a/src/connectors/raydium/clmm-routes/removeLiquidity.ts b/src/connectors/raydium/clmm-routes/removeLiquidity.ts
index 668b1c09ba..f3bed047a1 100644
--- a/src/connectors/raydium/clmm-routes/removeLiquidity.ts
+++ b/src/connectors/raydium/clmm-routes/removeLiquidity.ts
@@ -1,20 +1,13 @@
import { TxVersion } from '@raydium-io/raydium-sdk-v2';
-import { Static } from '@sinclair/typebox';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import Decimal from 'decimal.js';
-import { FastifyPluginAsync } from 'fastify';
import { Solana } from '../../../chains/solana/solana';
-import {
- RemoveLiquidityResponse,
- RemoveLiquidityRequestType,
- RemoveLiquidityResponseType,
-} from '../../../schemas/clmm-schema';
-import { httpErrors } from '../../../services/error-handler';
+import { accountLifecycleSol, liquidityWithoutRent } from '../../../chains/solana/solana.utils';
+import { RemoveLiquidityResponseType } from '../../../schemas/clmm-schema';
import { logger } from '../../../services/logger';
import { Raydium } from '../raydium';
-import { RaydiumClmmRemoveLiquidityRequest } from '../schemas';
export async function removeLiquidity(
network: string,
@@ -76,10 +69,9 @@ export async function removeLiquidity(
// Sign + send via the wallet-type-aware chokepoint (handles local/hardware and
// simulates internally).
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Retrying re-fetch; throws the shared landed-but-failed error if the transaction
+ // landed with an error, so txData existing below really means "confirmed".
+ const txData = await solana.getConfirmedTransactionData(signature);
const confirmed = txData !== null;
// Return with status
@@ -93,11 +85,23 @@ export async function removeLiquidity(
tokenBInfo?.address || poolInfo.mintB.address,
]);
- const baseTokenBalanceChange = balanceChanges[0];
- const quoteTokenBalanceChange = balanceChanges[1];
+ // A 100% removal closes the position and its NFT account in the same transaction, so
+ // their rent comes back inside the native side of this change. It is not liquidity.
+ // A partial removal closes nothing and this is a no-op.
+ const { closed } = accountLifecycleSol(txData);
+ const baseTokenBalanceChange = liquidityWithoutRent(
+ balanceChanges[0],
+ new PublicKey(tokenAInfo?.address || poolInfo.mintA.address),
+ closed,
+ );
+ const quoteTokenBalanceChange = liquidityWithoutRent(
+ balanceChanges[1],
+ new PublicKey(tokenBInfo?.address || poolInfo.mintB.address),
+ closed,
+ );
logger.info(
- `Liquidity removed from position ${positionAddress}: ${Math.abs(baseTokenBalanceChange).toFixed(4)} ${poolInfo.mintA.symbol}, ${Math.abs(quoteTokenBalanceChange).toFixed(4)} ${poolInfo.mintB.symbol}`,
+ `Liquidity removed from position ${positionAddress}: ${baseTokenBalanceChange.toFixed(4)} ${poolInfo.mintA.symbol}, ${quoteTokenBalanceChange.toFixed(4)} ${poolInfo.mintB.symbol}`,
);
const totalFee = txData.meta.fee;
@@ -105,9 +109,13 @@ export async function removeLiquidity(
signature,
status: 1, // CONFIRMED
data: {
+ // The pool this position belongs to, already loaded here. The unified route is
+ // position-addressed and never receives it, so this is the only place it can
+ // come from without a second lookup.
+ poolAddress: positionInfo.poolId.toBase58(),
fee: totalFee / 1e9,
- baseTokenAmountRemoved: Math.abs(baseTokenBalanceChange),
- quoteTokenAmountRemoved: Math.abs(quoteTokenBalanceChange),
+ baseTokenAmountRemoved: baseTokenBalanceChange,
+ quoteTokenAmountRemoved: quoteTokenBalanceChange,
},
};
} else {
@@ -118,35 +126,3 @@ export async function removeLiquidity(
};
}
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: Static;
- Reply: RemoveLiquidityResponseType;
- }>(
- '/remove-liquidity',
- {
- schema: {
- description: 'Remove liquidity from Raydium CLMM position',
- tags: ['/connector/raydium'],
- body: RaydiumClmmRemoveLiquidityRequest,
- response: {
- 200: RemoveLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, walletAddress, positionAddress, percentageToRemove } = request.body;
-
- return await removeLiquidity(network, walletAddress, positionAddress, percentageToRemove, false);
- } catch (e) {
- logger.error(e);
- if (e.statusCode) throw e;
- throw fastify.httpErrors.internalServerError('Internal server error');
- }
- },
- );
-};
-
-export default removeLiquidityRoute;
diff --git a/src/connectors/raydium/raydium.routes.ts b/src/connectors/raydium/raydium.routes.ts
deleted file mode 100644
index 9c6521d9e3..0000000000
--- a/src/connectors/raydium/raydium.routes.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { raydiumAmmRoutes } from './amm-routes';
-import { raydiumClmmRoutes } from './clmm-routes';
-
-// CLMM routes including swap endpoints
-const raydiumClmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/raydium'];
- }
- });
-
- await instance.register(raydiumClmmRoutes);
- });
-};
-
-// AMM routes including swap endpoints
-const raydiumAmmRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/raydium'];
- }
- });
-
- await instance.register(raydiumAmmRoutes);
- });
-};
-
-// Main export that combines all routes
-export const raydiumRoutes = {
- clmm: raydiumClmmRoutesWrapper,
- amm: raydiumAmmRoutesWrapper,
-};
diff --git a/src/connectors/raydium/raydium.ts b/src/connectors/raydium/raydium.ts
index cbf5d2ac44..dcae4caff3 100644
--- a/src/connectors/raydium/raydium.ts
+++ b/src/connectors/raydium/raydium.ts
@@ -220,7 +220,7 @@ export class Raydium {
}
const poolIdString = position.poolId.toBase58();
- const [poolInfo, poolKeys] = await this.getClmmPoolfromAPI(poolIdString);
+ const [poolInfo] = await this.getClmmPoolfromAPI(poolIdString);
const epochInfo = await this.solana.connection.getEpochInfo();
@@ -323,7 +323,12 @@ export class Raydium {
address: poolAddress,
baseTokenAddress: rawPool[poolAddress].baseMint.toString(),
quoteTokenAddress: rawPool[poolAddress].quoteMint.toString(),
- feePct: Number(rawPool[poolAddress].tradeFeeNumerator) / Number(rawPool[poolAddress].tradeFeeDenominator),
+ // feePct is a PERCENT on every other surface (getClmmPoolInfo above, Meteora,
+ // Orca), so the numerator/denominator ratio — a fraction — is scaled to match.
+ // Unscaled this reported 0.0025 for a pool charging 0.25%, and consumers render
+ // the field literally.
+ feePct:
+ (Number(rawPool[poolAddress].tradeFeeNumerator) / Number(rawPool[poolAddress].tradeFeeDenominator)) * 100,
price: Number(rawPool[poolAddress].poolPrice),
baseTokenAmount: Number(rawPool[poolAddress].mintAAmount) / 10 ** Number(rawPool[poolAddress].baseDecimal),
quoteTokenAmount: Number(rawPool[poolAddress].mintBAmount) / 10 ** Number(rawPool[poolAddress].quoteDecimal),
@@ -337,7 +342,9 @@ export class Raydium {
address: poolAddress,
baseTokenAddress: rawPool[poolAddress].mintA.toString(),
quoteTokenAddress: rawPool[poolAddress].mintB.toString(),
- feePct: Number(rawPool[poolAddress].configInfo?.tradeFeeRate || 0),
+ // CPMM's tradeFeeRate is in millionths (2500 = 0.25%); /10000 yields the percent,
+ // the same conversion getClmmPoolInfo applies to the CLMM config's rate.
+ feePct: Number(rawPool[poolAddress].configInfo?.tradeFeeRate || 0) / 10000,
price: Number(rawPool[poolAddress].poolPrice),
baseTokenAmount: Number(rawPool[poolAddress].baseReserve) / 10 ** Number(rawPool[poolAddress].mintDecimalA),
quoteTokenAmount: Number(rawPool[poolAddress].quoteReserve) / 10 ** Number(rawPool[poolAddress].mintDecimalB),
diff --git a/src/connectors/raydium/schemas.ts b/src/connectors/raydium/schemas.ts
deleted file mode 100644
index 60745782b2..0000000000
--- a/src/connectors/raydium/schemas.ts
+++ /dev/null
@@ -1,689 +0,0 @@
-import { Type, Static } from '@sinclair/typebox';
-
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { RaydiumConfig } from './raydium.config';
-
-// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
-
-// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.01;
-const BASE_TOKEN_AMOUNT = 0.01;
-const QUOTE_TOKEN_AMOUNT = 2;
-const LOWER_PRICE_BOUND = 100;
-const UPPER_PRICE_BOUND = 300;
-const AMM_POOL_ADDRESS_EXAMPLE = '58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2';
-const CLMM_POOL_ADDRESS_EXAMPLE = '3ucNos4NbumPLZNWztqGHNFFgkHeRMBQAVemeeomsUxv';
-
-// ========================================
-// AMM Request Schemas
-// ========================================
-
-export const RaydiumAmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium AMM pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
-});
-
-export const RaydiumAmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium AMM pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
-});
-
-export const RaydiumAmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'AMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair (optional - required if poolAddress not provided)',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-// Export the type for ExecuteSwapRequest
-export type RaydiumClmmExecuteSwapRequestType = Static;
-
-export const RaydiumAmmExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'AMM pool address (optional - can be looked up from baseToken and quoteToken)',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumAmmQuoteLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium AMM pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumAmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium AMM pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumAmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium AMM pool address',
- examples: [AMM_POOL_ADDRESS_EXAMPLE],
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- examples: [100],
- }),
-});
-
-export const RaydiumAmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create and seed the pool',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to seed the pool with',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description:
- 'Amount of quote token to seed with. If provided, the base:quote ratio sets the initial price. ' +
- 'If omitted (and no initialPrice), the current market price is fetched from the swap router.',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. Overrides quoteTokenAmount. ' +
- 'If both are omitted, the pool is seeded at the current market price so it is not immediately arbitraged.',
- }),
- ),
- feeConfigIndex: Type.Optional(
- Type.Integer({
- description:
- 'Index into the CPMM fee-config list returned by the Raydium API (getCpmmConfigs). ' +
- 'Default 0 selects the first/lowest fee tier.',
- default: 0,
- minimum: 0,
- }),
- ),
- openTime: Type.Optional(
- Type.Integer({
- description: 'Unix timestamp (seconds) when trading opens. Default 0 opens the pool immediately on confirmation.',
- default: 0,
- minimum: 0,
- }),
- ),
-});
-
-// ========================================
-// CLMM Request Schemas
-// ========================================
-
-export const RaydiumClmmGetPoolInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.String({
- description: 'Raydium CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- binCount: Type.Optional(
- Type.Integer({
- description:
- 'If > 0, include a `bins` array (per-tickSpacing token amounts around the current tick), ' +
- 'mirroring Meteora pool-info.bins[]. Default 0 — pool-info skips the extra tick-array fetch.',
- default: 0,
- minimum: 0,
- maximum: 401,
- }),
- ),
-});
-export type RaydiumClmmGetPoolInfoRequestType = Static;
-
-export const RaydiumClmmGetPositionInfoRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
-});
-
-export const RaydiumClmmQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'CLMM pool address (optional - can be looked up from tokens)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Token to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'The other token in the pair',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumClmmExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- examples: [solanaChainConfig.defaultWallet],
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- poolAddress: Type.Optional(
- Type.String({
- description: 'CLMM pool address (optional)',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.Optional(
- Type.String({
- description: 'Quote token symbol or address',
- examples: [QUOTE_TOKEN],
- }),
- ),
- amount: Type.Number({
- description: 'Amount to swap',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description: 'Trade direction',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- examples: ['SELL'],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-// ========================================
-// CLMM Liquidity Request Schemas
-// ========================================
-
-export const RaydiumClmmOpenPositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Raydium CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumClmmCreatePoolRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will create and initialize the pool',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- baseToken: Type.String({
- description: 'Base token symbol or address (becomes the pool base)',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'Quote token symbol or address (becomes the pool quote)',
- examples: [QUOTE_TOKEN],
- }),
- initialPrice: Type.Optional(
- Type.Number({
- description:
- 'Initial price as quote per base. If omitted, the current market price is fetched from the ' +
- 'unified swap router so the pool opens on-market. No position is opened; only the pool is created.',
- examples: [QUOTE_TOKEN_AMOUNT / BASE_TOKEN_AMOUNT],
- }),
- ),
- ammConfigIndex: Type.Optional(
- Type.Integer({
- description:
- 'Index into the CLMM amm-config list returned by the Raydium API (getClmmConfigs). ' +
- 'Each config carries a fee tier and tickSpacing. Default 0 selects the first/lowest tier.',
- default: 0,
- minimum: 0,
- }),
- ),
-});
-
-export const RaydiumClmmAddLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address',
- examples: [''],
- }),
- baseTokenAmount: Type.Number({
- description: 'Amount of base token to add',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- quoteTokenAmount: Type.Number({
- description: 'Amount of quote token to add',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
-
-export const RaydiumClmmRemoveLiquidityRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address to remove liquidity from',
- examples: ['DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263'],
- }),
- percentageToRemove: Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Percentage of liquidity to remove',
- examples: [100],
- }),
-});
-
-export const RaydiumClmmClosePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- positionAddress: Type.String({
- description: 'Position NFT address to close',
- examples: ['DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263'],
- }),
-});
-
-export const RaydiumClmmGetPositionsOwnedRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- walletAddress: Type.String({
- description: 'Solana wallet address to check for positions',
- examples: [solanaChainConfig.defaultWallet],
- }),
-});
-
-export type RaydiumClmmGetPositionsOwnedRequestType = Static;
-
-export const RaydiumClmmQuotePositionRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...RaydiumConfig.networks],
- }),
- ),
- lowerPrice: Type.Number({
- description: 'Lower price bound for the position',
- examples: [LOWER_PRICE_BOUND],
- }),
- upperPrice: Type.Number({
- description: 'Upper price bound for the position',
- examples: [UPPER_PRICE_BOUND],
- }),
- poolAddress: Type.String({
- description: 'Raydium CLMM pool address',
- examples: [CLMM_POOL_ADDRESS_EXAMPLE],
- }),
- baseTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of base token to deposit',
- examples: [BASE_TOKEN_AMOUNT],
- }),
- ),
- quoteTokenAmount: Type.Optional(
- Type.Number({
- description: 'Amount of quote token to deposit',
- examples: [QUOTE_TOKEN_AMOUNT],
- }),
- ),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: RaydiumConfig.config.slippagePct,
- examples: [RaydiumConfig.config.slippagePct],
- }),
- ),
-});
diff --git a/src/connectors/router-utils.ts b/src/connectors/router-utils.ts
index 63b6f15ad1..08828ed18d 100644
--- a/src/connectors/router-utils.ts
+++ b/src/connectors/router-utils.ts
@@ -50,6 +50,58 @@ export interface ApproximateBuyResult {
forwardQuote: ExactInQuote;
}
+/**
+ * A router's price impact as the percentage the schema documents.
+ *
+ * `QuoteSwapResponse.priceImpactPct` promises "Estimated price impact percentage
+ * (0-100)". Jupiter's field of the same name is a decimal *fraction* — 0.0126 means
+ * 1.26% — and it was passed through unconverted, so the number was 100x low against its
+ * own documentation, in the direction that makes a bad trade look harmless. A guard of
+ * the form `if (priceImpactPct > 5) reject` could never fire.
+ *
+ * Measured on SOL-USDC: a 20,000 SOL sell reported 0.001260 against a 0.134% impact
+ * computed from the quoted prices — agreement to within the fee once the trade is large
+ * enough for impact to dominate.
+ *
+ * Applies to the routers that serve Jupiter's quote schema: jupiter itself and dflow,
+ * whose quote response is that schema field for field. It does NOT apply to a router's
+ * native payload passed back for execution — that has to stay in the router's own units.
+ */
+export function priceImpactPercentFromFraction(fraction: string | number | undefined | null): number {
+ const parsed = parseFloat(String(fraction ?? ''));
+ // A router that omits the field reports 0, which is what the call sites' `|| '0'` did
+ // before this existed. It is indistinguishable from a measured zero — the field cannot
+ // express "not computed" — which is the half of this defect the schema still owes.
+ return Number.isFinite(parsed) ? parsed * 100 : 0;
+}
+
+/**
+ * The route a quote actually attempted, for an error message a caller can act on.
+ *
+ * A SELL is ExactIn base -> quote; a BUY is ExactOut quote -> base. Every router here
+ * built its no-route message from the SELL shape and reused it for both, so a BUY that
+ * failed was reported as a failed ExactIn in the opposite direction — naming a route
+ * nobody tried. That matters because the message is a NO_ROUTE_FOUND, which reads as
+ * "this token is untradable": the same file already carries a fix for mislabelling a
+ * failure that way, after callers blacklisted good pools over it. A BUY declining
+ * approximation is precisely the case where ExactIn *does* route, since ExactIn is what
+ * the approximation would have used.
+ *
+ * `mode` overrides the side's default for a router whose executable mode differs from the
+ * one implied by the side, or to describe a compound attempt.
+ */
+export function attemptedRoute(
+ side: 'BUY' | 'SELL',
+ baseTokenName: string,
+ quoteTokenName: string,
+ mode?: string,
+): string {
+ const buying = side === 'BUY';
+ const from = buying ? quoteTokenName : baseTokenName;
+ const to = buying ? baseTokenName : quoteTokenName;
+ return `${from} -> ${to} (${mode ?? (buying ? 'ExactOut' : 'ExactIn')})`;
+}
+
/**
* Approximates a BUY (ExactOut) on a router that only supports ExactIn quotes.
*
diff --git a/src/connectors/titan/router-routes/executeQuote.ts b/src/connectors/titan/router-routes/executeQuote.ts
index 26407e0eb2..79cfc4ceee 100644
--- a/src/connectors/titan/router-routes/executeQuote.ts
+++ b/src/connectors/titan/router-routes/executeQuote.ts
@@ -1,11 +1,8 @@
-import { FastifyPluginAsync } from 'fastify';
-
import { Solana } from '../../../chains/solana/solana';
-import { ExecuteQuoteRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
-import { TitanExecuteQuoteRequest } from '../schemas';
import { buildVersionedTransactionFromInstructions } from '../titan.utils';
export async function executeQuote(
@@ -19,7 +16,7 @@ export async function executeQuote(
throw httpErrors.badRequest('Quote not found or expired');
}
- const { wallet, inputToken, outputToken, swapRoute } = cached;
+ const { wallet, inputToken, outputToken, swapRoute, slippagePct } = cached;
// Titan instructions are built for a specific wallet; executing them from another wallet
// would fail on-chain or move the wrong accounts — require a re-quote instead
@@ -43,18 +40,18 @@ export async function executeQuote(
);
const { signature } = await solana.sendAndConfirmTransactionForWallet(transaction, walletAddress);
- const txData = await solana.connection.getTransaction(signature, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0,
- });
+ // Re-fetch with retry; a landed-but-failed transaction throws instead of being
+ // misreported as confirmed or pending.
+ const txData = await solana.getConfirmedTransactionData(signature);
const result = await solana.handleConfirmation(
signature,
- txData !== null,
txData,
inputToken.address,
outputToken.address,
walletAddress,
+ undefined,
+ slippagePct,
);
// Remove quote from cache only after successful execution (confirmed)
@@ -67,33 +64,3 @@ export async function executeQuote(
return result as SwapExecuteResponseType;
}
-
-export const executeQuoteRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteQuoteRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-quote',
- {
- schema: {
- description: 'Execute a previously fetched quote from Titan (DART)',
- tags: ['/connector/titan'],
- body: TitanExecuteQuoteRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, quoteId } = request.body as typeof TitanExecuteQuoteRequest._type;
-
- return await executeQuote(walletAddress, network, quoteId);
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing Titan quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeQuoteRoute;
diff --git a/src/connectors/titan/router-routes/executeSwap.ts b/src/connectors/titan/router-routes/executeSwap.ts
index f3573592f6..95c4cbec7f 100644
--- a/src/connectors/titan/router-routes/executeSwap.ts
+++ b/src/connectors/titan/router-routes/executeSwap.ts
@@ -1,9 +1,4 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
-import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
-import { TitanExecuteSwapRequest } from '../schemas';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { TitanConfig } from '../titan.config';
import { executeQuote } from './executeQuote';
@@ -36,43 +31,3 @@ async function executeSwap(
}
export { executeSwap };
-
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Quote and execute a token swap on Titan (DART) in one step',
- tags: ['/connector/titan'],
- body: TitanExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const { walletAddress, network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut } =
- request.body as typeof TitanExecuteSwapRequest._type;
-
- return await executeSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing Titan swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default executeSwapRoute;
diff --git a/src/connectors/titan/router-routes/index.ts b/src/connectors/titan/router-routes/index.ts
deleted file mode 100644
index d612bb08d8..0000000000
--- a/src/connectors/titan/router-routes/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import executeQuoteRoute from './executeQuote';
-import executeSwapRoute from './executeSwap';
-import quoteSwapRoute from './quoteSwap';
-
-export const titanRouterRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(quoteSwapRoute);
- await fastify.register(executeQuoteRoute);
- await fastify.register(executeSwapRoute);
-};
-
-export default titanRouterRoutes;
diff --git a/src/connectors/titan/router-routes/quoteSwap.ts b/src/connectors/titan/router-routes/quoteSwap.ts
index 20a8bdf3e0..974d6f91d6 100644
--- a/src/connectors/titan/router-routes/quoteSwap.ts
+++ b/src/connectors/titan/router-routes/quoteSwap.ts
@@ -1,16 +1,14 @@
import { Static } from '@sinclair/typebox';
-import { FastifyPluginAsync } from 'fastify';
import { v4 as uuidv4 } from 'uuid';
import { Solana } from '../../../chains/solana/solana';
import { getSolanaChainConfig } from '../../../chains/solana/solana.config';
-import { QuoteSwapRequestType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { quoteCache } from '../../../services/quote-cache';
import { sanitizeErrorMessage } from '../../../services/sanitize';
-import { approximateBuyViaSellLeg } from '../../router-utils';
-import { TitanQuoteSwapRequest, TitanQuoteSwapResponse } from '../schemas';
+import { approximateBuyViaSellLeg, attemptedRoute } from '../../router-utils';
+import { TitanQuoteSwapResponse } from '../schemas';
import { Titan, TitanSwapResponse } from '../titan';
import { TitanConfig } from '../titan.config';
@@ -28,7 +26,7 @@ export async function quoteSwap(
const titan = await Titan.getInstance(network);
// Titan DART quotes are wallet-bound; fall back to the configured default wallet when
- // the caller does not specify one (the unified /trading/swap dispatcher omits it)
+ // the caller does not specify one (the unified /trading/router dispatcher omits it)
const wallet = walletAddress || getSolanaChainConfig().defaultWallet;
if (!wallet) {
throw httpErrors.badRequest(
@@ -60,7 +58,7 @@ export async function quoteSwap(
swapRoute = await titan.getSwapRoute(inputToken.address, outputToken.address, amountRaw, wallet, slippageBps);
} catch (error) {
throw httpErrors.noRouteFound(
- `No route found for ${baseTokenInfo.symbol} -> ${quoteTokenInfo.symbol} (ExactIn). ${error?.message || error}`,
+ `No route found for ${attemptedRoute(side, baseTokenInfo.symbol, quoteTokenInfo.symbol)}. ${error?.message || error}`,
);
}
} else {
@@ -128,43 +126,3 @@ export async function quoteSwap(
wallet,
};
}
-
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: Static;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get an executable swap quote from Titan (DART)',
- tags: ['/connector/titan'],
- querystring: TitanQuoteSwapRequest,
- response: { 200: TitanQuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, baseToken, quoteToken, amount, side, slippagePct, approximateIfNoExactOut, walletAddress } =
- request.query as typeof TitanQuoteSwapRequest._type;
-
- return await quoteSwap(
- network,
- baseToken,
- quoteToken,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- approximateIfNoExactOut,
- walletAddress,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error getting Titan quote:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
diff --git a/src/connectors/titan/schemas.ts b/src/connectors/titan/schemas.ts
index abbf8a2a19..41cecf2aa5 100644
--- a/src/connectors/titan/schemas.ts
+++ b/src/connectors/titan/schemas.ts
@@ -1,68 +1,8 @@
import { Type } from '@sinclair/typebox';
-import { getSolanaChainConfig } from '../../chains/solana/solana.config';
-
-import { TitanConfig } from './titan.config';
-
// Get chain config for defaults
-const solanaChainConfig = getSolanaChainConfig();
// Constants for examples
-const BASE_TOKEN = 'SOL';
-const QUOTE_TOKEN = 'USDC';
-const SWAP_AMOUNT = 0.1;
-
-// Titan-specific quote-swap request (superset of base QuoteSwapRequest).
-// Titan DART quotes are wallet-bound (the API builds instructions for a wallet even when
-// only quoting), so walletAddress is accepted here and defaults to the Solana default wallet.
-export const TitanQuoteSwapRequest = Type.Object({
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...TitanConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: TitanConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders: Titan DART is ExactIn-only, so BUYs are approximated via a sell-leg ExactIn quote. If false, BUY requests fail with a clear error.',
- default: true,
- }),
- ),
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet the quote instructions are built for (Titan quotes are wallet-bound)',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
-});
// Titan-specific quote-swap response (superset of base QuoteSwapResponse)
export const TitanQuoteSwapResponse = Type.Object({
@@ -104,74 +44,3 @@ export const TitanQuoteSwapResponse = Type.Object({
'Wallet address this quote is bound to; execute-quote must be called with the same wallet or it will fail',
}),
});
-
-// Titan-specific execute-quote request (superset of base ExecuteQuoteRequest)
-export const TitanExecuteQuoteRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap (must match the wallet the quote was created for)',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...TitanConfig.networks],
- }),
- ),
- quoteId: Type.String({
- description: 'ID of the Titan quote to execute',
- examples: ['123e4567-e89b-12d3-a456-426614174000'],
- }),
-});
-
-// Titan-specific execute-swap request (superset of base ExecuteSwapRequest)
-export const TitanExecuteSwapRequest = Type.Object({
- walletAddress: Type.Optional(
- Type.String({
- description: 'Solana wallet address that will execute the swap',
- default: solanaChainConfig.defaultWallet,
- }),
- ),
- network: Type.Optional(
- Type.String({
- description: 'Solana network to use',
- default: solanaChainConfig.defaultNetwork,
- enum: [...TitanConfig.networks],
- }),
- ),
- baseToken: Type.String({
- description: 'Solana token symbol or address to determine swap direction',
- examples: [BASE_TOKEN],
- }),
- quoteToken: Type.String({
- description: 'The other Solana token symbol or address in the pair',
- examples: [QUOTE_TOKEN],
- }),
- amount: Type.Number({
- description: 'Amount of base token to trade',
- examples: [SWAP_AMOUNT],
- }),
- side: Type.String({
- description:
- 'Trade direction - BUY means buying base token with quote token, SELL means selling base token for quote token',
- enum: ['BUY', 'SELL'],
- default: 'SELL',
- }),
- slippagePct: Type.Optional(
- Type.Number({
- minimum: 0,
- maximum: 100,
- description: 'Maximum acceptable slippage percentage',
- default: TitanConfig.config.slippagePct,
- }),
- ),
- approximateIfNoExactOut: Type.Optional(
- Type.Boolean({
- description:
- 'For BUY orders: Titan DART is ExactIn-only, so BUYs are approximated via a sell-leg ExactIn quote. If false, BUY requests fail with a clear error.',
- default: true,
- }),
- ),
-});
diff --git a/src/connectors/titan/titan.routes.ts b/src/connectors/titan/titan.routes.ts
deleted file mode 100644
index 818181dcdc..0000000000
--- a/src/connectors/titan/titan.routes.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import sensible from '@fastify/sensible';
-import type { FastifyPluginAsync } from 'fastify';
-
-// Import routes
-import { titanRouterRoutes } from './router-routes';
-
-// Titan routes with 3 endpoints
-const titanRouterRoutesWrapper: FastifyPluginAsync = async (fastify) => {
- await fastify.register(sensible);
-
- await fastify.register(async (instance) => {
- // Decorate the instance with a hook to modify route options
- instance.addHook('onRoute', (routeOptions) => {
- if (routeOptions.schema && routeOptions.schema.tags) {
- routeOptions.schema.tags = ['/connector/titan'];
- }
- });
-
- await instance.register(titanRouterRoutes);
- });
-};
-
-// Export routes in the same pattern as Jupiter
-export const titanRoutes = {
- router: titanRouterRoutesWrapper,
-};
diff --git a/src/connectors/uniswap/amm-routes/addLiquidity.ts b/src/connectors/uniswap/amm-routes/addLiquidity.ts
index 62b46cdfa8..5944c02a01 100644
--- a/src/connectors/uniswap/amm-routes/addLiquidity.ts
+++ b/src/connectors/uniswap/amm-routes/addLiquidity.ts
@@ -1,16 +1,13 @@
import { Contract } from '@ethersproject/contracts';
-import { Static } from '@sinclair/typebox';
import { Percent } from '@uniswap/sdk-core';
-import { BigNumber, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
-import { re } from 'mathjs';
+import { BigNumber } from 'ethers';
import { Ethereum } from '../../../chains/ethereum/ethereum';
import { wrapEthereum } from '../../../chains/ethereum/routes/wrap';
-import { AddLiquidityResponseType, AddLiquidityResponse } from '../../../schemas/amm-schema';
+import { AddLiquidityResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
-import { UniswapAmmAddLiquidityRequest } from '../schemas';
import { Uniswap } from '../uniswap';
import { UniswapConfig } from '../uniswap.config';
import { IUniswapV2Router02ABI } from '../uniswap.contracts';
@@ -31,8 +28,6 @@ async function addLiquidityInternal(
baseTokenAmount: number,
quoteTokenAmount: number,
slippagePct: number = UniswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
const networkToUse = network;
@@ -40,6 +35,11 @@ async function addLiquidityInternal(
let actualBaseToken = baseToken;
let baseWrapTxHash = null;
if (baseToken === 'ETH') {
+ // Declared here, as the quote-token branch below does. It used to resolve to a
+ // function-scope binding declared further down, which made this branch a
+ // guaranteed ReferenceError: adding liquidity with ETH as the base token could
+ // never have worked. The dead-code sweep that removed the unused later binding is
+ // what surfaced it.
const uniswap = await Uniswap.getInstance(networkToUse);
const wethToken = await uniswap.getToken('WETH');
if (!wethToken) {
@@ -87,7 +87,6 @@ async function addLiquidityInternal(
// Get Ethereum instance
const ethereum = await Ethereum.getInstance(networkToUse);
- const uniswap = await Uniswap.getInstance(networkToUse);
// Get wallet
const wallet = await ethereum.getWallet(walletAddress);
@@ -182,8 +181,7 @@ async function addLiquidityInternal(
// Add liquidity Token + ETH
// Convert gasPrice from wei to gwei if provided
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_ADD_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_ADD_LIQUIDITY_GAS_LIMIT);
gasOptions.value = quote.rawQuoteTokenAmount;
tx = await router.addLiquidityETH(
@@ -244,8 +242,7 @@ async function addLiquidityInternal(
// Add liquidity Token + Token
// Convert gasPrice from wei to gwei if provided
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_ADD_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_ADD_LIQUIDITY_GAS_LIMIT);
tx = await router.addLiquidity(
quote.baseTokenObj.address,
@@ -261,19 +258,17 @@ async function addLiquidityInternal(
}
// Wait for transaction confirmation
- const receipt = await ethereum.handleTransactionExecution(tx);
-
- // Calculate gas fee
- const gasFee = formatTokenAmount(
- receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(),
- 18, // ETH has 18 decimals
- );
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the quoted amounts were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ fee: outcome.fee,
baseTokenAmountAdded: quote.baseTokenAmount,
quoteTokenAmountAdded: quote.quoteTokenAmount,
...(baseWrapTxHash && { baseWrapTxHash }),
@@ -293,8 +288,6 @@ export async function addLiquidity(
baseTokenAmount: number,
quoteTokenAmount: number,
slippagePct: number = UniswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
const poolInfo = await getUniswapPoolInfo(poolAddress, network, 'amm');
if (!poolInfo) throw httpErrors.notFound(`Pool not found: ${poolAddress}`);
@@ -308,93 +301,5 @@ export async function addLiquidity(
baseTokenAmount,
quoteTokenAmount,
slippagePct,
- gasPrice,
- maxGas,
);
}
-
-export const addLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.post<{
- Body: Static;
- Reply: AddLiquidityResponseType;
- }>(
- '/add-liquidity',
- {
- schema: {
- description: 'Add liquidity to a Uniswap V2 pool',
- tags: ['/connector/uniswap'],
- body: UniswapAmmAddLiquidityRequest,
- response: {
- 200: AddLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- walletAddress: requestedWalletAddress,
- gasPrice,
- maxGas,
- } = request.body;
-
- // Validate essential parameters
- if (!poolAddress || !baseTokenAmount || !quoteTokenAmount) {
- throw fastify.httpErrors.badRequest('Missing required parameters');
- }
-
- const networkToUse = network;
-
- // Get wallet address - either from request or first available
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no wallets found.');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- return await addLiquidity(
- networkToUse,
- walletAddress,
- poolAddress,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- gasPrice,
- maxGas,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
-
- // Handle specific user-actionable errors
- if (e.message && e.message.includes('Insufficient allowance')) {
- logger.error('Request error:', e);
- throw fastify.httpErrors.badRequest('Invalid request');
- }
-
- // Handle insufficient funds errors
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient ETH balance to pay for gas fees. Please add more ETH to your wallet.',
- );
- }
-
- throw fastify.httpErrors.internalServerError('Failed to add liquidity');
- }
- },
- );
-};
-
-export default addLiquidityRoute;
diff --git a/src/connectors/uniswap/amm-routes/createPool.ts b/src/connectors/uniswap/amm-routes/createPool.ts
index 945078d9b6..6e7419dcd0 100644
--- a/src/connectors/uniswap/amm-routes/createPool.ts
+++ b/src/connectors/uniswap/amm-routes/createPool.ts
@@ -1,15 +1,13 @@
import { Contract } from '@ethersproject/contracts';
-import { Static } from '@sinclair/typebox';
import { Percent } from '@uniswap/sdk-core';
import { Decimal } from 'decimal.js';
import { BigNumber, constants, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum, TokenInfo } from '../../../chains/ethereum/ethereum';
-import { CreatePoolResponse, CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { CreatePoolResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
-import { UniswapAmmCreatePoolRequest } from '../schemas';
import { UniswapConfig } from '../uniswap.config';
import {
IUniswapV2FactoryABI,
@@ -54,10 +52,10 @@ async function fetchMarketPrice(
quoteToken: string,
amount: number,
): Promise {
- const { getUnifiedQuoteSwap } = await import('../../../trading/swap/quote');
+ const { getSwapQuote } = await import('../../../trading/market-price');
let quote: any;
try {
- quote = await getUnifiedQuoteSwap(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
+ quote = await getSwapQuote(`ethereum-${network}`, baseToken, quoteToken, amount, 'SELL');
} catch (e: any) {
throw httpErrors.badRequest(
`Could not fetch a market price for ${baseToken}/${quoteToken} to seed the pool (${e.message}). ` +
@@ -80,8 +78,6 @@ export async function createPool(
baseTokenAmount: number,
quoteTokenAmount?: number,
initialPrice?: number,
- gasPrice?: number,
- maxGas?: number,
slippagePct: number = UniswapConfig.config.slippagePct,
): Promise {
if (baseTokenAmount <= 0) {
@@ -178,10 +174,6 @@ export async function createPool(
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- // gasPrice arrives already in gwei (the unit prepareGasOptions expects). The connector's Fastify
- // route accepts gasPrice as a wei string (sibling shape) and converts it to gwei before calling.
- const gasPriceGwei = gasPrice;
-
let tx;
if (baseIsEth || quoteIsEth) {
// One side is ETH/WETH → addLiquidityETH. The ERC20 side needs an allowance to the router; the
@@ -204,7 +196,7 @@ export async function createPool(
);
}
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_CREATE_POOL_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_CREATE_POOL_GAS_LIMIT);
gasOptions.value = ethRawAmount;
tx = await router.addLiquidityETH(
@@ -248,7 +240,7 @@ export async function createPool(
);
}
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_CREATE_POOL_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_CREATE_POOL_GAS_LIMIT);
tx = await router.addLiquidity(
baseTokenInfo.address,
@@ -265,118 +257,32 @@ export async function createPool(
logger.info(`Creating Uniswap V2 pool ${baseTokenInfo.symbol}/${quoteTokenInfo.symbol} via tx ${tx.hash}`);
- const receipt = await ethereum.handleTransactionExecution(tx);
+ // A revert throws out of here (400 TRANSACTION_FAILED) — it is never reported as PENDING.
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
// Read the (now-created) pair address from the factory — authoritative source of the pool address.
const pairAddress: string = await factory.getPair(baseTokenInfo.address, quoteTokenInfo.address);
- if (receipt && receipt.status === 1) {
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18); // ETH has 18 decimals
+ if (!outcome.confirmed) {
+ // Timed out but still broadcasting — report PENDING with the tx hash so the caller can
+ // reconcile it. The seed amounts below have not moved, so they are deliberately omitted.
return {
- signature: receipt.transactionHash,
- status: 1, // CONFIRMED
+ signature: outcome.signature,
+ status: TransactionStatus.PENDING,
poolAddress: pairAddress,
price: seedPrice,
- data: {
- fee: gasFee,
- baseTokenAmountAdded: baseTokenAmount,
- quoteTokenAmountAdded: effectiveQuoteAmount,
- },
};
}
- // Timed out (still broadcasting) or reverted — report as pending with the tx hash.
return {
- signature: receipt ? receipt.transactionHash : tx.hash,
- status: 0, // PENDING
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
poolAddress: pairAddress,
price: seedPrice,
+ data: {
+ fee: outcome.fee,
+ baseTokenAmountAdded: baseTokenAmount,
+ quoteTokenAmountAdded: effectiveQuoteAmount,
+ },
};
}
-
-export const createPoolRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
-
- fastify.post<{
- Body: Static;
- Reply: CreatePoolResponseType;
- }>(
- '/create-pool',
- {
- schema: {
- description: 'Create a new Uniswap V2 (AMM) pool and seed it with initial liquidity (fixed 0.30% fee)',
- tags: ['/connector/uniswap'],
- body: UniswapAmmCreatePoolRequest,
- response: {
- 200: CreatePoolResponse,
- },
- },
- },
- async (request) => {
- try {
- const {
- network,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- slippagePct,
- gasPrice,
- maxGas,
- walletAddress: requestedWalletAddress,
- } = request.body;
-
- if (!baseToken || !quoteToken || !baseTokenAmount) {
- throw fastify.httpErrors.badRequest('Missing required parameters');
- }
-
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await Ethereum.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no wallets found.');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- // Route accepts gasPrice as a wei string (matching sibling AMM requests); createPool expects gwei.
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
-
- return await createPool(
- network,
- walletAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- initialPrice,
- gasPriceGwei,
- maxGas,
- slippagePct,
- );
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
-
- if (e.message && e.message.includes('Insufficient allowance')) {
- throw fastify.httpErrors.badRequest(e.message);
- }
- if (e.message && e.message.includes('already exists')) {
- throw fastify.httpErrors.badRequest(e.message);
- }
- if (e.code === 'INSUFFICIENT_FUNDS' || (e.message && e.message.includes('insufficient funds'))) {
- throw fastify.httpErrors.badRequest(
- 'Insufficient ETH balance to pay for gas fees. Please add more ETH to your wallet.',
- );
- }
-
- throw fastify.httpErrors.internalServerError('Failed to create pool');
- }
- },
- );
-};
-
-export default createPoolRoute;
diff --git a/src/connectors/uniswap/amm-routes/executeSwap.ts b/src/connectors/uniswap/amm-routes/executeSwap.ts
index d9830dd32b..c9ebdd13d4 100644
--- a/src/connectors/uniswap/amm-routes/executeSwap.ts
+++ b/src/connectors/uniswap/amm-routes/executeSwap.ts
@@ -1,13 +1,11 @@
import { BigNumber, Contract, utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
-import { Ethereum } from '../../../chains/ethereum/ethereum';
+import { Ethereum, EthereumTransactionOutcome } from '../../../chains/ethereum/ethereum';
import { EthereumLedger } from '../../../chains/ethereum/ethereum-ledger';
-import { getEthereumChainConfig } from '../../../chains/ethereum/ethereum.config';
-import { ExecuteSwapRequestType, SwapExecuteResponseType, SwapExecuteResponse } from '../../../schemas/router-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
+import { SwapExecuteResponseType } from '../../../schemas/router-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
-import { UniswapAmmExecuteSwapRequest } from '../schemas';
import { Uniswap } from '../uniswap';
import { UniswapConfig } from '../uniswap.config';
import { getUniswapV2RouterAddress, IUniswapV2Router02ABI } from '../uniswap.contracts';
@@ -86,7 +84,7 @@ export async function executeAmmSwap(
// Prepare transaction parameters
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- let receipt;
+ let outcome: EthereumTransactionOutcome;
try {
if (isHardwareWallet) {
@@ -151,7 +149,7 @@ export async function executeAmmSwap(
logger.info(`Transaction sent: ${txResponse.hash}`);
// Wait for confirmation with timeout
- receipt = await ethereum.handleTransactionExecution(txResponse);
+ outcome = await ethereum.handleTransactionConfirmation(txResponse);
} else {
// Regular wallet flow
let wallet;
@@ -208,19 +206,18 @@ export async function executeAmmSwap(
logger.info(`Transaction sent: ${tx.hash}`);
// Wait for transaction confirmation
- receipt = await ethereum.handleTransactionExecution(tx);
+ outcome = await ethereum.handleTransactionConfirmation(tx);
}
- // Check if the transaction was successful
- if (receipt.status === 0) {
- logger.error(`Transaction failed on-chain. Receipt: ${JSON.stringify(receipt)}`);
- throw httpErrors.internalServerError(
- 'Transaction reverted on-chain. This could be due to slippage, insufficient funds, or other blockchain issues.',
- );
+ // A revert threw out of the confirmation helper as a 400 TRANSACTION_FAILED. What is left
+ // is a transaction that is still pending after the extended poll: report it as PENDING
+ // with its hash rather than dereferencing a null receipt and losing the hash to a 500.
+ if (!outcome.confirmed) {
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
}
- logger.info(`Transaction confirmed: ${receipt.transactionHash}`);
- logger.info(`Gas used: ${receipt.gasUsed.toString()}`);
+ logger.info(`Transaction confirmed: ${outcome.signature}`);
+ logger.info(`Gas used: ${outcome.receipt.gasUsed.toString()}`);
// Calculate amounts using quote values
const amountIn = quote.estimatedAmountIn;
@@ -230,27 +227,22 @@ export async function executeAmmSwap(
const baseTokenBalanceChange = side === 'BUY' ? amountOut : -amountIn;
const quoteTokenBalanceChange = side === 'BUY' ? -amountIn : amountOut;
- // Calculate gas fee (formatTokenAmount already returns a number)
- const gasFee = formatTokenAmount(
- receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(),
- 18, // ETH has 18 decimals
- );
-
// Determine token addresses for computed fields
const tokenIn = quote.inputToken.address;
const tokenOut = quote.outputToken.address;
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
tokenIn,
tokenOut,
amountIn,
amountOut,
- fee: gasFee,
+ fee: outcome.fee,
baseTokenBalanceChange,
quoteTokenBalanceChange,
+ slippagePct,
},
};
} catch (error) {
@@ -278,51 +270,6 @@ export async function executeAmmSwap(
}
}
-export const executeSwapRoute: FastifyPluginAsync = async (fastify) => {
- fastify.post<{
- Body: ExecuteSwapRequestType;
- Reply: SwapExecuteResponseType;
- }>(
- '/execute-swap',
- {
- schema: {
- description: 'Execute a swap on Uniswap V2 AMM using Router02',
- tags: ['/connector/uniswap'],
- body: UniswapAmmExecuteSwapRequest,
- response: { 200: SwapExecuteResponse },
- },
- },
- async (request) => {
- try {
- const ethereumConfig = getEthereumChainConfig();
- const {
- walletAddress = ethereumConfig.defaultWallet,
- network = ethereumConfig.defaultNetwork,
- baseToken,
- quoteToken,
- amount,
- side = 'SELL',
- slippagePct,
- } = request.body as typeof UniswapAmmExecuteSwapRequest._type;
-
- return await executeAmmSwap(
- walletAddress,
- network,
- baseToken,
- quoteToken || '', // Handle optional quoteToken
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- if (e.statusCode) throw e;
- logger.error('Error executing swap:', e);
- throw httpErrors.internalServerError(e.message || 'Internal server error');
- }
- },
- );
-};
-
/**
* Standard AMM execute-swap entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. The quote token is derived from the pool; `amount` is denominated in the base token.
@@ -339,5 +286,3 @@ export async function executeSwap(
const { baseAddress, quoteAddress } = await resolveSwapPair(network, poolAddress, baseToken);
return await executeAmmSwap(walletAddress, network, baseAddress, quoteAddress, amount, side, slippagePct);
}
-
-export default executeSwapRoute;
diff --git a/src/connectors/uniswap/amm-routes/index.ts b/src/connectors/uniswap/amm-routes/index.ts
deleted file mode 100644
index 651da9f512..0000000000
--- a/src/connectors/uniswap/amm-routes/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { FastifyPluginAsync } from 'fastify';
-
-import addLiquidityRoute from './addLiquidity';
-import createPoolRoute from './createPool';
-import executeSwapRoute from './executeSwap';
-import poolInfoRoute from './poolInfo';
-import positionInfoRoute from './positionInfo';
-import quoteLiquidityRoute from './quoteLiquidity';
-import quoteSwapRoute from './quoteSwap';
-import removeLiquidityRoute from './removeLiquidity';
-
-export const uniswapAmmRoutes: FastifyPluginAsync = async (fastify) => {
- await fastify.register(poolInfoRoute);
- await fastify.register(positionInfoRoute);
- await fastify.register(quoteSwapRoute);
- await fastify.register(quoteLiquidityRoute);
- await fastify.register(executeSwapRoute);
- await fastify.register(addLiquidityRoute);
- await fastify.register(createPoolRoute);
- await fastify.register(removeLiquidityRoute);
-};
-
-export default uniswapAmmRoutes;
diff --git a/src/connectors/uniswap/amm-routes/poolInfo.ts b/src/connectors/uniswap/amm-routes/poolInfo.ts
index 3e6d30dec2..89c612a4a2 100644
--- a/src/connectors/uniswap/amm-routes/poolInfo.ts
+++ b/src/connectors/uniswap/amm-routes/poolInfo.ts
@@ -1,11 +1,8 @@
import { Contract } from '@ethersproject/contracts';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { GetPoolInfoRequestType, PoolInfo, PoolInfoSchema } from '../../../schemas/amm-schema';
+import { PoolInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
-import { UniswapAmmGetPoolInfoRequest } from '../schemas';
import { Uniswap } from '../uniswap';
import { IUniswapV2PairABI } from '../uniswap.contracts';
import { formatTokenAmount } from '../uniswap.utils';
@@ -57,48 +54,3 @@ export async function getPoolInfo(network: string, poolAddress: string): Promise
quoteTokenAmount,
};
}
-
-export const poolInfoRoute: FastifyPluginAsync = async (fastify) => {
- fastify.get<{
- Querystring: GetPoolInfoRequestType;
- Reply: Record;
- }>(
- '/pool-info',
- {
- schema: {
- description: 'Get AMM pool information from Uniswap V2',
- tags: ['/connector/uniswap'],
- querystring: UniswapAmmGetPoolInfoRequest,
- response: {
- 200: PoolInfoSchema,
- },
- },
- },
- async (request): Promise => {
- try {
- const { poolAddress, network } = request.query;
- return await getPoolInfo(network, poolAddress);
- } catch (e) {
- logger.error(`Error in pool-info route: ${e.message}`);
- if (e.stack) {
- logger.debug(`Stack trace: ${e.stack}`);
- }
-
- // Return appropriate error based on the error message
- if (e.statusCode) {
- throw e; // Already a formatted error carrying an HTTP status
- } else if (e.message && e.message.includes('invalid address')) {
- throw fastify.httpErrors.badRequest(`Invalid pool address`);
- } else if (e.message && e.message.includes('not found')) {
- logger.error('Not found error:', e);
- throw fastify.httpErrors.notFound('Resource not found');
- } else {
- logger.error('Unexpected error fetching pool info:', e);
- throw fastify.httpErrors.internalServerError('Failed to fetch pool info');
- }
- }
- },
- );
-};
-
-export default poolInfoRoute;
diff --git a/src/connectors/uniswap/amm-routes/positionInfo.ts b/src/connectors/uniswap/amm-routes/positionInfo.ts
index bebeca2b9a..9fb3e67d1d 100644
--- a/src/connectors/uniswap/amm-routes/positionInfo.ts
+++ b/src/connectors/uniswap/amm-routes/positionInfo.ts
@@ -1,16 +1,9 @@
import { Contract } from '@ethersproject/contracts';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- GetPositionInfoRequestType,
- GetPositionInfoRequest,
- PositionInfo,
- PositionInfoSchema,
-} from '../../../schemas/amm-schema';
+import { PositionInfo } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
import { Uniswap } from '../uniswap';
import { IUniswapV2PairABI } from '../uniswap.contracts';
import { formatTokenAmount } from '../uniswap.utils';
@@ -97,145 +90,3 @@ export async function checkLPAllowance(
);
}
}
-
-export const positionInfoRoute: FastifyPluginAsync = async (fastify) => {
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.get<{
- Querystring: GetPositionInfoRequestType;
- Reply: PositionInfo;
- }>(
- '/position-info',
- {
- schema: {
- description: 'Get position information for a Uniswap V2 pool',
- tags: ['/connector/uniswap'],
- querystring: {
- ...GetPositionInfoRequest,
- properties: {
- network: { type: 'string', default: 'base' },
- walletAddress: { type: 'string', examples: [walletAddressExample] },
- poolAddress: {
- type: 'string',
- examples: [''],
- },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- },
- },
- response: {
- 200: PositionInfoSchema,
- },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, walletAddress: requestedWalletAddress } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (!poolAddress) {
- throw fastify.httpErrors.badRequest('Pool address is required');
- }
-
- // Get Uniswap and Ethereum instances
- const uniswap = await Uniswap.getInstance(networkToUse);
- const ethereum = await Ethereum.getInstance(networkToUse);
-
- // Get wallet address - either from request or first available
- let walletAddress = requestedWalletAddress;
- if (!walletAddress) {
- walletAddress = await uniswap.getFirstWalletAddress();
- if (!walletAddress) {
- throw fastify.httpErrors.badRequest('No wallet address provided and no default wallet found');
- }
- logger.info(`Using first available wallet address: ${walletAddress}`);
- }
-
- // Get the pair contract
- const pairContract = new Contract(poolAddress, IUniswapV2PairABI.abi, ethereum.provider);
-
- // Get LP token balance for the wallet
- const lpBalance = await pairContract.balanceOf(walletAddress);
-
- // Get token addresses from the pair
- const [token0, token1] = await Promise.all([pairContract.token0(), pairContract.token1()]);
-
- // Get token objects by address
- const baseTokenObj = await uniswap.getToken(token0);
- const quoteTokenObj = await uniswap.getToken(token1);
-
- if (!baseTokenObj || !quoteTokenObj) {
- throw fastify.httpErrors.badRequest('Token information not found for pool');
- }
-
- // If no position, return early
- if (lpBalance.isZero()) {
- return {
- poolAddress,
- walletAddress,
- baseTokenAddress: baseTokenObj.address,
- quoteTokenAddress: quoteTokenObj.address,
- lpTokenAmount: 0,
- baseTokenAmount: 0,
- quoteTokenAmount: 0,
- price: 0,
- };
- }
-
- // Get total supply and reserves
- const [totalSupply, reserves] = await Promise.all([pairContract.totalSupply(), pairContract.getReserves()]);
-
- // Determine which token is base and which is quote
- const token0IsBase = token0.toLowerCase() === baseTokenObj.address.toLowerCase();
-
- // Calculate user's share of the pool
- const userShare = lpBalance.mul(10000).div(totalSupply).toNumber() / 10000; // Convert to percentage
-
- // Calculate token amounts
- const baseTokenReserve = token0IsBase ? reserves[0] : reserves[1];
- const quoteTokenReserve = token0IsBase ? reserves[1] : reserves[0];
-
- const userBaseTokenAmount = baseTokenReserve.mul(lpBalance).div(totalSupply);
- const userQuoteTokenAmount = quoteTokenReserve.mul(lpBalance).div(totalSupply);
-
- // Calculate price (quoteToken per baseToken)
- const baseTokenAmountFloat = formatTokenAmount(baseTokenReserve.toString(), baseTokenObj.decimals);
- const quoteTokenAmountFloat = formatTokenAmount(quoteTokenReserve.toString(), quoteTokenObj.decimals);
- const price = quoteTokenAmountFloat / baseTokenAmountFloat;
-
- // Format for response
- logger.info(`Raw LP balance: ${lpBalance.toString()}`);
- logger.info(`Total supply: ${totalSupply.toString()}`);
-
- const formattedLpAmount = formatTokenAmount(lpBalance.toString(), 18); // LP tokens have 18 decimals
- const formattedBaseAmount = formatTokenAmount(userBaseTokenAmount.toString(), baseTokenObj.decimals);
- const formattedQuoteAmount = formatTokenAmount(userQuoteTokenAmount.toString(), quoteTokenObj.decimals);
-
- logger.info(`Formatted LP amount: ${formattedLpAmount}`);
- logger.info(`Formatted base amount: ${formattedBaseAmount}`);
- logger.info(`Formatted quote amount: ${formattedQuoteAmount}`);
-
- return {
- poolAddress,
- walletAddress,
- baseTokenAddress: baseTokenObj.address,
- quoteTokenAddress: quoteTokenObj.address,
- lpTokenAmount: formattedLpAmount,
- baseTokenAmount: formattedBaseAmount,
- quoteTokenAmount: formattedQuoteAmount,
- price,
- };
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to get position info');
- }
- },
- );
-};
-
-export default positionInfoRoute;
diff --git a/src/connectors/uniswap/amm-routes/quoteLiquidity.ts b/src/connectors/uniswap/amm-routes/quoteLiquidity.ts
index 4fe7454503..03bc2bf58a 100644
--- a/src/connectors/uniswap/amm-routes/quoteLiquidity.ts
+++ b/src/connectors/uniswap/amm-routes/quoteLiquidity.ts
@@ -1,18 +1,12 @@
import { Contract } from '@ethersproject/contracts';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- QuoteLiquidityRequestType,
- QuoteLiquidityRequest,
- QuoteLiquidityResponseType,
- QuoteLiquidityResponse,
-} from '../../../schemas/amm-schema';
+import { QuoteLiquidityResponseType } from '../../../schemas/amm-schema';
import { logger } from '../../../services/logger';
import { Uniswap } from '../uniswap';
import { IUniswapV2PairABI, getUniswapV2RouterAddress } from '../uniswap.contracts';
-import { formatTokenAmount, getUniswapPoolInfo } from '../uniswap.utils';
+import { formatTokenAmount } from '../uniswap.utils';
import { getAmmPoolTokens } from './poolTokens';
@@ -82,7 +76,7 @@ export async function getUniswapAmmLiquidityQuote(
const pairContract = new Contract(poolAddressToUse, IUniswapV2PairABI.abi, ethereum.provider);
// Get token addresses and reserves
- const [token0, token1, reserves] = await Promise.all([
+ const [token0, , reserves] = await Promise.all([
pairContract.token0(),
pairContract.token1(),
pairContract.getReserves(),
@@ -175,87 +169,6 @@ export async function getUniswapAmmLiquidityQuote(
};
}
-export const quoteLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- fastify.get<{
- Querystring: QuoteLiquidityRequestType;
- Reply: QuoteLiquidityResponseType;
- }>(
- '/quote-liquidity',
- {
- schema: {
- description: 'Get liquidity quote for a Uniswap V2 pool',
- tags: ['/connector/uniswap'],
- querystring: {
- ...QuoteLiquidityRequest,
- properties: {
- ...QuoteLiquidityRequest.properties,
- network: { type: 'string', default: 'base' },
- poolAddress: {
- type: 'string',
- examples: [''],
- },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- baseTokenAmount: { type: 'number', examples: [0.001] },
- quoteTokenAmount: { type: 'number', examples: [2.5] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: {
- 200: QuoteLiquidityResponse,
- },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseTokenAmount, quoteTokenAmount, slippagePct } = request.query;
-
- if (!poolAddress) {
- throw fastify.httpErrors.badRequest('Pool address is required');
- }
-
- // Get pool information to determine tokens
- const poolInfo = await getUniswapPoolInfo(poolAddress, network, 'amm');
- if (!poolInfo) {
- throw fastify.httpErrors.notFound(`Pool not found: ${poolAddress}`);
- }
-
- const baseToken = poolInfo.baseTokenAddress;
- const quoteToken = poolInfo.quoteTokenAddress;
-
- const quote = await getUniswapAmmLiquidityQuote(
- network,
- poolAddress,
- baseToken,
- quoteToken,
- baseTokenAmount,
- quoteTokenAmount,
- slippagePct,
- );
-
- // Use standard gas limit for liquidity operations
- const computeUnits = 500000;
-
- return {
- baseLimited: quote.baseLimited,
- baseTokenAmount: quote.baseTokenAmount,
- quoteTokenAmount: quote.quoteTokenAmount,
- baseTokenAmountMax: quote.baseTokenAmountMax,
- quoteTokenAmountMax: quote.quoteTokenAmountMax,
- computeUnits,
- };
- } catch (e) {
- logger.error(e);
- if (e.statusCode) {
- throw e;
- }
- throw fastify.httpErrors.internalServerError('Failed to get liquidity quote');
- }
- },
- );
-};
-
/**
* Standard AMM quote-liquidity entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. Base/quote follow the pair's token0/token1 orientation.
@@ -285,5 +198,3 @@ export async function quoteLiquidity(
quoteTokenAmountMax: q.quoteTokenAmountMax,
};
}
-
-export default quoteLiquidityRoute;
diff --git a/src/connectors/uniswap/amm-routes/quoteSwap.ts b/src/connectors/uniswap/amm-routes/quoteSwap.ts
index 7241f4f18b..88ba08fa0d 100644
--- a/src/connectors/uniswap/amm-routes/quoteSwap.ts
+++ b/src/connectors/uniswap/amm-routes/quoteSwap.ts
@@ -1,20 +1,14 @@
import { Token, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core';
-import { Pair as V2Pair, Route as V2Route, Trade as V2Trade } from '@uniswap/v2-sdk';
+import { Route as V2Route, Trade as V2Trade } from '@uniswap/v2-sdk';
import { BigNumber } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import {
- QuoteSwapRequestType,
- QuoteSwapResponseType,
- QuoteSwapRequest,
- QuoteSwapResponse,
-} from '../../../schemas/amm-schema';
+import { QuoteSwapResponseType } from '../../../schemas/amm-schema';
import { httpErrors } from '../../../services/error-handler';
import { logger } from '../../../services/logger';
import { Uniswap } from '../uniswap';
import { UniswapConfig } from '../uniswap.config';
-import { formatTokenAmount, getUniswapPoolInfo } from '../uniswap.utils';
+import { formatTokenAmount } from '../uniswap.utils';
import { resolveSwapPair } from './poolTokens';
@@ -190,7 +184,7 @@ async function formatSwapQuote(
try {
// Use the extracted quote function
- const { quote, uniswap, ethereum, baseTokenObj, quoteTokenObj } = await getUniswapAmmQuote(
+ const { quote, ethereum } = await getUniswapAmmQuote(
network,
poolAddress,
baseToken,
@@ -244,7 +238,6 @@ async function formatSwapQuote(
const tokenOut = quote.outputToken.address;
// Calculate fee (V2 has 0.3% fixed fee)
- const fee = quote.estimatedAmountIn * 0.003;
return {
// Base QuoteSwapResponse fields in correct order
@@ -269,144 +262,6 @@ async function formatSwapQuote(
}
}
-export const quoteSwapRoute: FastifyPluginAsync = async (fastify) => {
- // Import the httpErrors plugin to ensure it's available
- await fastify.register(require('@fastify/sensible'));
-
- fastify.get<{
- Querystring: QuoteSwapRequestType;
- Reply: QuoteSwapResponseType;
- }>(
- '/quote-swap',
- {
- schema: {
- description: 'Get swap quote for Uniswap V2 AMM',
- tags: ['/connector/uniswap'],
- querystring: {
- ...QuoteSwapRequest,
- properties: {
- ...QuoteSwapRequest.properties,
- network: { type: 'string', default: 'base' },
- baseToken: { type: 'string', examples: ['WETH'] },
- quoteToken: { type: 'string', examples: ['USDC'] },
- amount: { type: 'number', examples: [0.001] },
- side: { type: 'string', enum: ['BUY', 'SELL'], examples: ['SELL'] },
- poolAddress: { type: 'string', examples: [''] },
- slippagePct: { type: 'number', examples: [1] },
- },
- },
- response: { 200: QuoteSwapResponse },
- },
- },
- async (request) => {
- try {
- const { network, poolAddress, baseToken, quoteToken, amount, side, slippagePct } = request.query;
-
- const networkToUse = network;
-
- // Validate essential parameters
- if (!baseToken || !amount || !side) {
- throw httpErrors.badRequest('baseToken, amount, and side are required');
- }
-
- const uniswap = await Uniswap.getInstance(networkToUse);
-
- let poolAddressToUse = poolAddress;
- let baseTokenToUse: string;
- let quoteTokenToUse: string;
-
- if (poolAddressToUse) {
- // Pool address provided, get pool info to determine tokens
- const poolInfo = await getUniswapPoolInfo(poolAddressToUse, networkToUse, 'amm');
- if (!poolInfo) {
- throw httpErrors.notFound(`Pool not found: ${poolAddressToUse}`);
- }
-
- // Determine which token is base and which is quote based on the provided baseToken
- if (baseToken === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (baseToken === poolInfo.quoteTokenAddress) {
- // User specified the quote token as base, so swap them
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- // Try to resolve baseToken as symbol to address
- const resolvedToken = await uniswap.getToken(baseToken);
-
- if (resolvedToken) {
- if (resolvedToken.address === poolInfo.baseTokenAddress) {
- baseTokenToUse = poolInfo.baseTokenAddress;
- quoteTokenToUse = poolInfo.quoteTokenAddress;
- } else if (resolvedToken.address === poolInfo.quoteTokenAddress) {
- baseTokenToUse = poolInfo.quoteTokenAddress;
- quoteTokenToUse = poolInfo.baseTokenAddress;
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- } else {
- throw httpErrors.badRequest(`Token ${baseToken} not found in pool ${poolAddressToUse}`);
- }
- }
- } else {
- // No pool address provided, need quoteToken to find pool
- if (!quoteToken) {
- throw httpErrors.badRequest('quoteToken is required when poolAddress is not provided');
- }
-
- baseTokenToUse = baseToken;
- quoteTokenToUse = quoteToken;
-
- // Find pool using findDefaultPool
- poolAddressToUse = await uniswap.findDefaultPool(baseTokenToUse, quoteTokenToUse, 'amm');
-
- if (!poolAddressToUse) {
- throw httpErrors.notFound(`No AMM pool found for pair ${baseTokenToUse}-${quoteTokenToUse}`);
- }
- }
-
- return await formatSwapQuote(
- networkToUse,
- poolAddressToUse,
- baseTokenToUse,
- quoteTokenToUse,
- amount,
- side as 'BUY' | 'SELL',
- slippagePct,
- );
- } catch (e) {
- logger.error(`Error in quote-swap route: ${e.message}`);
-
- // If it's already a Fastify HTTP error, re-throw it
- if (e.statusCode) {
- throw e;
- }
-
- // Check for specific error types
- if (e.message?.includes('Insufficient liquidity')) {
- logger.error('Request error:', e);
- throw httpErrors.badRequest('Invalid request');
- }
- if (e.message?.includes('Pool not found') || e.message?.includes('No AMM pool found')) {
- logger.error('Pool not found error:', e);
- throw httpErrors.notFound(e.message || 'Pool not found');
- }
- if (e.message?.includes('token not found')) {
- logger.error('Request error:', e);
- throw httpErrors.badRequest('Invalid request');
- }
-
- // Default to internal server error
- logger.error('Unexpected error getting swap quote:', e);
- logger.error('Error stack:', e.stack);
- throw httpErrors.internalServerError(e.message || 'Error getting swap quote');
- }
- },
- );
-};
-
-export default quoteSwapRoute;
-
/**
* Standard AMM quote-swap entry point (network-based) — consumed by the unified /trading/amm
* dispatcher. `amount` is denominated in the base token; the quote token is derived from the pool.
diff --git a/src/connectors/uniswap/amm-routes/removeLiquidity.ts b/src/connectors/uniswap/amm-routes/removeLiquidity.ts
index cfe1f9d645..4c91378805 100644
--- a/src/connectors/uniswap/amm-routes/removeLiquidity.ts
+++ b/src/connectors/uniswap/amm-routes/removeLiquidity.ts
@@ -1,14 +1,10 @@
import { Contract } from '@ethersproject/contracts';
-import { Static } from '@sinclair/typebox';
import { Percent } from '@uniswap/sdk-core';
-import { utils } from 'ethers';
-import { FastifyPluginAsync } from 'fastify';
import { Ethereum } from '../../../chains/ethereum/ethereum';
-import { RemoveLiquidityResponseType, RemoveLiquidityResponse } from '../../../schemas/amm-schema';
+import { RemoveLiquidityResponseType } from '../../../schemas/amm-schema';
+import { TransactionStatus } from '../../../schemas/chain-schema';
import { httpErrors } from '../../../services/error-handler';
-import { logger } from '../../../services/logger';
-import { UniswapAmmRemoveLiquidityRequest } from '../schemas';
import { Uniswap } from '../uniswap';
import { UniswapConfig } from '../uniswap.config';
import { getUniswapV2RouterAddress, IUniswapV2Router02ABI, IUniswapV2PairABI } from '../uniswap.contracts';
@@ -29,8 +25,6 @@ export async function removeLiquidity(
poolAddress: string,
percentageToRemove: number,
slippagePct: number = UniswapConfig.config.slippagePct,
- gasPrice?: string,
- maxGas?: number,
): Promise {
if (!poolAddress || !percentageToRemove) throw httpErrors.badRequest('Missing required parameters');
if (percentageToRemove <= 0 || percentageToRemove > 100) {
@@ -85,8 +79,7 @@ export async function removeLiquidity(
await checkLPAllowance(ethereum, wallet, poolAddress, routerAddress, liquidityToRemove);
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes from now
- const gasPriceGwei = gasPrice ? parseFloat(utils.formatUnits(gasPrice, 'gwei')) : undefined;
- const gasOptions = await ethereum.prepareGasOptions(gasPriceGwei, maxGas || AMM_REMOVE_LIQUIDITY_GAS_LIMIT);
+ const gasOptions = await ethereum.prepareGasOptions(undefined, AMM_REMOVE_LIQUIDITY_GAS_LIMIT);
let tx;
if (baseTokenObj.symbol === 'WETH') {
@@ -122,82 +115,22 @@ export async function removeLiquidity(
);
}
- const receipt = await ethereum.handleTransactionExecution(tx);
+ const outcome = await ethereum.handleTransactionConfirmation(tx);
+ if (!outcome.confirmed) {
+ // Still pending — the expected amounts were computed before sending and have not moved.
+ return { signature: outcome.signature, status: TransactionStatus.PENDING };
+ }
+
const baseTokenAmountRemoved = formatTokenAmount(expectedBaseTokenAmount.toString(), baseTokenObj.decimals);
const quoteTokenAmountRemoved = formatTokenAmount(expectedQuoteTokenAmount.toString(), quoteTokenObj.decimals);
- const gasFee = formatTokenAmount(receipt.gasUsed.mul(receipt.effectiveGasPrice).toString(), 18);
return {
- signature: receipt.transactionHash,
- status: receipt.status,
+ signature: outcome.signature,
+ status: TransactionStatus.CONFIRMED,
data: {
- fee: gasFee,
+ fee: outcome.fee,
baseTokenAmountRemoved,
quoteTokenAmountRemoved,
},
};
}
-
-export const removeLiquidityRoute: FastifyPluginAsync = async (fastify) => {
- await fastify.register(require('@fastify/sensible'));
- const walletAddressExample = await Ethereum.getWalletAddressExample();
-
- fastify.post<{
- Body: Static