diff --git a/CLAUDE.md b/CLAUDE.md index efa4263f2..21c243881 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,8 @@ Three ways to construct the SDK: `constructSimpleSDK` accepts `{ axios }`, `{ fetch }`, or `{ fetcher }` for the network layer, and optionally `{ ethersProviderOrSigner | ethersV6ProviderOrSigner | viemClient | web3, account }` for signing/transacting. +`constructFullSDK` exposes namespaced methods: `sdk.delta.*`, `sdk.swap.*`, `sdk.quote.*`, etc. + ## Provider Adapters (`src/helpers/providers/`) Each file exports `constructContractCaller(provider, account)` → `ContractCallerFunctions`: @@ -43,11 +45,11 @@ Each file exports `constructContractCaller(provider, account)` → `ContractCall ## Module Structure (`src/methods/`) -- `delta/` — Core feature: Delta auction orders (see detail below) +- `delta/` — Core feature: Delta auction orders (server-side order building, route-based pricing, paginated orders; see detail below) - `swap/` — Token swap: rates, transaction building, approvals, balances -- `limitOrders/` — **Deprecated.** EIP-712 signed limit orders +- `otcOrders/` — EIP-712 signed OTC orders - `nftOrders/` — **Deprecated.** EIP-712 signed NFT orders -- `quote/` — Unified quote endpoint +- `quote/` — Unified `/v2/quote` endpoint (mode-selectable Delta v2 price / market / fallback) ## Composable Constructor Pattern @@ -56,7 +58,7 @@ Every feature module exports a `constructXxx(options) => XxxFunctions` factory: - `D` selects required caller methods: `'transactCall'` | `'signTypedDataCall'` | both - Generic `` = transaction response type (e.g., `TxHash`, `ethers.ContractTransaction`) - Non-generic constructors use `any` (for API-only flows that don't return tx responses) -- All Delta constructors are combined in `constructAllDeltaOrdersHandlers` in `src/methods/delta/index.ts` +- All Delta constructors are combined in `constructAllDeltaOrdersHandlers` in `src/methods/delta/index.ts`. **Convention:** bind each `constructXxx(options)` call to a named local (`const deltaPrice = constructGetDeltaPrice(options)`), then spread those locals into the returned object — don't spread the constructor calls inline. ## Key Patterns @@ -73,52 +75,82 @@ Every feature module exports a `constructXxx(options) => XxxFunctions` factory: ## Delta Module (`src/methods/delta/`) -Three order families, each with build/sign/post/preSign constructors: +Delta is the SDK's core feature: server-built, on-chain auction orders. Exposed as `sdk.delta.*` and via bare top-level exports. + +> **History.** Delta was once a **v1** with local EIP-712 order building and per-family sign functions. It was replaced (breaking) by the server-built **v2** described here — `sdk.delta.*` *is* v2, with a single set of bare top-level exports. All Delta URLs use the `/v2/delta/...` prefix. + +Order building is **server-side**: `POST /v2/delta/orders/build` returns a `BuiltDeltaOrder { toSign, orderHash }`; a single `signDeltaOrder(builtOrder)` signs every family; `post*` submits the signed order. Partner fee is passed as raw params (`partner`, `partnerFeeBps`) to the server rather than resolved locally. Reads are paginated (`PaginatedResponse`), price is route-based. + +### Order families + +All built via `POST /v2/delta/orders/build` with an `orderType` field: + +| Family | `orderType` / `onChainOrderType` | Build params | Build fn | +|--------|-------------------|-----------|----------| +| Standard | `'Order'` | `BuildDeltaOrderParams` | `buildDeltaOrder` | +| External | `'ExternalOrder'` | `BuildExternalDeltaOrderParams` (adds `handler`, `data`) | `buildExternalDeltaOrder` | +| TWAP Sell | `'TWAPOrder'` | `BuildTWAPSellDeltaOrderParams` | `buildTWAPDeltaOrder` | +| TWAP Buy | `'TWAPBuyOrder'` | `BuildTWAPBuyDeltaOrderParams` | `buildTWAPDeltaOrder` | +| Productive | `'ProductiveOrder'` | _read-only_ — no SDK builder (server-produced) | — | -| Family | `onChainOrderType` | Order type | Build input key | -|--------|-------------------|-----------|-----------------| -| Standard | `'Order'` | `DeltaAuctionOrder` | `buildDeltaOrder` | -| External | `'ExternalOrder'` | `ExternalDeltaOrder` | `buildExternalDeltaOrder` (has `handler` field instead of `bridge`) | -| TWAP Sell | `'TWAPOrder'` | `TWAPDeltaOrder` | `buildTWAPDeltaOrder` | -| TWAP Buy | `'TWAPBuyOrder'` | `TWAPBuyDeltaOrder` | `buildTWAPDeltaOrder` | +`'FillableOrder'` is also a key in `OnChainOrderMap`/`OnChainOrderType`, mapping to the same `DeltaAuctionOrder` shape as `'Order'`. It is not a separate buildable family — it's the `onChainOrderType` the server reports when a Standard order is `partiallyFillable`. Only surfaces (read-only) on the way back through the read paths. -Each family has four files: `build*`, `sign*`, `post*`, `preSign*`. High-level orchestrators (`constructSubmitDeltaOrder`, `constructSubmitExternalDeltaOrder`, `constructSubmitTWAPDeltaOrder`) in `index.ts` wrap build→sign→post. +Submit orchestrators (`constructSubmitDeltaOrder`, `constructSubmitExternalDeltaOrder`, `constructSubmitTWAPDeltaOrder`) in `index.ts` wrap build→sign→post. Productive orders surface only through the read paths (`getDeltaOrders*` / `getDeltaOrderById*`). ### Key Files -| File | Constructor | Purpose | Generic? | Pattern | -|------|-------------|---------|----------|---------| -| `index.ts` | `constructSubmitDeltaOrder`, `constructAllDeltaOrdersHandlers` | Composite: orchestrates all modules, defines `DeltaOrderHandlers` | `submitDelta`: No, `allHandlers`: `` | Composite | -| `buildDeltaOrder.ts` | `constructBuildDeltaOrder` | Build `SignableDeltaOrderData` from params (fetches contract + partner fee, then local computation) | No | API fetch + local | -| `signDeltaOrder.ts` | `constructSignDeltaOrder` | EIP-712 sign order via `signTypedDataCall` → returns signature `string` | No (`any`) | `signTypedDataCall` | -| `postDeltaOrder.ts` | `constructPostDeltaOrder` | POST signed order to API → `DeltaOrderApiResponse` | No | `fetcher` POST | -| `getDeltaPrice.ts` | `constructGetDeltaPrice` | Fetch quote/price from API. Overloaded: returns `DeltaPrice` (same-chain) or `BridgePrice` (cross-chain when `destChainId` present) | No | `fetcher` GET | -| `getDeltaOrders.ts` | `constructGetDeltaOrders` | Query orders from API: `getDeltaOrderById`, `getDeltaOrderByHash`, `getDeltaOrders` (list), `getRequiredBalanceForDeltaLimitOrders` | No | `fetcher` GET | -| `getDeltaContract.ts` | `constructGetDeltaContract` | Resolve ParaswapDelta contract address from contracts endpoint | No | `fetcher` GET | -| `approveForDelta.ts` | `constructApproveTokenForDelta` | ERC-20 `approve` with ParaswapDelta as spender (delegates to `approveTokenMethodFactory`) | `` | `transactCall` | -| `preSignDeltaOrder.ts` | `constructPreSignDeltaOrder` | On-chain `setPreSignature` + order hashing helpers (`hashDeltaOrderTypedData`, `hashDeltaOrder`, `preSignDeltaOrder`) | `` | `transactCall` | -| `cancelDeltaOrder.ts` | `constructCancelDeltaOrder` | API cancel: `signCancelLimitDeltaOrderRequest` → `postCancelLimitDeltaOrderRequest` → `cancelLimitDeltaOrders` (orchestrator) | No (`any`) | `signTypedDataCall` + `fetcher` POST | -| `deltaTokenModule.ts` | `constructDeltaTokenModule` | On-chain `cancelAndWithdrawDeltaOrder`, `withdrawDeltaNative`, `depositNativeAndPreSign`, `depositNativeAndPreSignDeltaOrder` | `` | `transactCall` | -| `getPartnerFee.ts` | `constructGetPartnerFee` | Fetch partner fee info (internally cached per partner in a `Map`) | No | `fetcher` GET | -| `getBridgeInfo.ts` | `constructGetBridgeInfo` | `getBridgeInfo` (supported routes) + `getBridgeProtocols` | No | `fetcher` GET | -| `isTokenSupportedInDelta.ts` | `constructIsTokenSupportedInDelta` | Check if a token is supported → `boolean` | No | `fetcher` GET | -| `constants.ts` | — | `DEFAULT_BRIDGE` constant (all-zero values for same-chain orders) | — | — | +| File | Constructor | Purpose | Generic? | +|------|-------------|---------|----------| +| `index.ts` | `constructAllDeltaOrdersHandlers`, `constructSubmit{Delta,External,TWAP}Order`, `constructSignDeltaOrder` | Composite: orchestrates all modules, defines `DeltaOrderHandlers`, hosts the single `signDeltaOrder` (signs any `BuiltDeltaOrder`), re-exports every leaf module | `allHandlers`: `` | +| `buildDeltaOrder.ts` | `constructBuildDeltaOrder` | POST `/v2/orders/build` → `BuiltDeltaOrder` | No | +| `buildExternalDeltaOrder.ts` | `constructBuildExternalDeltaOrder` | Same, `orderType: 'ExternalOrder'` | No | +| `buildTWAPDeltaOrder.ts` | `constructBuildTWAPDeltaOrder` | Same, `orderType: 'TWAPOrder'` / `'TWAPBuyOrder'` | No | +| `postDeltaOrder.ts` / `postExternalDeltaOrder.ts` / `postTWAPDeltaOrder.ts` | `constructPostDeltaOrder` | POST `/v2/delta/orders` → `DeltaAuction` | No | +| `getDeltaPrice.ts` | `constructGetDeltaPrice` | GET `/v2/delta/prices` → `DeltaPrice` (route-based: `route` + `alternatives`; cross-chain handled in-route via `destChainId`) | No | +| `getDeltaOrders.ts` | `constructGetDeltaOrders` | `getDeltaOrders` (paginated list), `getDeltaOrderById`, `getDeltaOrderByHash`, `getRequiredBalanceForDeltaOrders`. Reads return `DeltaAuction`. | No | +| `cancelDeltaOrder.ts` | `constructCancelDeltaOrder` | `signCancelDeltaOrderRequest` → `postCancelDeltaOrderRequest` → `cancelDeltaOrders` (orchestrator). POST `/v2/orders/cancel`. | No (`any`) | +| `getBridgeRoutes.ts` | `constructGetBridgeRoutes` | `getBridgeRoutes` (flat `BridgeRoute[]`) + `getBridgeProtocols` | No | +| `isTokenSupportedInDelta.ts` | `constructIsTokenSupportedInDelta` | GET `/v2/delta/prices/is-token-supported` → `boolean` | No | +| `getAgentsList.ts` | `constructGetAgentsList` | GET `/v2/agents/list/:chainId` → `string[]` | No | +| `getDeltaContract.ts` | `constructGetDeltaContract` | Resolve ParaswapDelta contract address | No | +| `getPartnerFee.ts` | `constructGetPartnerFee` | Fetch partner fee info (cached per partner in a `Map`) | No | +| `approveForDelta.ts` | `constructApproveTokenForDelta` | ERC-20 `approve` with ParaswapDelta as spender | `` | +| `preSignDeltaOrder.ts` / `preSignExternalDeltaOrder.ts` / `preSignTWAPDeltaOrder.ts` | `constructPreSign*DeltaOrder` | On-chain `setPreSignature` + order hashing helpers (`produceDeltaOrderHash`, etc.) | `` | +| `deltaTokenModule.ts` | `constructDeltaTokenModule` | On-chain `cancelAndWithdrawDeltaOrder`, `withdrawDeltaNative`, `depositNativeAndPreSign`, `depositNativeAndPreSignDeltaOrder` | `` | + +The on-chain modules (`preSign*`, `deltaTokenModule`, `approveForDelta`) and the local EIP-712 hashing helpers (`helpers/build*OrderData`, `helpers/misc`) are retained from the original delta module — they back the on-chain flows (pre-signing, native deposit, cancel-and-withdraw) that complement server-side building. + +### Types + +- **`src/methods/delta/types.ts`** (v2 surface) — `BuiltDeltaOrder`, `DeltaPrice` (+ `DeltaRoute` / `DeltaRouteStep` / `DeltaRouteBridge` / `DeltaRouteBridgeContractParams`, `DeltaPriceToken`, `DeltaTokenAmount`, `BridgeTag`, `BridgeRoute`), `DeltaAuction` (the envelope returned by **every** read/post — `status: DeltaOrderStatus`, `input`/`output: DeltaTokenSide`, flat `transactions: DeltaTransaction`, explicit `side`; generic over `onChainOrderType`, narrowing `order` to `OnChainOrderMap[T]`), `DeltaOrderStatus`, `DeltaTokenSide`, `DeltaTransaction`. +- **`src/methods/delta/helpers/types.ts`** (shared on-chain order structs) — `DeltaAuctionOrder`, `ExternalDeltaOrder`, `TWAPDeltaOrder`, `TWAPBuyDeltaOrder`, `ProductiveDeltaOrder`, `Bridge`, `OnChainOrderMap` (Standard/Fillable/External/TWAP Sell/TWAP Buy/Productive), `OnChainOrderType`, `TWAPOnChainOrderType`, `DeltaOrderUnion`, `DeltaOrderType` (`'MARKET' | 'LIMIT'`), `DeltaAmounts*`, `UnifiedDeltaOrderData`, `OrderKind` / `SwapSideToOrderKind`. +- `PaginatedResponse` lives in `src/types.ts`. ### Delta Helpers (`src/methods/delta/helpers/`) -- `types.ts` — `DeltaAuctionOrder`, `Bridge`, `DeltaAuction`, `DeltaAuctionStatus`, `BridgeMetadata`, `BridgeStatus`, `BridgePriceInfo`, `SwapSideToOrderKind`, `OnChainOrderType`, `DeltaAuctionUnion` -- `buildDeltaOrderData.ts` — `buildDeltaSignableOrderData`, `produceDeltaOrderTypedData`, `SignableDeltaOrderData`, `BuildDeltaOrderDataInput`, `DELTA_DEFAULT_EXPIRY` -- `buildCancelDeltaOrderData.ts` — `buildCancelDeltaOrderSignableData`, `SignableCancelDeltaOrderData`, `CancelDeltaOrderData` -- `buildTWAPOrderData.ts` — `buildTWAPSignableOrderData`, `SignableTWAPOrderData`, `BuildTWAPOrderDataInput` -- `buildExternalOrderData.ts` — `buildExternalSignableOrderData`, `SignableExternalOrderData` -- `misc.ts` — `sanitizeDeltaOrderData` (strips extra fields before signing/hashing), `applySlippage`, `resolvePartnerFee` -- `orders.ts` — `OrderHelpers` namespace with `.checks` (type guards: `isDeltaOrder`, `isTWAPOrder`, `isExternalOrder`, `isOrderCrosschain`, `isExecutedAuction`, etc.) and `.getters` (`getUnifiedDeltaOrderData`, `getAuctionAmounts`, `getTwapAuctionAmounts`, `getFilledPercent`, etc.) -- `abi.ts` — shared ABI fragments +- `types.ts` — shared order-struct types (above). +- `buildDeltaOrderData.ts` / `buildExternalOrderData.ts` / `buildTWAPOrderData.ts` — EIP-712 typed-data producers (`produceDeltaOrderTypedData` / `produceExternalOrderTypedData` / `produceTWAPOrderTypedData`) + the `SignableDeltaOrderData` / `SignableExternalOrderData` / `SignableTWAPOrderData` types. Consumed by `preSign*` / `deltaTokenModule` for on-chain hashing/pre-signing. (The v1 local order-struct builders and `DELTA_DEFAULT_EXPIRY` were dropped — the server builds the order now.) +- `buildCancelDeltaOrderData.ts` — `SignableCancelDeltaOrderData`, `CancelDeltaOrderData`. +- `misc.ts` — `sanitizeDeltaOrderData` / `sanitizeExternalOrderData` / `sanitizeTWAPOrderData` (strip extra fields off an order before hashing/pre-signing). +- `orders.ts` — single `OrderHelpers` object `{ checks, getters }` (no v1/v2 split): + - `checks`: order-struct guards (`isDeltaOrder`, `isExternalOrder`, `isTWAPOrder` / `isTWAPSellOrder` / `isTWAPBuyOrder`, `isProductiveOrder`, `isOrderCrosschain`); auction discriminants (`isDeltaAuction`, `isExternalAuction`, `isTWAPAuction` / `isTWAPSellAuction` / `isTWAPBuyAuction`, `isProductiveAuction`, `isFillableAuction`); status guards over the v2 envelope (`isCompletedAuction`, `isFailedAuction`, `isCanceledAuction`, `isExpiredAuction`, `isPendingAuction`, `isPartiallyExecutedAuction`). + - `getters`: `getUnifiedDeltaOrderData`, `getAuctionAmounts` (`{ expected, executed }`), `getAuctionTokenAddresses`, `getAuctionSrcChainId` / `getAuctionDestChainId`, `getAuctionSwapSide` (reads `auction.side`), `getTransactionAmounts`, `getFilledPercent`; plus order-level `getOrderTokenAddresses`, `getSwapSideFromDeltaOrder`, `getSwapSideFromTwapOrderType`, `getExpectedTwapSrcAmount` / `getExpectedTwapDestAmount` / `getExpectedTwapOrderAmounts`. +- `abi.ts` — shared ABI fragments. ### Core Types (`src/`) -- `types.ts` — `ConstructProviderFetchInput`, `ContractCallerFunctions`, `TxSendOverrides` +- `types.ts` — `ConstructProviderFetchInput`, `ContractCallerFunctions`, `TxSendOverrides`, `PaginatedResponse` - `helpers/misc.ts` — `ExtractAbiMethodNames` - `sdk/partial.ts` — `constructPartialSDK`, `InferWithTxResponse` type tuple +### `OnChainOrderType` note + +`'ProductiveOrder'` is part of `OnChainOrderType` and `OnChainOrderMap` — `DeltaAuction<'ProductiveOrder'>` resolves to `ProductiveDeltaOrder`. The type is wired through the public surface, but **no build/sign/post helpers** exist for productive orders (`constructSubmit*` / `construct(Build|Post)*` cover only `Order`, `ExternalOrder`, `TWAPOrder`, `TWAPBuyOrder`). Productive orders are read-only from the SDK's perspective. Sides are inferred as `SELL` (productive orders carry no `OrderKind`). + +`'FillableOrder'` is likewise a member of `OnChainOrderType`/`OnChainOrderMap`, resolving (via `DeltaAuction<'FillableOrder'>`) to the same `DeltaAuctionOrder` shape as `'Order'`. It's the `onChainOrderType` the server reports for a `partiallyFillable` Standard order — there is no separate builder. Consumers narrowing a `DeltaAuction` should treat `onChainOrderType === 'FillableOrder'` the same as `'Order'` (`isDeltaAuction(a) || isFillableAuction(a)`). + +## Quote Module (`src/methods/quote/`) + +`constructGetQuote` → `getQuote` hits **`GET /v2/quote`**. Same overloaded, `mode`-based shape as before (`mode: 'delta' | 'market' | 'all'`, with `'all'` returning Delta pricing or a market `fallbackReason`) — the only v2 change is that the delta side is the v2 `DeltaPrice` (route-based) from `methods/delta/types`, not the old v1 `DeltaPrice`/`BridgePrice`. Return types (`QuoteWithDeltaPrice`, `QuoteWithBridgePrice`, `QuoteWithDeltaPriceAndBridgePrice`, `QuoteWithMarketPrice`, `QuoteWithMarketPriceAsFallback`) and all function overloads are preserved. Exposed as `sdk.quote.getQuote`. + ## Checklist: Adding a New On-Chain Method 1. Add ABI to the module file (inline `as const`) @@ -168,4 +200,5 @@ OrderWithSig tuple: - EIP-712 domain: `{ name: 'Portikus', version: '2.0.0', chainId, verifyingContract }` - Order hash: computed via viem's `hashTypedData` in `produceDeltaOrderHash()` - ABI style: always inline `const ... as const`, never imported from external ABI files -- Cross-chain detection: `isOrderCrosschain(order)` checks `bridge.destinationChainId !== 0`; `DEFAULT_BRIDGE` has all-zero values for same-chain orders +- Cross-chain detection: `isOrderCrosschain(order)` checks `bridge.destinationChainId !== 0` +- **Commit messages**: `prefix/what was done` — `prefix` is the file, function, or component that was changed. Examples: `OrderDetails/added button`, `useDeltaPrice/migrate to v2 route fields`. Do NOT add a `Co-Authored-By: Claude` trailer. diff --git a/README.md b/README.md index 4f4005fb5..851f9ddef 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ const allowance = await sdk.getAllowance(userAddress, tokenAddress); ### Basic usage -The easiest way to make a trade is to rely on Quote method that communicates with [/quote API endpoint](https://developers.velora.xyz/api/velora-api/velora-delta-api/retrieve-delta-price-with-fallback-to-market) +The easiest way to make a trade is to rely on the Quote method that communicates with the `/v2/quote` API endpoint. With `mode: 'all'` it returns Delta v2 pricing when possible, falling back to the current market price (use `mode: 'delta'` or `mode: 'market'` to request a single source). ```typescript import axios from 'axios'; @@ -196,11 +196,12 @@ const quote = await simpleSDK.quote.getQuote({ srcDecimals: 18, destDecimals: 18, mode: 'all', // Delta quote if possible, with fallback to Market price - side: 'SELL', // Delta mode only supports side: SELL currenly + side: 'SELL', // Delta mode only supports side: SELL currently // partner: "..." // if available }); if ('delta' in quote) { + // quote.delta is the v2 DeltaPrice (route-based) const deltaPrice = quote.delta; const DeltaContract = await simpleSDK.delta.getDeltaContract(); @@ -208,58 +209,26 @@ if ('delta' in quote) { // or sign a Permit1 or Permit2 TransferFrom for DeltaContract await simpleSDK.delta.approveTokenForDelta(amount, Token1); - const slippagePercent = 0.5; - const destAmountAfterSlippage = BigInt( - // get rid of exponential notation - - +(+deltaPrice.destAmount * (1 - slippagePercent / 100)).toFixed(0) - // get rid of decimals - ).toString(10); - + // order building is server-side: pass the quoted route + side, no local amounts const deltaAuction = await simpleSDK.delta.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or any deltaPrice.alternatives[i] + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send the output destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: Token1, - destToken: Token2, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount + slippage: 50, // 50 bps = 0.5% }); - // poll if necessary - function isExecutedDeltaAuction( - auction: Omit, - waitForCrosschain = true // only consider executed when destChain work is done - ) { - if (auction.status !== 'EXECUTED') return false; - - // crosschain Order is executed on destChain if bridgeStatus is filled - if (waitForCrosschain && auction.order.bridge.destinationChainId !== 0) { - return auction.bridgeStatus === 'filled'; - } - - return true; - } - - function fetchOrderPeriodically(auctionId: string) { + // poll if necessary — v2 status COMPLETED already accounts for any dest-chain bridge + function startStatusCheck(auctionId: string) { const intervalId = setInterval(async () => { const auction = await simpleSDK.delta.getDeltaOrderById(auctionId); - console.log('checks: ', auction); // Handle or log the fetched auction as needed - - if (isExecutedDeltaAuction(auction)) { - clearInterval(intervalId); // Stop interval if completed + if (auction.status === 'COMPLETED') { + clearInterval(intervalId); console.log('Order completed'); } }, 3000); - console.log('Order Pending'); - // Return intervalId to enable clearing the interval if needed externally - return intervalId; - } - - function startStatusCheck(auctionId: string) { - const intervalId = fetchOrderPeriodically(auctionId); - setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + setTimeout(() => clearInterval(intervalId), 60000 * 5); // stop after 5 minutes } startStatusCheck(deltaAuction.id); @@ -297,33 +266,39 @@ This way the user doesn't need to make a transaction themselve but only to sign (For **Crosschain Delta Orders** refer to a separate documentation page [DELTA.md](./docs/DELTA.md#crosschain-delta-orders) ) -After getting **deltaPrice** from **/quote** endpoint, there are additional steps to sign the Order and wait for its execution. +In v2 the Order is **built by the server** from the quoted route — you sign the returned typed data and post it. After getting **deltaPrice**, there are a few steps to sign the Order and wait for its execution. -### 1. Get deltaPrice from /quote +### 1. Get deltaPrice ```ts const amount = '1000000000000'; // wei const Token1 = '0x1234...' const Token2 = '0xabcde...' +// ... from the quote endpoint (mode: 'delta' or 'all') const quote = await simpleSDK.quote.getQuote({ - srcToken: Token1, // Native token (ETH) is only supported in mode: 'market' + srcToken: Token1, destToken: Token2, amount, userAddress: account, srcDecimals: 18, destDecimals: 18, - mode: 'delta' // or mode: 'all' + mode: 'delta', + side: 'SELL', // partner: "..." // if available -}) - -// if used mode: 'all' -if ('delta' in quote) { - const deltaPrice = quote.delta; -} - -// if used mode: 'delta' +}); const deltaPrice = quote.delta; + +// ... or straight from the Delta price endpoint +const deltaPriceDirect = await simpleSDK.delta.getDeltaPrice({ + srcToken: Token1, + destToken: Token2, + amount, + srcDecimals: 18, + destDecimals: 18, + userAddress: account, + // destChainId: 42161, // for cross-chain — bridge details land in deltaPrice.route.bridge +}); ``` @@ -345,35 +320,28 @@ const signature = await signer._signTypedData(domain, types, message); See more on accepted Permit variants in [Velora documentation](https://developers.velora.xyz/api/velora-api/velora-delta-api/build-a-delta-order-to-sign#supported-permits) -### 3. Sign and submit a Delta Order +### 3. Build, sign and post a Delta Order ```ts -// calculate acceptable destAmount -const slippagePercent = 0.5; - const destAmountAfterSlippage = ( - +deltaPrice.destAmount * - (1 - slippagePercent / 100) - ).toString(10); - -const signableOrderData = await simpleSDK.delta.buildDeltaOrder({ - deltaPrice, +// build is server-side — pass the quoted route + side and your slippage +const built = await simpleSDK.delta.buildDeltaOrder({ + route: deltaPrice.route, // or any deltaPrice.alternatives[i] + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send the output destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: Token1, - destToken: Token2, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount - // partner: "..." // if available + slippage: 50, // 50 bps = 0.5% + // partner, partnerFeeBps — forwarded to the server }); -const signature = await simpleSDK.delta.signDeltaOrder(signableOrderData); +// one signer for every order family (Order / ExternalOrder / TWAPOrder / TWAPBuyOrder) +const signature = await simpleSDK.delta.signDeltaOrder(built); const deltaAuction = await simpleSDK.delta.postDeltaOrder({ - // partner: "..." // if available - // partiallyFillabel: true, // allow the Order to be partially filled as opposed to fill-or-kill - order: signableOrderData.data, + order: built.toSign.value, signature, + // partner: "...", + // partiallyFillable: true, // allow the Order to be partially filled as opposed to fill-or-kill }); ``` @@ -383,15 +351,13 @@ As an option the `buildDeltaOrder + signDeltaOrder + postDeltaOrder` can be comb ```ts const deltaAuction = await simpleSDK.delta.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send output destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - // partiallyFillabel: true, // allow the Order to be partially filled as opposed to fill-or-kill - srcToken: Token1, - destToken: Token2, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount + // partiallyFillable: true, // allow the Order to be partially filled as opposed to fill-or-kill + slippage: 50, }); ``` @@ -399,69 +365,26 @@ This allows to simplify the flow at the expense of control over the Order signin #### 3.b adding partner fee -A portion of destToken will be collected as a partner fee if `partner` parameter is provided to `buildDeltaOrder` (and `submitDeltaOrder`). The `partnerFee` itself is `deltaPrice.partnerFee` - -To examine the default partnerFee parameters (`{partnerAddress: Address, partnerFee: number, takeSurplus: boolean}`), you can call `getPartnerFee` method. These parameters are then encoded in Order.partnerAndFee field. +A portion of destToken is collected as a partner fee when `partner` (and optionally `partnerFeeBps`) is provided to `buildDeltaOrder` / `submitDeltaOrder`. In v2 these are forwarded to the server, which encodes them into `Order.partnerAndFee`. You can inspect the default partner-fee parameters with `getPartnerFee`: ```ts const partnerFeeResponse = await simpleSDK.delta.getPartnerFee({ partner }); ``` -Alternatively, you can supply your own partnerFee parameters that will be encoded in Order.partnerAndFee field - -```ts -const signableOrderData = await simpleSDK.delta.buildDeltaOrder({ - deltaPrice, - owner: account, - // beneficiary: anotherAccount, // if need to send the output destToken to another account - // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - // partiallyFillabel: true, // allow the Order to be partially filled as opposed to fill-or-kill - srcToken: Token1, - destToken: Token2, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount - partnerAddress: '0x1234...', - partnerFee: 0.12, - takeSurplus: true, -}); -``` - ### 4. Wait for Delta Order execution ```ts -// poll if necessary -function isExecutedDeltaAuction( - auction: Omit, - waitForCrosschain = true // only consider executed when destChain work is done -) { - if (auction.status !== 'EXECUTED') return false; - - // crosschain Order is executed on destChain if bridgeStatus is filled - if (waitForCrosschain && auction.order.bridge.destinationChainId !== 0) { - return auction.bridgeStatus === 'filled'; - } - - return true; -} - -function fetchOrderPeriodically(auctionId: string) { +// poll if necessary — v2 status COMPLETED already accounts for any dest-chain bridge +function startStatusCheck(auctionId: string) { const intervalId = setInterval(async () => { const auction = await simpleSDK.delta.getDeltaOrderById(auctionId); - console.log('checks: ', auction); // Handle or log the fetched auction as needed - - if (isExecutedDeltaAuction(auction)) { - clearInterval(intervalId); // Stop interval if completed + if (auction.status === 'COMPLETED') { + clearInterval(intervalId); // stop interval once completed console.log('Order completed'); } }, 3000); - console.log('Order Pending'); - // Return intervalId to enable clearing the interval if needed externally - return intervalId; -} - -function startStatusCheck(auctionId: string) { - const intervalId = fetchOrderPeriodically(auctionId); - setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + // stop polling after 5 minutes + setTimeout(() => clearInterval(intervalId), 60000 * 5); } startStatusCheck(deltaAuction.id); @@ -475,13 +398,102 @@ For **External Delta Orders** (orders that delegate token handling to an externa ------------ +### Advanced Delta usage + +#### TWAP order + +A TWAP sell splits `totalSrcAmount` into `numSlices` equal slices executed `interval` seconds apart. Price is quoted for a single slice — the server multiplies amounts internally. + +```ts +const perSliceAmount = (BigInt(totalSrcAmount) / BigInt(numSlices)).toString(); + +const slicePrice = await simpleSDK.delta.getDeltaPrice({ + srcToken: Token1, + destToken: Token2, + amount: perSliceAmount, + srcDecimals: 18, + destDecimals: 18, + userAddress: account, +}); + +await simpleSDK.delta.approveTokenForDelta(totalSrcAmount, Token1); + +const twapAuction = await simpleSDK.delta.submitTWAPDeltaOrder({ + onChainOrderType: 'TWAPOrder', // or 'TWAPBuyOrder' + route: slicePrice.route, + owner: account, + totalSrcAmount, + numSlices, + interval: 300, // seconds (min 60) + slippage: 50, +}); +``` + +#### Partial SDK + +For bundle-savvy code, pull only the Delta constructors you need — they tree-shake cleanly. + +```ts +import { + constructPartialSDK, + constructFetchFetcher, + constructGetDeltaPrice, + constructGetDeltaOrders, + constructGetBridgeRoutes, +} from '@velora-dex/sdk'; + +const sdk = constructPartialSDK( + { chainId: 1, fetcher: constructFetchFetcher(fetch) }, + constructGetDeltaPrice, + constructGetDeltaOrders, + constructGetBridgeRoutes, +); + +const price = await sdk.getDeltaPrice({ /* ... */ }); +const orders = await sdk.getDeltaOrders({ userAddress: account, page: 1, limit: 50 }); +``` + +A complete example (standard, external handler, TWAP, and order listing) is in [examples/delta](./src/examples/delta.ts). + +#### Productive Orders (read-only) + +Alongside the four buildable families (`Order`, `ExternalOrder`, `TWAPOrder`, `TWAPBuyOrder`), the SDK surfaces a fifth `onChainOrderType` — **`ProductiveOrder`** — through the read endpoints (`sdk.delta.getDeltaOrderById`, `sdk.delta.getDeltaOrders`, etc.). Productive orders are produced and managed entirely by the server: there are deliberately **no `buildProductiveOrder`, `signProductiveOrder`, or `submitProductiveOrder` helpers**. The shape is wired through `OnChainOrderType` and `OnChainOrderMap` so that consumers iterating over an order list can type-narrow on `onChainOrderType === 'ProductiveOrder'` and read the order safely — productive orders carry no `OrderKind`, so the side is always `SELL`. + +`OnChainOrderType` additionally includes **`'FillableOrder'`**, which maps to the same shape as a Standard `'Order'` (`DeltaAuctionOrder`). It is not a separate buildable family — it's the `onChainOrderType` the server reports for a `partiallyFillable` Standard order, so treat it the same as `'Order'` when narrowing. + +#### Order helpers + +`OrderHelpers` exposes `{ checks, getters }` for auctions returned by `sdk.delta.*` read/post methods (`status: DeltaOrderStatus`, `input`/`output`, flat `transactions`, explicit `side`): + +```ts +import { OrderHelpers } from '@velora-dex/sdk'; + +const { checks, getters } = OrderHelpers; + +if (checks.isProductiveAuction(auction)) { + // read-only, no SDK builder +} else if (checks.isFillableAuction(auction) || checks.isDeltaAuction(auction)) { + // treat FillableOrder the same as a standard Order +} + +if (checks.isCompletedAuction(auction)) { + const { expected, executed } = getters.getAuctionAmounts(auction); + // `executed` — matches the API convention +} + +const unified = getters.getUnifiedDeltaOrderData(auction); +// { srcChainId, destChainId, srcToken, destToken, swapSide, filledPercent, amounts, ... } +``` + +------------ + ### Market Swap handling #### A more detailed overview of the Trade Flow, Market variant. Unlike the Delta Order, a Market swap requires the user themselves to submit a Swap transaction -### 1. Get Market priceRoute from /quote +### 1. Get Market priceRoute from /v2/quote ```ts const amount = '1000000000000'; // wei @@ -489,22 +501,17 @@ const Token1 = '0x1234...' const Token2 = '0xabcde...' const quote = await simpleSDK.quote.getQuote({ - srcToken: Token1, // Native token (ETH) is only supported in mode: 'market' + srcToken: Token1, destToken: Token2, amount, userAddress: account, srcDecimals: 18, destDecimals: 18, - mode: 'market' + mode: 'market', + side: 'SELL', // or 'BUY' // partner: "..." // if available }) -// if used mode: 'all' -if ('market' in quote) { - const priceRoute = quote.market; -} - -// if used mode: 'market' const priceRoute = quote.market; ``` diff --git a/docs/DELTA.md b/docs/DELTA.md index 4b251b13b..24a86a2b8 100644 --- a/docs/DELTA.md +++ b/docs/DELTA.md @@ -1,6 +1,7 @@ **Velora Delta** is an intent-based protocol that enables a Velora user to make gasless swaps where multiple agents compete to execute the trade at the best price possible. This way the user doesn't need to make a transaction themselves but only to sign a Delta Order. -The easiest way to make use of the Delta Order is to use the SDK following these steps: + +In Delta v2 the Order is **built by the server** from the route returned in the price response — you sign the returned typed data and post it. The easiest way to make use of the Delta Order is to use the SDK following these steps: ### 1. Construct an SDK object @@ -32,6 +33,8 @@ const deltaPrice = await deltaSDK.getDeltaPrice({ destDecimals: 6, // partner: "..." // if available }); + +// deltaPrice.route is the recommended route; deltaPrice.alternatives holds the rest ``` @@ -56,68 +59,42 @@ See more on accepted Permit variants in [Velora documentation](https://developer ### 4. Sign and submit a Delta Order -```ts -// calculate acceptable destAmount -const slippagePercent = 0.5; - const destAmountAfterSlippage = ( - +deltaPrice.destAmount * - (1 - slippagePercent / 100) - ).toString(10); +Order building is server-side: pass the quoted `route` + `side` and your acceptable `slippage` — the server computes the amounts. `submitDeltaOrder` bundles build → sign → post. +```ts const deltaAuction = await deltaSDK.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or any deltaPrice.alternatives[i] + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount + slippage: 50, // 50 bps = 0.5% + // partner, partnerFeeBps — forwarded to the server }); ``` +For full control over signing, use `buildDeltaOrder` → `signDeltaOrder` → `postDeltaOrder` separately (see the main [README](../README.md)). + ### 5. Wait for Delta Order execution ```ts -// poll if necessary -function isExecutedDeltaAuction( - auction: Omit, - waitForCrosschain = true // only consider executed when destChain work is done -) { - if (auction.status !== 'EXECUTED') return false; - - // crosschain Order is executed on destChain if bridgeStatus is filled - if (waitForCrosschain && auction.order.bridge.destinationChainId !== 0) { - return auction.bridgeStatus === 'filled'; - } - - return true; -} - -function fetchOrderPeriodically(auctionId: string) { +// poll if necessary — v2 status COMPLETED already accounts for any dest-chain bridge +function startStatusCheck(auctionId: string) { const intervalId = setInterval(async () => { - const auction = await simpleSDK.delta.getDeltaOrderById(auctionId); - console.log('checks: ', auction); // Handle or log the fetched auction as needed - - if (isExecutedDeltaAuction(auction)) { - clearInterval(intervalId); // Stop interval if completed + const auction = await deltaSDK.getDeltaOrderById(auctionId); + if (auction.status === 'COMPLETED') { + clearInterval(intervalId); // stop interval once completed console.log('Order completed'); } }, 3000); - console.log('Order Pending'); - // Return intervalId to enable clearing the interval if needed externally - return intervalId; -} - -function startStatusCheck(auctionId: string) { - const intervalId = fetchOrderPeriodically(auctionId); - setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + // stop polling after 5 minutes + setTimeout(() => clearInterval(intervalId), 60000 * 5); } startStatusCheck(deltaAuction.id); ``` -#### A more detailed example of Delta Order usage can be found in [examples/delta](./src/examples/delta.ts) +#### A more detailed example of Delta Order usage can be found in [examples/delta](../src/examples/delta.ts) @@ -147,12 +124,15 @@ const deltaSDK = constructSimpleSDK( ### 2. Check which tokens are available on the destination chain. -A limited list of tokens are available in Across, the service facilitating crosschain bridging +A limited list of tokens are available in Across, the service facilitating crosschain bridging. ```ts -const bridgeInfo = await deltaSDK.getBridgeInfo(); +const bridgeRoutes = await deltaSDK.getBridgeRoutes(); -const tokensAvailableForBridging = bridgeInfo[SRC_CHAIN_ID]?.[DEST_CHAIN_ID] +const tokensAvailableForBridging = bridgeRoutes.find( + (route) => + route.srcChainId === SRC_CHAIN_ID && route.destChainId === DEST_CHAIN_ID +)?.tokens; ``` @@ -174,6 +154,8 @@ const deltaPrice = await deltaSDK.getDeltaPrice({ destDecimals: 6, // partner: "..." // if available }); + +// the returned deltaPrice.route already encodes the bridge step for the crosschain swap ``` @@ -198,71 +180,35 @@ See more on accepted Permit variants in [Velora documentation](https://developer ### 5. Sign and submit a Delta Order -```ts -// calculate acceptable destAmount -const slippagePercent = 0.5; -const destAmountAfterSlippage = ( - +deltaPrice.destAmount * - (1 - slippagePercent / 100) -).toString(10); +The crosschain `route` (from a `getDeltaPrice` call with `destChainId`) already carries the bridge details, so submitting is the same as a same-chain order — the server builds the cross-chain Order from the route. +```ts const deltaAuction = await deltaSDK.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // crosschain route, includes the bridge step + side: deltaPrice.side, owner: account, + // beneficiary: anotherAccount, // if need to send destToken to another account on destChain // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN_ON_DEST_CHAIN, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount - destChainId: DEST_CHAIN_ID, // required to construct a Crosschain Order - beneficiary: anotherAccount, // if need to send destToken to another account on destChain - beneficiaryType: 'EOA', // whether the beneficiary on destChain is a smart contract - // bridge, // user-constructed Bridge object for Crosschain Orders + slippage: 50, // 50 bps = 0.5% }); ``` -To construct a Crosschain Delta Order it is required to either: -* provide both `beneficiary` address and `beneficiaryType` value, so that the `Order.bridge` can be constructed automatically by the SDK. -* construct Bridge object. Refer to [documentation](https://developers.velora.xyz/api/velora-api/velora-delta-api/build-a-delta-order-to-sign#sign-an-order-cross-chain) for how to do that. - -This is necessary because Across, the service facilitating crosschain bridging, has [special logic when it comes to transferring ETH and WETH](https://docs.across.to/introduction/technical-faq#what-is-the-behavior-of-eth-weth-in-transfers). +Across, the service facilitating crosschain bridging, has [special logic when it comes to transferring ETH and WETH](https://docs.across.to/introduction/technical-faq#what-is-the-behavior-of-eth-weth-in-transfers). Refer to the [Velora documentation](https://developers.velora.xyz/api/velora-api/velora-delta-api/build-a-delta-order-to-sign#sign-an-order-cross-chain) for more on cross-chain orders. -### 5. Wait for Delta Order execution +### 6. Wait for Delta Order execution ```ts -// poll if necessary -function isExecutedDeltaAuction( - auction: Omit, - waitForCrosschain = true // only consider executed when destChain work is done -) { - if (auction.status !== 'EXECUTED') return false; - - // crosschain Order is executed on destChain if bridgeStatus is filled - if (waitForCrosschain && auction.order.bridge.destinationChainId !== 0) { - return auction.bridgeStatus === 'filled'; - } - - return true; -} - -function fetchOrderPeriodically(auctionId: string) { +// poll if necessary — v2 status COMPLETED already accounts for the dest-chain bridge +function startStatusCheck(auctionId: string) { const intervalId = setInterval(async () => { - const auction = await simpleSDK.delta.getDeltaOrderById(auctionId); - console.log('checks: ', auction); // Handle or log the fetched auction as needed - - if (isExecutedDeltaAuction(auction)) { - clearInterval(intervalId); // Stop interval if completed + const auction = await deltaSDK.getDeltaOrderById(auctionId); + if (auction.status === 'COMPLETED') { + clearInterval(intervalId); // stop interval once completed console.log('Order completed'); } }, 3000); - console.log('Order Pending'); - // Return intervalId to enable clearing the interval if needed externally - return intervalId; -} - -function startStatusCheck(auctionId: string) { - const intervalId = fetchOrderPeriodically(auctionId); - setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + // stop polling after 5 minutes + setTimeout(() => clearInterval(intervalId), 60000 * 5); } startStatusCheck(deltaAuction.id); diff --git a/docs/EXTERNAL_ORDERS.md b/docs/EXTERNAL_ORDERS.md index f9cf20cf0..8688a2315 100644 --- a/docs/EXTERNAL_ORDERS.md +++ b/docs/EXTERNAL_ORDERS.md @@ -2,6 +2,8 @@ External orders delegate token handling to an external **handler** contract, enabling complex DeFi strategies that go beyond simple token swaps. The handler manages the actual token logic (e.g. Aave flash loan + collateral/debt swap), while the Delta protocol handles the auction, settlement, and signature verification. +As with all Delta v2 orders, the Order is **built by the server** from the route returned by `getDeltaPrice` — you sign the returned typed data and post it. + ### Handler Contract The handler contract must be deployed by the integrator and implement the `IExternalProtocolHandler` interface: @@ -25,12 +27,13 @@ The `data` field carries protocol-specific parameters (e.g. an Aave operation ty | Feature | Standard Order | External Order | |---|---|---| -| `beneficiary` field | yes | no (output goes to owner) | -| `bridge` field | yes | no | | `handler` field | no | yes (required) | | `data` field | no | yes (required) | +| `bridge` field | yes | no | | Cross-chain support | yes | no | +`beneficiary` is supported by both (defaults to `owner`). + --- @@ -64,7 +67,7 @@ const deltaPrice = await deltaSDK.getDeltaPrice({ userAddress: account, srcDecimals: 6, destDecimals: 18, - side: SwapSide.SELL, + side: 'SELL', }); ``` @@ -83,41 +86,37 @@ await aUSDC.approve(AAVE_HANDLER, amount); #### Using `submitExternalDeltaOrder` (recommended) -The simplest approach — builds, signs, and posts the order in one call: +The simplest approach — builds, signs, and posts the order in one call. Pass the quoted `route` + `side` and your `slippage`; the server computes the amounts. ```ts const deltaAuction = await deltaSDK.submitExternalDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or any deltaPrice.alternatives[i] + side: deltaPrice.side, owner: account, handler: AAVE_HANDLER, // your deployed handler contract data: '0x0000000000000000000000000000000000000000000000000000000000000000', // protocol-specific bytes - srcToken: USDC, - destToken: WETH, - srcAmount: amount, slippage: 50, // 0.5% in bps }); ``` #### Using individual steps -For more control, you can build, sign, and post separately: +For more control, you can build, sign, and post separately. A single `signDeltaOrder` signs every order family. ```ts -const signableOrderData = await deltaSDK.buildExternalDeltaOrder({ - deltaPrice, +const built = await deltaSDK.buildExternalDeltaOrder({ + route: deltaPrice.route, + side: deltaPrice.side, owner: account, handler: AAVE_HANDLER, data: '0x0000000000000000000000000000000000000000000000000000000000000000', - srcToken: USDC, - destToken: WETH, - srcAmount: amount, slippage: 50, // 0.5% in bps }); -const signature = await deltaSDK.signExternalDeltaOrder(signableOrderData); +const signature = await deltaSDK.signDeltaOrder(built); const deltaAuction = await deltaSDK.postExternalDeltaOrder({ - order: signableOrderData.data, + order: built.toSign.value, signature, }); ``` @@ -129,7 +128,7 @@ const intervalId = setInterval(async () => { const auction = await deltaSDK.getDeltaOrderById(deltaAuction.id); console.log('Status:', auction.status); - if (auction.status === 'EXECUTED' || auction.status === 'FAILED') { + if (auction.status === 'COMPLETED' || auction.status === 'FAILED') { clearInterval(intervalId); } }, 3000); @@ -141,9 +140,9 @@ const intervalId = setInterval(async () => { // fetch a specific external order const order = await deltaSDK.getDeltaOrderById(orderId); -// list external orders only -const orders = await deltaSDK.getDeltaOrders({ - owner: account, +// list external orders only (paginated — `data` holds the orders) +const { data: externalOrders } = await deltaSDK.getDeltaOrders({ + userAddress: account, onChainOrderType: 'ExternalOrder', }); ``` @@ -152,34 +151,27 @@ const orders = await deltaSDK.getDeltaOrders({ ## Specifying Amounts -There are two ways to specify amounts: +Amounts are derived server-side from the quoted `route`. Two ways to control them: -**With `slippage` (recommended)** — the SDK computes the slippage-adjusted amount from `deltaPrice` automatically: +**With `slippage` (recommended)** — the server computes the slippage-adjusted amount from the route: ```ts -// SELL: provide srcAmount + slippage → destAmount auto-computed await deltaSDK.buildExternalDeltaOrder({ + route: deltaPrice.route, + side: deltaPrice.side, // 'SELL' or 'BUY' // ... - srcAmount: amount, slippage: 50, // 0.5% in bps }); - -// BUY: provide destAmount + slippage → srcAmount auto-computed -await deltaSDK.buildExternalDeltaOrder({ - // ... - destAmount: amount, - slippage: 50, -}); ``` -**With explicit amounts** — you compute both amounts yourself: +**With an explicit `limitAmount`** — pin the limit yourself; the server uses it as the SELL `destAmount` (or BUY `srcAmount`) and `expectedAmount`: ```ts await deltaSDK.buildExternalDeltaOrder({ + route: deltaPrice.route, + side: deltaPrice.side, // ... - srcAmount: amount, - destAmount: destAmountAfterSlippage, - side: SwapSide.SELL, // or SwapSide.BUY + limitAmount: destAmountLimit, }); ``` @@ -187,31 +179,29 @@ await deltaSDK.buildExternalDeltaOrder({ ## Pre-signing External Orders -For smart contract wallets or other cases where EIP-712 signatures are not available, you can pre-sign an external order on-chain: +For smart contract wallets or other cases where EIP-712 signatures are not available, you can pre-sign an external order on-chain using the `orderHash` returned by the server build: ```ts -const signableOrderData = await deltaSDK.buildExternalDeltaOrder({ - deltaPrice, +const built = await deltaSDK.buildExternalDeltaOrder({ + route: deltaPrice.route, + side: deltaPrice.side, owner: account, handler: AAVE_HANDLER, data: '0x0000000000000000000000000000000000000000000000000000000000000000', - srcToken: USDC, - destToken: WETH, - srcAmount: amount, slippage: 50, }); -// on-chain pre-sign transaction -const tx = await deltaSDK.preSignExternalDeltaOrder(signableOrderData); +// on-chain pre-sign transaction (setPreSignature for the built order hash) +const tx = await deltaSDK.setExternalDeltaOrderPreSignature(built.orderHash); await tx.wait(); // post with empty signature const deltaAuction = await deltaSDK.postExternalDeltaOrder({ - order: signableOrderData.data, + order: built.toSign.value, signature: '0x', }); ``` --- -#### A more detailed example can be found in [examples/externalDelta](../src/examples/externalDelta.ts) +#### A more detailed example can be found in [examples/delta](../src/examples/delta.ts) diff --git a/package.json b/package.json index 2f401b838..a27b85143 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@size-limit/preset-small-lib": "^12.1.0", "@tsconfig/recommended": "^1.0.8", "@types/jest": "^30.0.0", + "@types/node": "^22.8.5", "@wagmi/connectors": "^8.0.13", "@wagmi/core": "^3.4.11", "axios": "^1.13.2", @@ -131,4 +132,4 @@ }, "bugs": "https://github.com/VeloraDEX/paraswap-sdk/issues", "packageManager": "pnpm@11.1.2" -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b285007e..57aefeb46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,9 @@ importers: '@types/jest': specifier: ^30.0.0 version: 30.0.0 + '@types/node': + specifier: ^22.8.5 + version: 22.8.5 '@wagmi/connectors': specifier: ^8.0.13 version: 8.0.13(@wagmi/core@3.4.11(typescript@5.6.3)(viem@2.39.0(typescript@5.6.3)(zod@3.25.76)))(typescript@5.6.3)(viem@2.39.0(typescript@5.6.3)(zod@3.25.76)) diff --git a/src/examples/delta.ts b/src/examples/delta.ts index 208e4d948..3b371cfef 100644 --- a/src/examples/delta.ts +++ b/src/examples/delta.ts @@ -22,7 +22,6 @@ const contractCaller = constructEthersContractCaller( account ); -// type AdaptersFunctions & ApproveTokenFunctions const deltaSDK = constructPartialSDK( { chainId: 1, @@ -55,19 +54,18 @@ async function simpleDeltaFlow() { await tx.wait(); const deltaAuction = await deltaSDK.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or pick from deltaPrice.alternatives + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - slippage: 50, // 50 bps = 0.5% slippage, destAmount auto-computed from deltaPrice + slippage: 50, // 50 bps = 0.5% slippage }); // poll if necessary startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); } + async function manualDeltaFlow() { const amount = '1000000000000'; // wei @@ -87,25 +85,112 @@ async function manualDeltaFlow() { const tx = await deltaSDK.approveTokenForDelta(amount, DAI_TOKEN); await tx.wait(); - const signableOrderData = await deltaSDK.buildDeltaOrder({ - deltaPrice, + // server-side build (returns EIP-712 typed data + orderHash) + const builtOrder = await deltaSDK.buildDeltaOrder({ + route: deltaPrice.route, // or pick from deltaPrice.alternatives + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - slippage: 50, // 50 bps = 0.5% slippage, destAmount auto-computed from deltaPrice + slippage: 50, // 50 bps = 0.5% slippage }); - const signature = await deltaSDK.signDeltaOrder(signableOrderData); + // one signer for every v2 order type (Order / ExternalOrder / TWAPOrder / TWAPBuyOrder) + const signature = await deltaSDK.signDeltaOrder(builtOrder); const deltaAuction = await deltaSDK.postDeltaOrder({ // partner: "..." // if available - order: signableOrderData.data, + order: builtOrder.toSign.value, signature, }); // poll if necessary startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); } + +// External orders forward execution to an integrator-provided handler contract. +// Same build/sign/post shape as standard orders, plus { handler, data }. +// See docs/EXTERNAL_ORDERS.md for handler-specific details (Aave collateral swap, etc.). +async function externalDeltaFlow() { + const amount = ethers.utils.parseUnits('1', 6).toString(); // 1 USDC + + const deltaPrice = await deltaSDK.getDeltaPrice({ + srcToken: USDC_TOKEN, + destToken: DAI_TOKEN, + amount, + userAddress: account, + srcDecimals: 6, + destDecimals: 18, + }); + + const HANDLER = '0xb4a2c36668cf8b19fe08f263e3685a5e16e82912'; // handler contract + const HANDLER_DATA = + '0x0000000000000000000000000000000000000000000000000000000000000000'; // handler-specific encoded bytes + + const builtOrder = await deltaSDK.buildExternalDeltaOrder({ + route: deltaPrice.route, + side: deltaPrice.side, + owner: account, + handler: HANDLER, + data: HANDLER_DATA, + slippage: 50, + }); + + const signature = await deltaSDK.signDeltaOrder(builtOrder); + + const deltaAuction = await deltaSDK.postExternalDeltaOrder({ + order: builtOrder.toSign.value, + signature, + }); + + startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); +} + +// TWAP sell splits a total srcAmount into N equal slices executed `interval` seconds apart. +// The price quote is fetched for a single slice; the server multiplies amounts by numSlices. +async function twapSellDeltaFlow() { + const numSlices = 4; + const totalSrcAmount = ethers.utils.parseUnits('100', 18).toString(); // 100 DAI total + const perSliceAmount = ( + BigInt(totalSrcAmount) / BigInt(numSlices) + ).toString(); + + // quote a single slice — route amounts must match floor(totalSrcAmount / numSlices) + const deltaPrice = await deltaSDK.getDeltaPrice({ + srcToken: DAI_TOKEN, + destToken: USDC_TOKEN, + amount: perSliceAmount, + userAddress: account, + srcDecimals: 18, + destDecimals: 6, + }); + + const tx = await deltaSDK.approveTokenForDelta(totalSrcAmount, DAI_TOKEN); + await tx.wait(); + + const deltaAuction = await deltaSDK.submitTWAPDeltaOrder({ + onChainOrderType: 'TWAPOrder', + route: deltaPrice.route, + owner: account, + totalSrcAmount, + numSlices, + interval: 300, // 5 minutes between slices (min 60) + slippage: 50, + }); + + startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); +} + +// Paginated list of a user's orders (returns a { data, total, page, limit, hasMore } envelope). +async function listUserOrders() { + const page1 = await deltaSDK.getDeltaOrders({ + userAddress: account, + page: 1, + limit: 50, + // status: ['ACTIVE', 'BRIDGING'], + // type: 'MARKET', + }); + + console.log('orders:', page1.data); + console.log('total:', page1.total, 'hasMore:', page1.hasMore); +} diff --git a/src/examples/externalDelta.ts b/src/examples/externalDelta.ts deleted file mode 100644 index 6144d5b4f..000000000 --- a/src/examples/externalDelta.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import axios from 'axios'; -import { ethers, Wallet } from 'ethersV5'; -import { - constructPartialSDK, - constructEthersContractCaller, - constructAxiosFetcher, - constructAllDeltaOrdersHandlers, - SwapSide, -} from '..'; -import { startStatusCheck } from './helpers/delta'; - -const fetcher = constructAxiosFetcher(axios); - -const provider = ethers.getDefaultProvider(1); // Ethereum -const signer = Wallet.createRandom().connect(provider); -const account = signer.address; -const contractCaller = constructEthersContractCaller( - { - ethersProviderOrSigner: signer, - EthersContract: ethers.Contract, - }, - account -); - -const deltaSDK = constructPartialSDK( - { - chainId: 1, // Ethereum - fetcher, - contractCaller, - }, - constructAllDeltaOrdersHandlers -); - -// Ethereum tokens -const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; -const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; - -// Aave external handler on Ethereum (https://etherscan.io/address/0xb4a2c36668cf8b19fe08f263e3685a5e16e82912#code) -// The handler contract is provided by the integrator and must implement IExternalProtocolHandler. -// Different handlers serve different purposes and may have different prerequisites -// (e.g. token approvals, credit delegation, position setup). -const AAVE_HANDLER = '0xb4a2c36668cf8b19fe08f263e3685a5e16e82912'; - -// Aave-specific order types passed as `data` field. -// The `data` encoding is handler-specific — each handler defines its own format. -const AaveOrderTypes = { - COLLATERAL_SWAP: - '0x0000000000000000000000000000000000000000000000000000000000000000', - DEBT_SWAP: - '0x0000000000000000000000000000000000000000000000000000000000000001', - REPAY_WITH_COLLATERAL: - '0x0000000000000000000000000000000000000000000000000000000000000002', -}; - -// Aave Collateral Swap: swap one collateral asset for another (SELL side) -// Prerequisites: user must approve the source aToken to the handler -async function collateralSwapFlow() { - const amount = ethers.utils.parseUnits('1', 6).toString(); // 1 USDC - - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: USDC, - destToken: WETH, - amount, - userAddress: account, - srcDecimals: 6, - destDecimals: 18, - side: SwapSide.SELL, - }); - - const signableOrderData = await deltaSDK.buildExternalDeltaOrder({ - deltaPrice, - owner: account, - handler: AAVE_HANDLER, - data: AaveOrderTypes.COLLATERAL_SWAP, - srcToken: USDC, - destToken: WETH, - srcAmount: amount, - slippage: 50, // 0.5% slippage in bps - }); - - const signature = await deltaSDK.signExternalDeltaOrder(signableOrderData); - - const deltaAuction = await deltaSDK.postExternalDeltaOrder({ - order: signableOrderData.data, - signature, - }); - - startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); -} - -// Aave Debt Swap: swap one debt for another (BUY side) -// Prerequisites: user must grant borrowAllowance on the source variable debt token to the handler -async function debtSwapFlow() { - const debtAmount = ethers.utils.parseUnits('1', 6).toString(); // amount of debt to swap - - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: USDC, - destToken: WETH, - amount: debtAmount, - userAddress: account, - srcDecimals: 6, - destDecimals: 18, - side: SwapSide.BUY, - }); - - const signableOrderData = await deltaSDK.buildExternalDeltaOrder({ - deltaPrice, - owner: account, - handler: AAVE_HANDLER, - data: AaveOrderTypes.DEBT_SWAP, - srcToken: USDC, - destToken: WETH, - destAmount: debtAmount, - slippage: 50, // 0.5% slippage in bps - }); - - const signature = await deltaSDK.signExternalDeltaOrder(signableOrderData); - - const deltaAuction = await deltaSDK.postExternalDeltaOrder({ - order: signableOrderData.data, - signature, - }); - - startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); -} - -// Aave Repay with Collateral: use collateral to repay debt (BUY side) -// Prerequisites: user must approve the source aToken to the handler -async function repayWithCollateralFlow() { - const collateralAmount = ethers.utils.parseUnits('1', 6).toString(); - - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: USDC, - destToken: WETH, - amount: collateralAmount, - userAddress: account, - srcDecimals: 6, - destDecimals: 18, - side: SwapSide.BUY, - }); - - const signableOrderData = await deltaSDK.buildExternalDeltaOrder({ - deltaPrice, - owner: account, - handler: AAVE_HANDLER, - data: AaveOrderTypes.REPAY_WITH_COLLATERAL, - srcToken: USDC, - destToken: WETH, - destAmount: collateralAmount, - slippage: 50, // 0.5% slippage in bps - }); - - const signature = await deltaSDK.signExternalDeltaOrder(signableOrderData); - - const deltaAuction = await deltaSDK.postExternalDeltaOrder({ - order: signableOrderData.data, - signature, - }); - - startStatusCheck(() => deltaSDK.getDeltaOrderById(deltaAuction.id)); -} diff --git a/src/examples/helpers/delta.ts b/src/examples/helpers/delta.ts index 0c1247380..9b3b2b788 100644 --- a/src/examples/helpers/delta.ts +++ b/src/examples/helpers/delta.ts @@ -1,31 +1,19 @@ import { DeltaAuction } from '../..'; -function isExecutedDeltaAuction( - auction: DeltaAuction, - waitForCrosschain = true // only consider executed when destChain work is done -) { - if (auction.status !== 'EXECUTED') return false; - - // crosschain Order is executed on destChain if bridgeStatus is filled - if ( - waitForCrosschain && - auction.onChainOrderType === 'Order' && - auction.order.bridge.destinationChainId !== 0 - ) { - return auction.bridgeStatus === 'filled'; - } - - return true; +// v2 status COMPLETED already accounts for destChain bridge settlement +// (crosschain orders sit in BRIDGING until the destChain leg is done). +function isCompletedDeltaOrder(order: DeltaAuction) { + return order.status === 'COMPLETED'; } type GetDeltaOrderFn = () => Promise; function fetchOrderPeriodically(getDeltaOrder: GetDeltaOrderFn) { const intervalId = setInterval(async () => { - const auction = await getDeltaOrder(); - console.log('checks: ', auction); // Handle or log the fetched auction as needed + const order = await getDeltaOrder(); + console.log('checks: ', order); // Handle or log the fetched order as needed - if (isExecutedDeltaAuction(auction)) { + if (isCompletedDeltaOrder(order)) { clearInterval(intervalId); // Stop interval if completed console.log('Order completed'); } @@ -37,5 +25,10 @@ function fetchOrderPeriodically(getDeltaOrder: GetDeltaOrderFn) { export function startStatusCheck(getDeltaOrder: GetDeltaOrderFn) { const intervalId = fetchOrderPeriodically(getDeltaOrder); - setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + const timeoutId = setTimeout(() => clearInterval(intervalId), 60000 * 5); // Stop after 5 minutes + + return () => { + clearInterval(intervalId); + clearTimeout(timeoutId); + }; } diff --git a/src/examples/limitOrders_all.ts b/src/examples/otcOrders_all.ts similarity index 78% rename from src/examples/limitOrders_all.ts rename to src/examples/otcOrders_all.ts index f037e673d..651bb4c4a 100644 --- a/src/examples/limitOrders_all.ts +++ b/src/examples/otcOrders_all.ts @@ -8,14 +8,15 @@ import { constructPartialSDK, constructEthersContractCaller, constructAxiosFetcher, - // limitOrders methods - constructAllLimitOrdersHandlers, + // OTCOrders methods + constructAllOTCOrdersHandlers, // extra types - LimitOrderFromApi, + OTCOrder, SwappableOrder, } from '..'; const account = '0x1234...'; +const takerAccount = '0x5678...'; const fetcher = constructAxiosFetcher(axios); @@ -30,17 +31,17 @@ const contractCaller = constructEthersContractCaller( account ); -// type BuildLimitOrderFunctions -// & SignLimitOrderFunctions -// & CancelLimitOrderFunctions +// type BuildOTCOrderFunctions +// & SignOTCOrderFunctions +// & CancelOTCOrderFunctions // & ApproveTokenFunctions -const limitOrderSDK = constructPartialSDK( +const OTCOrderSDK = constructPartialSDK( { chainId: 1, fetcher, contractCaller, }, - constructAllLimitOrdersHandlers + constructAllOTCOrdersHandlers ); const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; @@ -54,26 +55,25 @@ const orderInput = { makerAmount: (1e18).toString(10), takerAmount: (8e18).toString(10), maker: account, + taker: takerAccount, }; async function run() { - // approve token for the limit order + // approve token for the OTC order const tx1: ethers.ContractTransaction = - await limitOrderSDK.approveMakerTokenForLimitOrder( + await OTCOrderSDK.approveMakerTokenForOTCOrder( orderInput.makerAmount, orderInput.makerAsset ); // builds + signs + posts order to API - // new limit order returned from API - const newLimitOrder: LimitOrderFromApi = await limitOrderSDK.submitLimitOrder( - orderInput - ); + // new OTC order returned from API + const newOTCOrder: OTCOrder = await OTCOrderSDK.submitOTCOrder(orderInput); // to act as order taker const anotherAccount = '0x5678...'; - const limitOrdersSDKForTaker = constructPartialSDK( + const OTCOrdersSDKForTaker = constructPartialSDK( { chainId: 1, fetcher, @@ -85,22 +85,22 @@ async function run() { anotherAccount ), }, - constructAllLimitOrdersHandlers + constructAllOTCOrdersHandlers ); const tx2: ethers.ContractTransaction = - await limitOrdersSDKForTaker.approveTakerTokenForLimitOrder( + await OTCOrdersSDKForTaker.approveTakerTokenForOTCOrder( orderInput.takerAmount, orderInput.takerAsset ); const executingOrder: SwappableOrder = { - ...newLimitOrder, - permitMakerAsset: newLimitOrder.permitMakerAsset || undefined, + ...newOTCOrder, + permitMakerAsset: newOTCOrder.permitMakerAsset || undefined, }; const { gas: payloadGas, ...LOPayloadTxParams } = - await limitOrdersSDKForTaker.buildLimitOrderTx({ + await OTCOrdersSDKForTaker.buildOTCOrderTx({ srcDecimals: 18, destDecimals: 18, userAddress: anotherAccount, // taker diff --git a/src/examples/limitOrders_partial.ts b/src/examples/otcOrders_partial.ts similarity index 67% rename from src/examples/limitOrders_partial.ts rename to src/examples/otcOrders_partial.ts index 126b9943a..a341fc0cc 100644 --- a/src/examples/limitOrders_partial.ts +++ b/src/examples/otcOrders_partial.ts @@ -8,20 +8,21 @@ import { constructPartialSDK, constructEthersContractCaller, constructAxiosFetcher, - // limitOrders methods - constructBuildLimitOrder, - constructCancelLimitOrder, - constructSignLimitOrder, - constructGetLimitOrders, - constructPostLimitOrder, - constructApproveTokenForLimitOrder, + // OTCOrders methods + constructBuildOTCOrder, + constructCancelOTCOrder, + constructSignOTCOrder, + constructGetOTCOrders, + constructPostOTCOrder, + constructApproveTokenForOTCOrder, // extra types SignableOrderData, - LimitOrderToSend, - constructBuildLimitOrderTx, + OTCOrderToPost, + constructBuildOTCOrderTx, } from '..'; const account = '0x1234...'; +const takerAccount = '0x5678...'; const fetcher = constructAxiosFetcher(axios); @@ -36,22 +37,22 @@ const contractCaller = constructEthersContractCaller( account ); -// type BuildLimitOrderFunctions -// & SignLimitOrderFunctions -// & CancelLimitOrderFunctions +// type BuildOTCOrderFunctions +// & SignOTCOrderFunctions +// & CancelOTCOrderFunctions // & ApproveTokenFunctions -const limitOrderSDK = constructPartialSDK( +const OTCOrderSDK = constructPartialSDK( { chainId: 1, fetcher, contractCaller, }, - constructBuildLimitOrder, - constructCancelLimitOrder, - constructSignLimitOrder, - constructPostLimitOrder, - constructGetLimitOrders, - constructApproveTokenForLimitOrder + constructBuildOTCOrder, + constructCancelOTCOrder, + constructSignOTCOrder, + constructPostOTCOrder, + constructGetOTCOrders, + constructApproveTokenForOTCOrder ); const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; @@ -65,55 +66,56 @@ const orderInput = { makerAmount: (1e18).toString(10), takerAmount: (8e18).toString(10), maker: account, + taker: takerAccount, }; async function run() { /// cancelling current orders - const { orders: currentOrders } = await limitOrderSDK.getLimitOrders({ + const { orders: currentOrders } = await OTCOrderSDK.getOTCOrders({ maker: account, - type: 'LIMIT', }); if (currentOrders[0]?.orderHash) { - const tx1: ethers.ContractTransaction = - await limitOrderSDK.cancelLimitOrder(currentOrders[0].orderHash); + const tx1: ethers.ContractTransaction = await OTCOrderSDK.cancelOTCOrder( + currentOrders[0].orderHash + ); } const moreOrderHashes = currentOrders .slice(1, 2) .map((order) => order.orderHash); - const tx2: ethers.ContractTransaction = - await limitOrderSDK.cancelLimitOrderBulk(moreOrderHashes); + const tx2: ethers.ContractTransaction = await OTCOrderSDK.cancelOTCOrdersBulk( + moreOrderHashes + ); /// creating a new order const tx3: ethers.ContractTransaction = - await limitOrderSDK.approveMakerTokenForLimitOrder( + await OTCOrderSDK.approveMakerTokenForOTCOrder( orderInput.makerAmount, orderInput.makerAsset ); - const signableOrderData: SignableOrderData = - await limitOrderSDK.buildLimitOrder(orderInput); - - const signature: string = await limitOrderSDK.signLimitOrder( - signableOrderData + const signableOrderData: SignableOrderData = await OTCOrderSDK.buildOTCOrder( + orderInput ); - const orderToPostToApi: LimitOrderToSend = { + const signature: string = await OTCOrderSDK.signOTCOrder(signableOrderData); + + const orderToPostToApi: OTCOrderToPost = { ...signableOrderData.data, signature, }; - const newOrder = await limitOrderSDK.postLimitOrder(orderToPostToApi); + const newOrder = await OTCOrderSDK.postOTCOrder(orderToPostToApi); /// filling an order // to act as order taker const anotherAccount = '0x5678...'; - const limitOrderSDKForTaker = constructPartialSDK( + const OTCOrderSDKForTaker = constructPartialSDK( { chainId: 1, fetcher, @@ -125,18 +127,18 @@ async function run() { anotherAccount ), }, - constructBuildLimitOrderTx, - constructApproveTokenForLimitOrder + constructBuildOTCOrderTx, + constructApproveTokenForOTCOrder ); const tx4: ethers.ContractTransaction = - await limitOrderSDKForTaker.approveTakerTokenForLimitOrder( + await OTCOrderSDKForTaker.approveTakerTokenForOTCOrder( orderInput.takerAmount, orderInput.takerAsset ); const { gas: payloadGas, ...LOPayloadTxParams } = - await limitOrderSDKForTaker.buildLimitOrderTx({ + await OTCOrderSDKForTaker.buildOTCOrderTx({ srcDecimals: 18, destDecimals: 18, userAddress: anotherAccount, // taker diff --git a/src/examples/limitOrders_postOrder.ts b/src/examples/otcOrders_postOrder.ts similarity index 63% rename from src/examples/limitOrders_postOrder.ts rename to src/examples/otcOrders_postOrder.ts index 4373a395b..f7615080a 100644 --- a/src/examples/limitOrders_postOrder.ts +++ b/src/examples/otcOrders_postOrder.ts @@ -7,16 +7,17 @@ import { constructPartialSDK, constructEthersContractCaller, constructAxiosFetcher, - // limitOrders methods - constructBuildLimitOrder, - constructSignLimitOrder, - constructPostLimitOrder, + // OTCOrders methods + constructBuildOTCOrder, + constructSignOTCOrder, + constructPostOTCOrder, // extra types SignableOrderData, - LimitOrderToSend, + OTCOrderToPost, } from '..'; const wallet = ethers.Wallet.createRandom(); +const takerAccount = '0x5678...'; const fetcher = constructAxiosFetcher(axios); @@ -29,19 +30,19 @@ const contractCaller = constructEthersContractCaller( wallet.address ); -// type BuildLimitOrderFunctions -// & SignLimitOrderFunctions -// & PostLimitOrderFunctions +// type BuildOTCOrderFunctions +// & SignOTCOrderFunctions +// & PostOTCOrderFunctions -const limitOrderSDK = constructPartialSDK( +const OTCOrderSDK = constructPartialSDK( { chainId: 1, fetcher, contractCaller, }, - constructBuildLimitOrder, - constructSignLimitOrder, - constructPostLimitOrder + constructBuildOTCOrder, + constructSignOTCOrder, + constructPostOTCOrder ); const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; @@ -55,22 +56,22 @@ const orderInput = { makerAmount: (1e18).toString(10), takerAmount: (8e18).toString(10), maker: wallet.address, + taker: takerAccount, }; async function run() { - const signableOrderData: SignableOrderData = - await limitOrderSDK.buildLimitOrder(orderInput); - - const signature: string = await limitOrderSDK.signLimitOrder( - signableOrderData + const signableOrderData: SignableOrderData = await OTCOrderSDK.buildOTCOrder( + orderInput ); - const orderToPostToApi: LimitOrderToSend = { + const signature: string = await OTCOrderSDK.signOTCOrder(signableOrderData); + + const orderToPostToApi: OTCOrderToPost = { ...signableOrderData.data, signature, }; - const newOrder = await limitOrderSDK.postLimitOrder(orderToPostToApi); + const newOrder = await OTCOrderSDK.postOTCOrder(orderToPostToApi); console.log(newOrder); } diff --git a/src/examples/quote.ts b/src/examples/quote.ts index d2d0a119f..b80409def 100644 --- a/src/examples/quote.ts +++ b/src/examples/quote.ts @@ -10,7 +10,6 @@ import { constructSwapSDK, OptimalRate, DeltaPrice, - isFetcherError, } from '..'; import { startStatusCheck } from './helpers/delta'; @@ -40,74 +39,10 @@ const DAI_TOKEN = '0x6b175474e89094c44da98b954eedeac495271d0f'; const USDC_TOKEN = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; /** - * mode='delta' example + * mode='all' returns Delta pricing when possible, with Market price as a fallback. + * (mode='delta' and mode='market' request a single pricing source.) */ -async function deltaQuote() { - const amount = '1000000000000'; // wei - - const quote = await quoteSDK.getQuote({ - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - amount, - userAddress: account, - srcDecimals: 18, - destDecimals: 6, - mode: 'delta', - side: 'SELL', - // partner: "..." // if available - }); - - try { - const deltaPrice = quote.delta; - await handleDeltaQuote({ amount, deltaPrice }); - } catch (error) { - if (isFetcherError(error)) { - const data = error.response?.data; - console.log(`Delta Quote failed: ${data.errorType} - ${data.details}`); - } - } -} - -/** - * mode='market' example - */ -async function marketQuote() { - const amount = '1000000000000'; // wei - - const quote = await quoteSDK.getQuote({ - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - amount, - userAddress: account, - srcDecimals: 18, - destDecimals: 6, - mode: 'market', - side: 'SELL', - // partner: "..." // if available - }); - - const TokenTransferProxy = await quoteSDK.getSpender(); - - // or sign a Permit1 or Permit2 TransferFrom for TokenTransferProxy - const approveTxHash = quoteSDK.approveToken(amount, DAI_TOKEN); - - const txParams = await quoteSDK.buildTx({ - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - slippage: 250, // 2.5% - priceRoute: quote.market, - userAddress: account, - // partner: '...' // if available - }); - - const swapTx = await handleMarketQuote({ amount, priceRoute: quote.market }); -} - -/** - * mode='all' example - */ -async function allQuote() { +async function quoteExample() { const amount = '1000000000000'; // wei const quote = await quoteSDK.getQuote({ @@ -123,16 +58,14 @@ async function allQuote() { }); if ('delta' in quote) { - const deltaPrice = quote.delta; - await handleDeltaQuote({ amount, deltaPrice }); + // Delta path — quote.delta is the v2 DeltaPrice (route-based) + await handleDeltaQuote({ amount, deltaPrice: quote.delta }); } else { console.log( `Delta Quote failed: ${quote.fallbackReason.errorType} - ${quote.fallbackReason.details}` ); - const swapTx = await handleMarketQuote({ - amount, - priceRoute: quote.market, - }); + // settle against the current market price instead + await handleMarketQuote({ amount, priceRoute: quote.market }); } } @@ -151,23 +84,14 @@ async function handleDeltaQuote({ // or sign a Permit1 or Permit2 TransferFrom for DeltaContract await quoteSDK.approveTokenForDelta(amount, DAI_TOKEN); - const slippagePercent = 0.5; - const destAmountAfterSlippage = BigInt( - // get rid of exponential notation - - +(+deltaPrice.destAmount * (1 - slippagePercent / 100)).toFixed(0) - // get rid of decimals - ).toString(10); - + // v2 order building is server-side: pass the quoted route/side, no deltaPrice const deltaAuction = await quoteSDK.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or pick from deltaPrice.alternatives + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount + slippage: 50, // 50 bps = 0.5% slippage }); // poll if necessary diff --git a/src/examples/simple.ts b/src/examples/simple.ts index 3cefbd701..b23aa4316 100644 --- a/src/examples/simple.ts +++ b/src/examples/simple.ts @@ -1,12 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import axios from 'axios'; import { ethers, Wallet } from 'ethersV5'; -import { - constructSimpleSDK, - ContractMethod, - SwapSide, - SimpleSDKProviderOptions, -} from '..'; +import { constructSimpleSDK, SwapSide, SimpleSDKProviderOptions } from '..'; const provider = ethers.getDefaultProvider(1); const signer = Wallet.createRandom().connect(provider); diff --git a/src/examples/simpleQuote.ts b/src/examples/simpleQuote.ts index 322b1ab44..b74934884 100644 --- a/src/examples/simpleQuote.ts +++ b/src/examples/simpleQuote.ts @@ -39,6 +39,7 @@ async function allQuote() { }); if ('delta' in quote) { + // Delta path — quote.delta is the v2 DeltaPrice (route-based) const deltaPrice = quote.delta; const DeltaContract = await simpleSDK.delta.getDeltaContract(); @@ -49,23 +50,14 @@ async function allQuote() { DAI_TOKEN ); - const slippagePercent = 0.5; - const destAmountAfterSlippage = BigInt( - // get rid of exponential notation - - +(+deltaPrice.destAmount * (1 - slippagePercent / 100)).toFixed(0) - // get rid of decimals - ).toString(10); - + // v2 order building is server-side: pass the quoted route/side, no deltaPrice const deltaAuction = await simpleSDK.delta.submitDeltaOrder({ - deltaPrice, + route: deltaPrice.route, // or pick from deltaPrice.alternatives + side: deltaPrice.side, owner: account, // beneficiary: anotherAccount, // if need to send destToken to another account // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: DAI_TOKEN, - destToken: USDC_TOKEN, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount + slippage: 50, // 50 bps = 0.5% slippage }); // poll if necessary diff --git a/src/examples/viem.ts b/src/examples/viem.ts index aec012889..c54e8ff49 100644 --- a/src/examples/viem.ts +++ b/src/examples/viem.ts @@ -10,8 +10,8 @@ import { constructAxiosFetcher, constructPartialSDK, constructSimpleSDK, - constructSubmitLimitOrder, - type BuildLimitOrderInput, + constructSubmitOTCOrder, + type BuildOTCOrderInput, } from '../'; import { assert } from 'ts-essentials'; import { txParamsToViemTxParams } from '../helpers/providers/viem'; @@ -29,8 +29,10 @@ const walletClient = createWalletClient({ transport: custom(window.ethereum!), }); -// example of a minimal SDK for submitting Limit Orders only -async function limitOrderSDKExample() { +const takerAccount = '0x1234...'; + +// example of a minimal SDK for submitting OTC Orders only +async function OTCOrderSDKExample() { const [account] = await walletClient.getAddresses(); assert(account, 'account is necessary for Order signing'); @@ -39,31 +41,31 @@ async function limitOrderSDKExample() { account // pass account to enable write methods (tx signing, signTypedData) ); const fetcher = constructAxiosFetcher(axios); - // SDK with `submitLimitOrder` and `submitP2POrder` methods only + // SDK with `submitOTCOrder` methods only const LOrderSDK = constructPartialSDK( { contractCaller, fetcher, chainId: 1, // same chain as for walletClient }, - constructSubmitLimitOrder + constructSubmitOTCOrder ); /* - // alternatively, SDK with all Order methods: `submitLimitOrder`, `cancelLimitOrder`, `fillLimitOrder`, `getLimitOrders`, etc. methods + // alternatively, SDK with all Order methods: `submitOTCOrder`, `cancelOTCOrder`, `fillOTCOrder`, `getOTCOrders`, etc. methods const LOrderSDK = constructPartialSDK( { contractCaller, fetcher, chainId: 1, // same chain as for walletClient }, - constructAllLimitOrdersHandlers + constructAllOTCOrdersHandlers ); */ const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; const HEX = '0x2b591e99afe9f32eaa6214f7b7629768c40eeb39'; - const orderInput: BuildLimitOrderInput = { + const orderInput = { nonce: 1, expiry: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7, // week from now, in sec makerAsset: DAI, @@ -71,10 +73,11 @@ async function limitOrderSDKExample() { makerAmount: (1e18).toString(10), takerAmount: (8e18).toString(10), maker: account, - }; + taker: takerAccount, + } as const satisfies BuildOTCOrderInput; // submitted Order if successful - const orderFromAPI = LOrderSDK.submitLimitOrder(orderInput); + const orderFromAPI = LOrderSDK.submitOTCOrder(orderInput); } async function simpleSDKExample() { diff --git a/src/index.ts b/src/index.ts index 9a000901d..ec3b5bae2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,80 +27,44 @@ import { constructGetTokens, GetTokensFunctions } from './methods/swap/token'; import { BuildTxFunctions, constructBuildTx } from './methods/swap/transaction'; import { - BuildLimitOrderFunctions, - BuildLimitOrderInput, + BuildOTCOrderFunctions, + BuildOTCOrderInput, BuildOrderDataInput, - constructBuildLimitOrder, -} from './methods/limitOrders/buildOrder'; + constructBuildOTCOrder, +} from './methods/otcOrders/buildOrder'; import { - SignLimitOrderFunctions, - constructSignLimitOrder, -} from './methods/limitOrders/signOrder'; + SignOTCOrderFunctions, + constructSignOTCOrder, +} from './methods/otcOrders/signOrder'; import { - CancelLimitOrderFunctions, - constructCancelLimitOrder, -} from './methods/limitOrders/cancelOrder'; + CancelOTCOrderFunctions, + constructCancelOTCOrder, +} from './methods/otcOrders/cancelOrder'; import { - FillOrderDirectlyFunctions, - constructFillOrderDirectly, -} from './methods/limitOrders/fillOrderDirectly'; + FillOTCOrderFunctions, + constructFillOTCOrder, +} from './methods/otcOrders/fillOrderDirectly'; import { - GetLimitOrdersFunctions, - constructGetLimitOrders, - LimitOrdersUserParams, -} from './methods/limitOrders/getOrders'; + GetOTCOrdersFunctions, + constructGetOTCOrders, + OTCOrdersUserParams, +} from './methods/otcOrders/getOrders'; import { - PostLimitOrderFunctions, - constructPostLimitOrder, -} from './methods/limitOrders/postOrder'; + PostOTCOrderFunctions, + constructPostOTCOrder, +} from './methods/otcOrders/postOrder'; import { - ApproveTokenForLimitOrderFunctions, - constructApproveTokenForLimitOrder, -} from './methods/limitOrders/approveForOrder'; + ApproveTokenForOTCOrderFunctions, + constructApproveTokenForOTCOrder, +} from './methods/otcOrders/approveForOrder'; import { - GetLimitOrdersContractFunctions, - constructGetLimitOrdersContract, -} from './methods/limitOrders/getOrdersContract'; + GetOTCOrdersContractFunctions, + constructGetOTCOrdersContract, +} from './methods/otcOrders/getOrdersContract'; import { - BuildLimitOrdersTxFunctions, - constructBuildLimitOrderTx, -} from './methods/limitOrders/transaction'; - -import { - BuildNFTOrderFunctions, - BuildNFTOrderInput, - BuildNFTOrderDataInput, - constructBuildNFTOrder, -} from './methods/nftOrders/buildOrder'; -import { - SignNFTOrderFunctions, - constructSignNFTOrder, -} from './methods/nftOrders/signOrder'; -import { - CancelNFTOrderFunctions, - constructCancelNFTOrder, -} from './methods/nftOrders/cancelOrder'; -import { - GetNFTOrdersFunctions, - constructGetNFTOrders, - NFTOrdersUserParams, -} from './methods/nftOrders/getOrders'; -import { - PostNFTOrderFunctions, - constructPostNFTOrder, -} from './methods/nftOrders/postOrder'; -import { - ApproveTokenForNFTOrderFunctions, - constructApproveTokenForNFTOrder, -} from './methods/nftOrders/approveForOrder'; -import { - GetNFTOrdersContractFunctions, - constructGetNFTOrdersContract, -} from './methods/nftOrders/getOrdersContract'; -import { - BuildNFTOrdersTxFunctions, - constructBuildNFTOrderTx, -} from './methods/nftOrders/transaction'; + BuildOTCOrdersTxFunctions, + constructBuildOTCOrderTx, +} from './methods/otcOrders/transaction'; import { constructEthersContractCaller, @@ -135,39 +99,55 @@ import type { OptionalRate, APIVersion, ExtraFetchParams, + PaginatedResponse, } from './types'; +// ── Delta ───────────────────────────────────────────────────────────────── +// Delta is v2 (server-built orders). The previous local-build v1 surface was +// removed; every Delta symbol below refers to the v2 implementation. + +// Shared on-chain order-struct types import type { DeltaAuctionOrder, - DeltaAuction, - DeltaAuctionStatus, - DeltaAuctionTransaction, - BridgeMetadata, - BridgeStatus, Bridge, ExternalDeltaOrder, + ProductiveDeltaOrder, TWAPDeltaOrder, TWAPBuyDeltaOrder, TWAPOnChainOrderType, OnChainOrderType, + DeltaOrderType, SwapSideUnion, DeltaAmountsWithSlippage, DeltaAmountsSellSlippage, DeltaAmountsBuySlippage, DeltaAmountsExplicit, - DeltaAuctionDelta, - DeltaAuctionTWAP, - DeltaAuctionTWAPBuy, - DeltaAuctionExternal, DeltaOrderUnion, - DeltaAuctionUnion, UnifiedDeltaOrderData, } from './methods/delta/helpers/types'; +// v2 auction, price & route types +import type { + BuiltDeltaOrder, + DeltaAuction, + DeltaOrderStatus, + DeltaTokenSide, + DeltaTransaction, + BridgeRefundMetadata, + DeltaPrice, + DeltaPriceToken, + DeltaTokenAmount, + BridgeTag, + DeltaRoute, + DeltaRouteStep, + DeltaRouteBridge, + DeltaRouteBridgeContractParams, + BridgeRoute, +} from './methods/delta/types'; + import { - BuildDeltaOrderDataParams, BuildDeltaOrderFunctions, + BuildDeltaOrderParams, constructBuildDeltaOrder, - SignableDeltaOrderData, } from './methods/delta/buildDeltaOrder'; import { constructPostDeltaOrder, @@ -178,7 +158,7 @@ import { import { constructSignDeltaOrder, SignDeltaOrderFunctions, -} from './methods/delta/signDeltaOrder'; +} from './methods/delta'; import { constructPreSignDeltaOrder, PreSignDeltaOrderFunctions, @@ -190,16 +170,11 @@ import { import { constructGetDeltaPrice, GetDeltaPriceFunctions, - DeltaPrice, - BridgePrice, - AvailableBridge, DeltaPriceParams, } from './methods/delta/getDeltaPrice'; import { constructGetDeltaOrders, GetDeltaOrdersFunctions, - DeltaOrderFilterByStatus, - DeltaOrderFromAPI, } from './methods/delta/getDeltaOrders'; import { ApproveTokenForDeltaFunctions, @@ -210,15 +185,19 @@ import { GetPartnerFeeFunctions, } from './methods/delta/getPartnerFee'; import { - constructGetBridgeInfo, - GetBridgeInfoFunctions, - BridgeInfo, + constructGetBridgeRoutes, + GetBridgeRoutesFunctions, BridgeProtocolResponse, -} from './methods/delta/getBridgeInfo'; +} from './methods/delta/getBridgeRoutes'; import { constructIsTokenSupportedInDelta, IsTokenSupportedInDeltaFunctions, } from './methods/delta/isTokenSupportedInDelta'; +import { + constructGetAgentsList, + GetAgentsListFunctions, + AgentList, +} from './methods/delta/getAgentsList'; import { constructBuildExternalDeltaOrder, @@ -226,10 +205,6 @@ import { BuildExternalDeltaOrderParams, } from './methods/delta/buildExternalDeltaOrder'; import type { SignableExternalOrderData } from './methods/delta/helpers/buildExternalOrderData'; -import { - constructSignExternalDeltaOrder, - SignExternalDeltaOrderFunctions, -} from './methods/delta/signExternalDeltaOrder'; import { constructPostExternalDeltaOrder, PostExternalDeltaOrderFunctions, @@ -242,16 +217,12 @@ import { import { BuildTWAPDeltaOrderParams, - BuildTWAPSellOrderParams, - BuildTWAPBuyOrderParams, + BuildTWAPSellDeltaOrderParams, + BuildTWAPBuyDeltaOrderParams, BuildTWAPDeltaOrderFunctions, constructBuildTWAPDeltaOrder, } from './methods/delta/buildTWAPDeltaOrder'; import type { SignableTWAPOrderData } from './methods/delta/helpers/buildTWAPOrderData'; -import { - constructSignTWAPDeltaOrder, - SignTWAPDeltaOrderFunctions, -} from './methods/delta/signTWAPDeltaOrder'; import { constructPostTWAPDeltaOrder, PostTWAPDeltaOrderFunctions, @@ -273,6 +244,9 @@ import { } from './methods/quote/getQuote'; import { CancelDeltaOrderFunctions, + CancelDeltaOrder, + SignCancelDeltaOrderRequest, + PostCancelDeltaOrderRequest, constructCancelDeltaOrder, } from './methods/delta/cancelDeltaOrder'; import { @@ -286,14 +260,15 @@ import { CancelDeltaOrderData, SignableCancelDeltaOrderData, } from './methods/delta/helpers/buildCancelDeltaOrderData'; +import { SignableDeltaOrderData } from './methods/delta/helpers/buildDeltaOrderData'; export { constructSwapSDK, SwapSDKMethods } from './methods/swap'; export { - constructAllLimitOrdersHandlers, - constructSubmitLimitOrder, - LimitOrderHandlers, -} from './methods/limitOrders'; + constructAllOTCOrdersHandlers, + constructSubmitOTCOrder, + OTCOrderHandlers, +} from './methods/otcOrders'; export { constructAllDeltaOrdersHandlers, @@ -314,23 +289,16 @@ export type { BuildOptionsWithGasPrice, BuildTxInput, BuildSwapTxInput, - BuildLimitOrderTxInput, - BuildNFTOrderTxInput, - BuildSwapAndLimitOrderTxInput, - BuildSwapAndNFTOrderTxInput, + BuildOTCOrderTxInput, + BuildSwapAndOTCOrderTxInput, SwappableOrder, - SwappableNFTOrder, } from './methods/swap/transaction'; export type { Web3UnpromiEvent } from './helpers'; export * from './constants'; export type { SignableOrderData, OrderData, -} from './methods/limitOrders/helpers/buildOrderData'; -export type { - SignableNFTOrderData, - NFTOrderData, -} from './methods/nftOrders/helpers/buildOrderData'; +} from './methods/otcOrders/helpers/buildOrderData'; export type { SignableTypedData } from './methods/common/orders/buildOrderData'; // can import these individually @@ -346,25 +314,16 @@ export { constructGetAdapters, constructGetRate, constructSwapTx, - // limitOrders methods: - constructBuildLimitOrder, - constructSignLimitOrder, - constructCancelLimitOrder, - constructFillOrderDirectly, - constructGetLimitOrders, - constructPostLimitOrder, - constructApproveTokenForLimitOrder, - constructGetLimitOrdersContract, - constructBuildLimitOrderTx, - // nftOrders methods - constructBuildNFTOrder, - constructSignNFTOrder, - constructCancelNFTOrder, - constructGetNFTOrders, - constructPostNFTOrder, - constructApproveTokenForNFTOrder, - constructGetNFTOrdersContract, - constructBuildNFTOrderTx, + // OTCOrders methods: + constructBuildOTCOrder, + constructSignOTCOrder, + constructCancelOTCOrder, + constructFillOTCOrder, + constructGetOTCOrders, + constructPostOTCOrder, + constructApproveTokenForOTCOrder, + constructGetOTCOrdersContract, + constructBuildOTCOrderTx, // Delta methods constructBuildDeltaOrder, constructPostDeltaOrder, @@ -376,21 +335,20 @@ export { constructCancelDeltaOrder, constructDeltaTokenModule, constructApproveTokenForDelta, + constructGetAgentsList, // External Delta methods constructBuildExternalDeltaOrder, - constructSignExternalDeltaOrder, constructPostExternalDeltaOrder, constructPreSignExternalDeltaOrder, // TWAP Delta methods constructBuildTWAPDeltaOrder, - constructSignTWAPDeltaOrder, constructPostTWAPDeltaOrder, constructPreSignTWAPDeltaOrder, // Quote methods constructGetQuote, // different helpers constructGetPartnerFee, - constructGetBridgeInfo, + constructGetBridgeRoutes, constructIsTokenSupportedInDelta, constructEthersContractCaller, // same as constructEthersV5ContractCaller for backwards compatibility constructEthersV5ContractCaller, @@ -426,60 +384,47 @@ export type { GetRateInput, BuildTxFunctions, GetSwapTxFunctions, - // types for limitOrders methods: - BuildLimitOrderFunctions, - SignLimitOrderFunctions, - CancelLimitOrderFunctions, - FillOrderDirectlyFunctions, - GetLimitOrdersContractFunctions, - BuildLimitOrdersTxFunctions, - BuildLimitOrderInput, + // types for OTCOrders methods: + BuildOTCOrderFunctions, + SignOTCOrderFunctions, + CancelOTCOrderFunctions, + FillOTCOrderFunctions, + GetOTCOrdersContractFunctions, + BuildOTCOrdersTxFunctions, + BuildOTCOrderInput, BuildOrderDataInput, - PostLimitOrderFunctions, - ApproveTokenForLimitOrderFunctions, - GetLimitOrdersFunctions, - LimitOrdersUserParams, - // types for nftOrders methods: - SignNFTOrderFunctions, - CancelNFTOrderFunctions, - GetNFTOrdersFunctions, - PostNFTOrderFunctions, - ApproveTokenForNFTOrderFunctions, - GetNFTOrdersContractFunctions, - BuildNFTOrdersTxFunctions, - BuildNFTOrderFunctions, - BuildNFTOrderInput, - BuildNFTOrderDataInput, - NFTOrdersUserParams, - //types for Delta methods + PostOTCOrderFunctions, + ApproveTokenForOTCOrderFunctions, + GetOTCOrdersFunctions, + OTCOrdersUserParams, + // types for Delta methods DeltaPrice, - BridgePrice, DeltaPriceParams, + DeltaPriceToken, + DeltaTokenAmount, + DeltaRoute, + DeltaRouteStep, + DeltaRouteBridge, + DeltaRouteBridgeContractParams, + BridgeTag, + BridgeRoute, + BuiltDeltaOrder, DeltaAuctionOrder, DeltaAuction, - DeltaAuctionDelta, - DeltaAuctionTWAP, - DeltaAuctionTWAPBuy, - DeltaAuctionExternal, + DeltaOrderStatus, + DeltaTokenSide, + DeltaTransaction, + BridgeRefundMetadata, DeltaOrderUnion, - DeltaAuctionUnion, UnifiedDeltaOrderData, - DeltaAuctionStatus, - DeltaAuctionTransaction, - DeltaOrderFilterByStatus, - DeltaOrderFromAPI, CancelDeltaOrderData, SignableCancelDeltaOrderData, + SignableDeltaOrderData, // bridge part of DeltaOrder - BridgeMetadata, - BridgeStatus, Bridge, - BridgeInfo, - AvailableBridge, BridgeProtocolResponse, - BuildDeltaOrderDataParams, BuildDeltaOrderFunctions, - SignableDeltaOrderData, + BuildDeltaOrderParams, DeltaOrderToPost, PostDeltaOrderFunctions, PostDeltaOrderParams, @@ -488,18 +433,27 @@ export type { GetDeltaContractFunctions, GetDeltaPriceFunctions, GetDeltaOrdersFunctions, + GetBridgeRoutesFunctions, + GetAgentsListFunctions, + AgentList, ApproveTokenForDeltaFunctions, CancelDeltaOrderFunctions, + CancelDeltaOrder, + SignCancelDeltaOrderRequest, + PostCancelDeltaOrderRequest, DeltaTokenModuleFunctions, CancelAndWithdrawDeltaOrderParams, DepositNativeAndPreSignParams, DepositNativeAndPreSignDeltaOrderParams, // External Delta types ExternalDeltaOrder, + // Productive Delta types + ProductiveDeltaOrder, TWAPDeltaOrder, TWAPBuyDeltaOrder, TWAPOnChainOrderType, OnChainOrderType, + DeltaOrderType, DeltaAmountsWithSlippage, DeltaAmountsSellSlippage, DeltaAmountsBuySlippage, @@ -507,17 +461,15 @@ export type { SignableExternalOrderData, BuildExternalDeltaOrderParams, BuildExternalDeltaOrderFunctions, - SignExternalDeltaOrderFunctions, PostExternalDeltaOrderFunctions, PostExternalDeltaOrderParams, PreSignExternalDeltaOrderFunctions, // TWAP Delta types BuildTWAPDeltaOrderParams, - BuildTWAPSellOrderParams, - BuildTWAPBuyOrderParams, + BuildTWAPSellDeltaOrderParams, + BuildTWAPBuyDeltaOrderParams, BuildTWAPDeltaOrderFunctions, SignableTWAPOrderData, - SignTWAPDeltaOrderFunctions, PostTWAPDeltaOrderFunctions, PostTWAPDeltaOrderParams, PreSignTWAPDeltaOrderFunctions, @@ -534,7 +486,6 @@ export type { ConstructProviderFetchInput, // other types GetPartnerFeeFunctions, - GetBridgeInfoFunctions, IsTokenSupportedInDeltaFunctions, Token, Address, @@ -548,6 +499,7 @@ export type { APIVersion, SwapSideUnion, ExtraFetchParams, + PaginatedResponse, }; export { SDKConfig, constructPartialSDK } from './sdk/partial'; @@ -559,13 +511,9 @@ export { ProviderOptions as SimpleSDKProviderOptions, } from './sdk/simple'; -// bundled methods for limitOrders -export * from './methods/limitOrders'; -export * from './methods/limitOrders/helpers/types'; -// bundled methods for nftOrders -export * from './methods/nftOrders'; -export * from './methods/nftOrders/helpers/types'; -export { AssetType } from './methods/nftOrders/helpers/misc'; +// bundled methods for OTCOrders +export * from './methods/otcOrders'; +export * from './methods/otcOrders/helpers/types'; // helpers for Delta Orders export { OrderHelpers } from './methods/delta/helpers/orders'; diff --git a/src/methods/common/orders/misc.ts b/src/methods/common/orders/misc.ts index bdae2c134..509036f28 100644 --- a/src/methods/common/orders/misc.ts +++ b/src/methods/common/orders/misc.ts @@ -1,4 +1,4 @@ -import type { LimitOrderFromApi } from '../../limitOrders/helpers/types'; +import type { OTCOrderFromApi } from '../../otcOrders/helpers/types'; import { ZERO_ADDRESS } from './buildOrderData'; import type { OrderType } from './types'; @@ -76,7 +76,7 @@ export function baseFetchUrlGetterFactory( // that can't be filled through AugustusSwapper, // only through AugustusRFQ export function isOrderFillableDirectlyOnRFQOnly( - order: Pick + order: Pick ): boolean { // with 0x taker fillable by anyone if (order.taker === ZERO_ADDRESS) return false; diff --git a/src/methods/common/orders/types.ts b/src/methods/common/orders/types.ts index 147adc0cf..b2a116cb2 100644 --- a/src/methods/common/orders/types.ts +++ b/src/methods/common/orders/types.ts @@ -1,6 +1 @@ -export type OrderTransaction = { - hash: string; - event_type: 'OrderFilled' | 'OrderCancelled'; -}; - export type OrderType = 'LIMIT' | 'P2P'; diff --git a/src/methods/delta/buildDeltaOrder.ts b/src/methods/delta/buildDeltaOrder.ts index 04f954604..6c839e840 100644 --- a/src/methods/delta/buildDeltaOrder.ts +++ b/src/methods/delta/buildDeltaOrder.ts @@ -1,133 +1,86 @@ +import { API_URL } from '../../constants'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import { constructGetDeltaContract } from './getDeltaContract'; -import type { BridgePrice } from './getDeltaPrice'; -import { constructGetPartnerFee } from './getPartnerFee'; -import { - buildDeltaSignableOrderData, - type BuildDeltaOrderDataInput, - type SignableDeltaOrderData, -} from './helpers/buildDeltaOrderData'; -import type { DeltaAmountsWithSlippage } from './helpers/types'; -import { SwapSideToOrderKind } from './helpers/types'; -import { resolvePartnerFee, resolveAmounts } from './helpers/misc'; -import type { MarkOptional } from 'ts-essentials'; -export type { SignableDeltaOrderData } from './helpers/buildDeltaOrderData'; +import type { DeltaAuctionOrder } from './helpers/types'; +import type { BuiltDeltaOrder, DeltaRoute } from './types'; +export type { BuiltDeltaOrder } from './types'; -type BuildDeltaOrderDataParamsBase = { +export type BuildDeltaOrderParams = { /** @description The address of the order owner */ owner: string; - /** @description The address of the order beneficiary */ - beneficiary?: string; // beneficiary==owner if no transferTo - /** @description The address of the src token */ - srcToken: string; // lowercase - /** @description The address of the dest token. For Crosschain Order - destination token on the destination chain */ - destToken: string; // lowercase - /** @description The deadline for the order */ - deadline?: number; // seconds - /** @description The nonce of the order */ - nonce?: number | string; // can be random, can even be Date.now() - /** @description Optional permit signature for the src token https://developers.velora.xyz/api/velora-api/velora-delta-api/build-a-delta-order-to-sign#supported-permits-order#supported-permits */ - permit?: string; //can be "0x" - /** @description Partner string. */ + /** @description The address of the order beneficiary. Defaults to owner. */ + beneficiary?: string; + /** @description The deadline for the order (unix seconds) */ + deadline?: number; + /** @description The nonce of the order. Random if omitted. */ + nonce?: string; + /** @description Optional permit signature for the src token. Defaults to "0x". */ + permit?: string; + /** @description Partner string. Passed to the server to resolve partner fee details. */ partner?: string; - - /** @description Destination Chain ID for Crosschain Orders */ - destChainId?: number; - - /** @description price response received from /delta/prices (getDeltaPrice method) */ - deltaPrice: MarkOptional< - Pick< - BridgePrice, - | 'destAmount' - | 'partner' - | 'partnerFee' - | 'destToken' - | 'srcAmount' - | 'bridge' - >, - 'partner' | 'partnerFee' - >; - - /** @description partner fee in basis points (bps), 50bps=0.5% */ + /** @description Partner fee in basis points (bps), 50bps=0.5% */ partnerFeeBps?: number; - /** @description partner address */ + /** @description Partner address */ partnerAddress?: string; - /** @description take surplus */ + /** @description Take surplus flag */ partnerTakesSurplus?: boolean; - - /** @description A boolean indicating whether the surplus should be capped. True by default */ + /** @description Whether the surplus should be capped. True by default. */ capSurplus?: boolean; - /** @description Metadata for the order, hex string */ metadata?: string; + /** @description Designates the Order as partially fillable instead of fill-or-kill. Default false. */ + partiallyFillable?: boolean; + + /** @description DeltaRoute from getDeltaPrice — either price.route or any price.alternatives[i] */ + route: DeltaRoute; + /** @description Order side. SELL or BUY. */ + side: 'SELL' | 'BUY'; + /** @description Slippage in basis points (bps). 10000 = 100%, 50 = 0.5%. Default 0. */ + slippage?: number; + /** @description If passed, the server will use this as SELL destAmount (as BUY srcAmount) and expectedAmount */ + limitAmount?: string; }; -export type BuildDeltaOrderDataParams = BuildDeltaOrderDataParamsBase & - DeltaAmountsWithSlippage; - type BuildDeltaOrder = ( - buildOrderParams: BuildDeltaOrderDataParams, + buildOrderParams: BuildDeltaOrderParams, requestParams?: RequestParameters -) => Promise; +) => Promise>; export type BuildDeltaOrderFunctions = { - /** @description Build Orders to be posted to Delta API for execution */ + /** @description Build a Delta v2 order from a DeltaRoute via the server endpoint, ready to sign and post. */ buildDeltaOrder: BuildDeltaOrder; }; export const constructBuildDeltaOrder = ( options: ConstructFetchInput ): BuildDeltaOrderFunctions => { - const { chainId } = options; - - // cached internally - const { getDeltaContract } = constructGetDeltaContract(options); - // cached internally for `partner` - const { getPartnerFee } = constructGetPartnerFee(options); - - const buildDeltaOrder: BuildDeltaOrder = async (options, requestParams) => { - const ParaswapDelta = await getDeltaContract(requestParams); - if (!ParaswapDelta) { - throw new Error(`Delta is not available on chain ${chainId}`); - } - - const { partnerAddress, partnerFeeBps, partnerTakesSurplus } = - await resolvePartnerFee(options, getPartnerFee, requestParams); - - const { srcAmount, destAmount, expectedAmount, swapSide } = - resolveAmounts(options); - - const input: BuildDeltaOrderDataInput = { - owner: options.owner, - beneficiary: options.beneficiary, - srcToken: options.srcToken, - // for some cases of WETH->ETH crosschain swaps, the destToken is changed to WETH or ETH, - // this is already reflected in deltaPrice - destToken: options.deltaPrice.destToken, - srcAmount, - destAmount, - expectedAmount, - deadline: options.deadline, - nonce: options.nonce?.toString(10), - permit: options.permit, - kind: SwapSideToOrderKind[swapSide], - metadata: options.metadata, - - chainId, - paraswapDeltaAddress: ParaswapDelta, - partnerAddress, - partnerTakesSurplus, - partnerFeeBps, - - capSurplus: options.capSurplus, - - bridge: options.deltaPrice.bridge, // ZERO_BRIDGE for same-chain Orders - }; - - return buildDeltaSignableOrderData(input); - }; - - return { - buildDeltaOrder, - }; + const { apiURL = API_URL, fetcher } = options; + const buildUrl = `${apiURL}/v2/delta/orders/build` as const; + + const buildDeltaOrder: BuildDeltaOrder = async (params, requestParams) => + fetcher>({ + url: buildUrl, + method: 'POST', + data: { + side: params.side, + route: params.route, + owner: params.owner, + beneficiary: params.beneficiary, + deadline: params.deadline, + nonce: params.nonce, + permit: params.permit, + slippage: params.slippage, + limitAmount: params.limitAmount, + metadata: params.metadata, + partiallyFillable: params.partiallyFillable, + partner: params.partner, + partnerAddress: params.partnerAddress, + partnerFeeBps: params.partnerFeeBps, + partnerTakesSurplus: params.partnerTakesSurplus, + capSurplus: params.capSurplus, + orderType: 'Order', + }, + requestParams, + }); + + return { buildDeltaOrder }; }; diff --git a/src/methods/delta/buildExternalDeltaOrder.ts b/src/methods/delta/buildExternalDeltaOrder.ts index 8fc31b260..3067ad794 100644 --- a/src/methods/delta/buildExternalDeltaOrder.ts +++ b/src/methods/delta/buildExternalDeltaOrder.ts @@ -1,124 +1,95 @@ +import { API_URL } from '../../constants'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import { constructGetDeltaContract } from './getDeltaContract'; -import type { DeltaPrice } from './getDeltaPrice'; -import { constructGetPartnerFee } from './getPartnerFee'; -import { - buildExternalOrderSignableData, - type BuildExternalOrderDataInput, - type SignableExternalOrderData, -} from './helpers/buildExternalOrderData'; -import type { DeltaAmountsWithSlippage } from './helpers/types'; -import { SwapSideToOrderKind } from './helpers/types'; -import type { MarkOptional } from 'ts-essentials'; -import { resolvePartnerFee, resolveAmounts } from './helpers/misc'; -export type { SignableExternalOrderData } from './helpers/buildExternalOrderData'; +import type { ExternalDeltaOrder } from './helpers/types'; +import type { BuiltDeltaOrder, DeltaRoute } from './types'; +export type { BuiltDeltaOrder } from './types'; -type BuildExternalDeltaOrderParamsBase = { +export type BuildExternalDeltaOrderParams = { /** @description The address of the order owner */ owner: string; /** @description The address of the external handler contract */ handler: string; /** @description Protocol-specific encoded bytes for the external handler */ data: string; - /** @description The address of the src token */ - srcToken: string; - /** @description The address of the dest token */ - destToken: string; - /** @description The deadline for the order */ + /** @description The address of the order beneficiary. Defaults to owner. */ + beneficiary?: string; + /** @description The deadline for the order (unix seconds) */ deadline?: number; - /** @description The nonce of the order */ - nonce?: number | string; - /** @description Optional permit signature for the src token */ + /** @description The nonce of the order. Random if omitted. */ + nonce?: string; + /** @description Optional permit signature for the src token. Defaults to "0x". */ permit?: string; - /** @description Partner string */ + /** @description Partner string. Passed to the server to resolve partner fee details. */ partner?: string; - /** @description partner fee in basis points (bps), 50bps=0.5% */ + /** @description Partner fee in basis points (bps), 50bps=0.5% */ partnerFeeBps?: number; - /** @description partner address */ + /** @description Partner address */ partnerAddress?: string; - /** @description take surplus */ + /** @description Take surplus flag */ partnerTakesSurplus?: boolean; - /** @description A boolean indicating whether the surplus should be capped. True by default */ + /** @description Whether the surplus should be capped. True by default. */ capSurplus?: boolean; /** @description Metadata for the order, hex string */ metadata?: string; + /** @description Designates the Order as partially fillable. Default false. */ + partiallyFillable?: boolean; - /** @description price response received from /delta/prices (getDeltaPrice method) */ - deltaPrice: MarkOptional< - Pick< - DeltaPrice, - 'destAmount' | 'partner' | 'partnerFee' | 'destToken' | 'srcAmount' - >, - 'partner' | 'partnerFee' - >; + /** @description DeltaRoute from getDeltaPrice */ + route: DeltaRoute; + /** @description Order side. SELL or BUY. */ + side: 'SELL' | 'BUY'; + /** @description Slippage in basis points (bps). Default 0. */ + slippage?: number; + /** @description If passed, the server will use this as SELL destAmount (as BUY srcAmount) and expectedAmount */ + limitAmount?: string; }; -export type BuildExternalDeltaOrderParams = BuildExternalDeltaOrderParamsBase & - DeltaAmountsWithSlippage; - type BuildExternalDeltaOrder = ( buildOrderParams: BuildExternalDeltaOrderParams, requestParams?: RequestParameters -) => Promise; +) => Promise>; export type BuildExternalDeltaOrderFunctions = { - /** @description Build External Orders to be posted to Delta API for execution */ + /** @description Build a Delta v2 External Order from a DeltaRoute via the server endpoint, ready to sign and post. */ buildExternalDeltaOrder: BuildExternalDeltaOrder; }; export const constructBuildExternalDeltaOrder = ( options: ConstructFetchInput ): BuildExternalDeltaOrderFunctions => { - const { chainId } = options; - - // cached internally - const { getDeltaContract } = constructGetDeltaContract(options); - // cached internally for `partner` - const { getPartnerFee } = constructGetPartnerFee(options); + const { apiURL = API_URL, fetcher } = options; + const buildUrl = `${apiURL}/v2/delta/orders/build` as const; const buildExternalDeltaOrder: BuildExternalDeltaOrder = async ( - options, + params, requestParams - ) => { - const ParaswapDelta = await getDeltaContract(requestParams); - if (!ParaswapDelta) { - throw new Error(`Delta is not available on chain ${chainId}`); - } - - const { partnerAddress, partnerFeeBps, partnerTakesSurplus } = - await resolvePartnerFee(options, getPartnerFee, requestParams); - - const { srcAmount, destAmount, expectedAmount, swapSide } = - resolveAmounts(options); - - const input: BuildExternalOrderDataInput = { - owner: options.owner, - handler: options.handler, - srcToken: options.srcToken, - destToken: options.deltaPrice.destToken, - srcAmount, - destAmount, - expectedAmount, - deadline: options.deadline, - nonce: options.nonce?.toString(10), - permit: options.permit, - kind: SwapSideToOrderKind[swapSide], - metadata: options.metadata, - data: options.data, - - chainId, - paraswapDeltaAddress: ParaswapDelta, - partnerAddress, - partnerTakesSurplus, - partnerFeeBps, - - capSurplus: options.capSurplus, - }; - - return buildExternalOrderSignableData(input); - }; + ) => + fetcher>({ + url: buildUrl, + method: 'POST', + data: { + side: params.side, + route: params.route, + owner: params.owner, + handler: params.handler, + data: params.data, + beneficiary: params.beneficiary, + deadline: params.deadline, + nonce: params.nonce, + permit: params.permit, + slippage: params.slippage, + limitAmount: params.limitAmount, + metadata: params.metadata, + partiallyFillable: params.partiallyFillable, + partner: params.partner, + partnerAddress: params.partnerAddress, + partnerFeeBps: params.partnerFeeBps, + partnerTakesSurplus: params.partnerTakesSurplus, + capSurplus: params.capSurplus, + orderType: 'ExternalOrder', + }, + requestParams, + }); - return { - buildExternalDeltaOrder, - }; + return { buildExternalDeltaOrder }; }; diff --git a/src/methods/delta/buildTWAPDeltaOrder.ts b/src/methods/delta/buildTWAPDeltaOrder.ts index d7ed8b1a9..48b2b9529 100644 --- a/src/methods/delta/buildTWAPDeltaOrder.ts +++ b/src/methods/delta/buildTWAPDeltaOrder.ts @@ -1,187 +1,131 @@ +import { API_URL } from '../../constants'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import { DEFAULT_BRIDGE } from './constants'; -import { constructGetDeltaContract } from './getDeltaContract'; -import type { BridgePrice } from './getDeltaPrice'; -import { constructGetPartnerFee } from './getPartnerFee'; -import { - buildTWAPSignableOrderData, - TWAPOrderCommonInput, - type BuildTWAPOrderDataInput, - type SignableTWAPOrderData, -} from './helpers/buildTWAPOrderData'; -import { applySlippage, resolvePartnerFee } from './helpers/misc'; -import type { MarkOptional } from 'ts-essentials'; -export type { SignableTWAPOrderData } from './helpers/buildTWAPOrderData'; +import type { TWAPBuyDeltaOrder, TWAPDeltaOrder } from './helpers/types'; +import type { BuiltDeltaOrder, DeltaRoute } from './types'; +export type { BuiltDeltaOrder } from './types'; -type BuildTWAPDeltaOrderParamsBase = { +type BuildTWAPDeltaOrderBase = { /** @description The address of the order owner */ owner: string; - /** @description The address of the order beneficiary */ + /** @description The address of the order beneficiary. Defaults to owner. */ beneficiary?: string; - /** @description The address of the src token */ - srcToken: string; - /** @description The address of the dest token. For Crosschain Order - destination token on the destination chain */ - destToken: string; - /** @description The deadline for the order */ + /** @description The deadline for the order (unix seconds) */ deadline?: number; - /** @description The nonce of the order */ - nonce?: number | string; - /** @description Optional permit signature for the src token */ + /** @description The nonce of the order. Random if omitted. */ + nonce?: string; + /** @description Optional permit signature for the src token. Defaults to "0x". */ permit?: string; - /** @description Partner string */ + /** @description Partner string. Passed to the server to resolve partner fee details. */ partner?: string; - /** @description Destination Chain ID for Crosschain Orders */ - destChainId?: number; /** @description Seconds between slice executions (min 60) */ interval: number; /** @description Number of slices (min 2) */ numSlices: number; - /** @description Slippage in basis points (bps). 10000 = 100%, 50 = 0.5% */ + /** @description Slippage in basis points (bps). 10000 = 100%, 50 = 0.5%. Default 0. */ slippage?: number; - - /** @description price response received from /delta/prices (getDeltaPrice method) for a single slice */ - deltaPrice: MarkOptional< - Pick< - BridgePrice, - | 'destAmount' - | 'partner' - | 'partnerFee' - | 'destToken' - | 'srcAmount' - | 'bridge' - >, - 'partner' | 'partnerFee' - >; - - /** @description partner fee in basis points (bps), 50bps=0.5% */ + /** @description DeltaRoute from getDeltaPrice for a single slice */ + route: DeltaRoute; + /** @description Partner fee in basis points (bps) */ partnerFeeBps?: number; - /** @description partner address */ + /** @description Partner address */ partnerAddress?: string; - /** @description take surplus */ + /** @description Take surplus flag */ partnerTakesSurplus?: boolean; - /** @description A boolean indicating whether the surplus should be capped. True by default */ + /** @description Whether the surplus should be capped. True by default. */ capSurplus?: boolean; /** @description Metadata for the order, hex string */ metadata?: string; + /** @description Designates the Order as partially fillable. Default false. */ + partiallyFillable?: boolean; + /** @description If passed, the server will use this as SELL destAmount (as BUY srcAmount) and expectedAmount for each slice */ + limitAmount?: string; }; -export type BuildTWAPSellOrderParams = BuildTWAPDeltaOrderParamsBase & { - /** @description Must be "TWAPOrder" for sell orders */ +export type BuildTWAPSellDeltaOrderParams = BuildTWAPDeltaOrderBase & { onChainOrderType: 'TWAPOrder'; - /** @description Total source token amount across all slices */ + /** @description Total source token amount across all slices. route.origin.input.amount must equal floor(totalSrcAmount / numSlices). */ totalSrcAmount: string; }; -export type BuildTWAPBuyOrderParams = BuildTWAPDeltaOrderParamsBase & { - /** @description Must be "TWAPBuyOrder" for buy orders */ +export type BuildTWAPBuyDeltaOrderParams = BuildTWAPDeltaOrderBase & { onChainOrderType: 'TWAPBuyOrder'; - /** @description Total destination token amount to buy across all slices */ + /** @description Total destination token amount to buy across all slices. route.origin.output.amount must equal floor(totalDestAmount / numSlices). */ totalDestAmount: string; - /** @description Maximum source token amount willing to spend */ + /** @description Maximum source token amount willing to spend across all slices. */ maxSrcAmount: string; }; export type BuildTWAPDeltaOrderParams = - | BuildTWAPSellOrderParams - | BuildTWAPBuyOrderParams; + | BuildTWAPSellDeltaOrderParams + | BuildTWAPBuyDeltaOrderParams; type BuildTWAPDeltaOrder = ( buildOrderParams: BuildTWAPDeltaOrderParams, requestParams?: RequestParameters -) => Promise; +) => Promise>; export type BuildTWAPDeltaOrderFunctions = { - /** @description Build TWAP Orders (sell or buy) to be posted to Delta API for execution */ + /** @description Build a Delta v2 TWAP Order (sell or buy) from a DeltaRoute via the server endpoint, ready to sign and post. */ buildTWAPDeltaOrder: BuildTWAPDeltaOrder; }; export const constructBuildTWAPDeltaOrder = ( options: ConstructFetchInput ): BuildTWAPDeltaOrderFunctions => { - const { chainId } = options; - - const { getDeltaContract } = constructGetDeltaContract(options); - const { getPartnerFee } = constructGetPartnerFee(options); + const { apiURL = API_URL, fetcher } = options; + const buildUrl = `${apiURL}/v2/delta/orders/build` as const; const buildTWAPDeltaOrder: BuildTWAPDeltaOrder = async ( params, requestParams ) => { - const ParaswapDelta = await getDeltaContract(requestParams); - if (!ParaswapDelta) { - throw new Error(`Delta is not available on chain ${chainId}`); - } - - const { partnerAddress, partnerFeeBps, partnerTakesSurplus } = - await resolvePartnerFee(params, getPartnerFee, requestParams); - - const commonInput: TWAPOrderCommonInput = { + const commonBody = { + route: params.route, owner: params.owner, beneficiary: params.beneficiary, - srcToken: params.srcToken, - destToken: params.deltaPrice.destToken, deadline: params.deadline, - nonce: params.nonce?.toString(10), + nonce: params.nonce, permit: params.permit, + slippage: params.slippage, + limitAmount: params.limitAmount, metadata: params.metadata, + partiallyFillable: params.partiallyFillable, + partner: params.partner, + partnerAddress: params.partnerAddress, + partnerFeeBps: params.partnerFeeBps, + partnerTakesSurplus: params.partnerTakesSurplus, + capSurplus: params.capSurplus, interval: params.interval, numSlices: params.numSlices, - bridge: { - ...params.deltaPrice.bridge, - // TWAP child orders get their bridge data at execution time - protocolData: DEFAULT_BRIDGE.protocolData, - }, - - chainId, - paraswapDeltaAddress: ParaswapDelta, - partnerAddress, - partnerTakesSurplus, - partnerFeeBps, - capSurplus: params.capSurplus, }; - let input: BuildTWAPOrderDataInput; - if (params.onChainOrderType === 'TWAPOrder') { - const slippage = params.slippage ?? 0; - const destAmountPerSlice = - slippage > 0 - ? applySlippage({ - amount: params.deltaPrice.destAmount, - slippageBps: slippage, - increase: false, - }) - : params.deltaPrice.destAmount; - - input = { - ...commonInput, - onChainOrderType: 'TWAPOrder', - destAmountPerSlice, - totalSrcAmount: params.totalSrcAmount, - }; - } else { - const slippage = params.slippage ?? 0; - const maxSrcAmount = - slippage > 0 - ? applySlippage({ - amount: params.maxSrcAmount, - slippageBps: slippage, - increase: true, - }) - : params.maxSrcAmount; - - input = { - ...commonInput, - onChainOrderType: 'TWAPBuyOrder', - totalDestAmount: params.totalDestAmount, - maxSrcAmount, - }; + return fetcher>({ + url: buildUrl, + method: 'POST', + data: { + ...commonBody, + side: 'SELL', + orderType: 'TWAPOrder', + totalSrcAmount: params.totalSrcAmount, + }, + requestParams, + }); } - return buildTWAPSignableOrderData(input); + return fetcher>({ + url: buildUrl, + method: 'POST', + data: { + ...commonBody, + side: 'BUY', + orderType: 'TWAPBuyOrder', + totalDestAmount: params.totalDestAmount, + maxSrcAmount: params.maxSrcAmount, + }, + requestParams, + }); }; - return { - buildTWAPDeltaOrder, - }; + return { buildTWAPDeltaOrder }; }; diff --git a/src/methods/delta/cancelDeltaOrder.ts b/src/methods/delta/cancelDeltaOrder.ts index b35c215a6..0bb98bcfc 100644 --- a/src/methods/delta/cancelDeltaOrder.ts +++ b/src/methods/delta/cancelDeltaOrder.ts @@ -1,3 +1,4 @@ +import { API_URL } from '../../constants'; import type { ConstructProviderFetchInput, RequestParameters, @@ -5,7 +6,7 @@ import type { import { constructGetDeltaContract } from './getDeltaContract'; import { buildCancelDeltaOrderSignableData, - CancelDeltaOrderData, + type CancelDeltaOrderData, } from './helpers/buildCancelDeltaOrderData'; type SuccessResponse = { success: true }; @@ -31,10 +32,10 @@ export type CancelDeltaOrder = ( ) => Promise; export type CancelDeltaOrderFunctions = { - signCancelLimitDeltaOrderRequest: SignCancelDeltaOrderRequest; - postCancelLimitDeltaOrderRequest: PostCancelDeltaOrderRequest; - /** @description Cancel a Limit Delta order */ - cancelLimitDeltaOrders: CancelDeltaOrder; + signCancelDeltaOrderRequest: SignCancelDeltaOrderRequest; + postCancelDeltaOrderRequest: PostCancelDeltaOrderRequest; + /** @description Cancel one or more Delta orders via the v2 endpoint */ + cancelDeltaOrders: CancelDeltaOrder; }; export const constructCancelDeltaOrder = ( @@ -43,10 +44,11 @@ export const constructCancelDeltaOrder = ( 'contractCaller' | 'fetcher' | 'apiURL' | 'chainId' > ): CancelDeltaOrderFunctions => { - // cached internally + const apiURL = options.apiURL ?? API_URL; + const { getDeltaContract } = constructGetDeltaContract(options); - const signCancelLimitDeltaOrderRequest: SignCancelDeltaOrderRequest = async ( + const signCancelDeltaOrderRequest: SignCancelDeltaOrderRequest = async ( params, requestParams ) => { @@ -60,50 +62,39 @@ export const constructCancelDeltaOrder = ( paraswapDeltaAddress: ParaswapDelta, chainId: options.chainId, }); - const signature = await options.contractCaller.signTypedDataCall(typedData); - return signature; + return options.contractCaller.signTypedDataCall(typedData); }; - const postCancelLimitDeltaOrderRequest: PostCancelDeltaOrderRequest = async ( + const postCancelDeltaOrderRequest: PostCancelDeltaOrderRequest = async ( params, requestParams ) => { - const cancelUrl = `${options.apiURL}/delta/orders/cancel` as const; + const cancelUrl = `${apiURL}/v2/delta/orders/cancel` as const; - const res = await options.fetcher({ + return options.fetcher({ url: cancelUrl, method: 'POST', data: params, requestParams, }); - - return res; }; - const cancelLimitDeltaOrders: CancelDeltaOrder = async ( + const cancelDeltaOrders: CancelDeltaOrder = async ( { orderIds }, requestParams ) => { - const signature = await signCancelLimitDeltaOrderRequest( + const signature = await signCancelDeltaOrderRequest( { orderIds }, requestParams ); - const res = await postCancelLimitDeltaOrderRequest( - { - orderIds, - signature, - }, - requestParams - ); - - return res; + return postCancelDeltaOrderRequest({ orderIds, signature }, requestParams); }; return { - signCancelLimitDeltaOrderRequest, - postCancelLimitDeltaOrderRequest, - cancelLimitDeltaOrders, + signCancelDeltaOrderRequest, + postCancelDeltaOrderRequest, + cancelDeltaOrders, }; }; diff --git a/src/methods/delta/constants.ts b/src/methods/delta/constants.ts deleted file mode 100644 index bc22e0e0e..000000000 --- a/src/methods/delta/constants.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ZERO_ADDRESS } from '../common/orders/buildOrderData'; -import { Bridge } from './helpers/types'; - -// for same-chain Orders, all 0 params -export const DEFAULT_BRIDGE = { - protocolSelector: '0x00000000', // 4 bytes - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', -} as const satisfies Bridge; diff --git a/src/methods/delta/getAgentsList.ts b/src/methods/delta/getAgentsList.ts new file mode 100644 index 000000000..76b538da3 --- /dev/null +++ b/src/methods/delta/getAgentsList.ts @@ -0,0 +1,32 @@ +import { API_URL } from '../../constants'; +import type { ConstructFetchInput, RequestParameters } from '../../types'; + +export type AgentList = string[]; + +type AgentsListResponse = AgentList; + +type GetAgentsList = (requestParams?: RequestParameters) => Promise; + +export type GetAgentsListFunctions = { + /** @description List agents available on the current chain. */ + getAgentsList: GetAgentsList; +}; + +export const constructGetAgentsList = ({ + apiURL = API_URL, + chainId, + fetcher, +}: ConstructFetchInput): GetAgentsListFunctions => { + const baseUrl = `${apiURL}/v2/delta/agents/list/${chainId}` as const; + + const getAgentsList: GetAgentsList = async (requestParams) => { + const data = await fetcher({ + url: baseUrl, + method: 'GET', + requestParams, + }); + return data; + }; + + return { getAgentsList }; +}; diff --git a/src/methods/delta/getBridgeInfo.ts b/src/methods/delta/getBridgeRoutes.ts similarity index 50% rename from src/methods/delta/getBridgeInfo.ts rename to src/methods/delta/getBridgeRoutes.ts index b3d33981f..b655d8f0d 100644 --- a/src/methods/delta/getBridgeInfo.ts +++ b/src/methods/delta/getBridgeRoutes.ts @@ -1,80 +1,78 @@ import { API_URL } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; -import type { - Address, - ConstructFetchInput, - RequestParameters, -} from '../../types'; - -// srcChainId -> destChainId -> outputToken[] -// output Tokens that are supported for a srcChainId -> destChainId pair -export type BridgeInfo = Record>; -type BridgeInfoResponse = { supportedTokens: BridgeInfo }; - -type GetBridgeInfoParams = { +import type { ConstructFetchInput, RequestParameters } from '../../types'; +import type { BridgeRoute } from './types'; + +export type BridgeProtocolResponse = { + protocol: string; + displayName: string; + icon: string; +}; + +type GetBridgeRoutesParams = { /** @description Include tokens that can be swapped on destChain after bridge. Default is true. */ allowBridgeAndSwap?: boolean; /** @description Include only the specified bridges. Default is all bridges. */ bridges?: string[]; }; -type BridgeInfoQuery = { +type BridgeRoutesQuery = { allowBridgeAndSwap?: boolean; bridges?: string; }; -type GetBridgeInfo = ( - params?: GetBridgeInfoParams, +type BridgeRoutesResponse = { routes: BridgeRoute[] }; + +type GetBridgeRoutes = ( + params?: GetBridgeRoutesParams, requestParams?: RequestParameters -) => Promise; +) => Promise; -export type BridgeProtocolResponse = { - protocol: string; - displayName: string; - icon: string; -}; +type GetBridgeProtocols = ( + requestParams?: RequestParameters +) => Promise; type BridgeProtocolsResponse = { bridgeProtocols: BridgeProtocolResponse[]; }; -type GetBridgeProtocols = ( - requestParams?: RequestParameters -) => Promise; - -export type GetBridgeInfoFunctions = { - getBridgeInfo: GetBridgeInfo; +export type GetBridgeRoutesFunctions = { + /** @description Fetch supported bridge routes as a flat array (v2 replacement for bridge-info). */ + getBridgeRoutes: GetBridgeRoutes; + /** @description Fetch supported bridge protocols (unchanged from v1). */ getBridgeProtocols: GetBridgeProtocols; }; -export const constructGetBridgeInfo = ({ +export const constructGetBridgeRoutes = ({ apiURL = API_URL, fetcher, -}: ConstructFetchInput): GetBridgeInfoFunctions => { - const deltaBridgeUrl = `${apiURL}/delta/prices` as const; +}: ConstructFetchInput): GetBridgeRoutesFunctions => { + const deltaPricesUrl = `${apiURL}/v2/delta/prices` as const; - const getBridgeInfo: GetBridgeInfo = async (params = {}, requestParams) => { + const getBridgeRoutes: GetBridgeRoutes = async ( + params = {}, + requestParams + ) => { const { allowBridgeAndSwap, bridges } = params; - const bridgesString = bridges ? bridges.join(',') : undefined; - const search = constructSearchString({ + const search = constructSearchString({ allowBridgeAndSwap, - bridges: bridgesString, + bridges: bridges?.join(','), }); - const fetchURL = `${deltaBridgeUrl}/bridge-info${search}` as const; + const fetchURL = `${deltaPricesUrl}/bridge-routes${search}` as const; - const data = await fetcher({ + const data = await fetcher({ url: fetchURL, method: 'GET', requestParams, }); - return data.supportedTokens; + return data.routes; }; const getBridgeProtocols: GetBridgeProtocols = async (requestParams) => { - const fetchURL = `${deltaBridgeUrl}/bridge-protocols` as const; + const fetchURL = `${deltaPricesUrl}/bridge-protocols` as const; const data = await fetcher({ url: fetchURL, @@ -85,8 +83,5 @@ export const constructGetBridgeInfo = ({ return data.bridgeProtocols; }; - return { - getBridgeInfo, - getBridgeProtocols, - }; + return { getBridgeRoutes, getBridgeProtocols }; }; diff --git a/src/methods/delta/getDeltaOrders.ts b/src/methods/delta/getDeltaOrders.ts index 412a1362e..5721d6f3b 100644 --- a/src/methods/delta/getDeltaOrders.ts +++ b/src/methods/delta/getDeltaOrders.ts @@ -3,24 +3,11 @@ import { constructSearchString } from '../../helpers/misc'; import type { Address, ConstructFetchInput, + PaginatedResponse, RequestParameters, } from '../../types'; -import type { - DeltaAuction, - DeltaAuctionStatus, - OnChainOrderType, -} from './helpers/types'; - -/** @deprecated Use DeltaAuction directly */ -export type DeltaOrderFromAPI = DeltaAuction; - -export type DeltaOrderFilterByStatus = - | DeltaAuctionStatus - | 'INSUFFICIENT_BALANCE' - | 'INSUFFICIENT_ALLOWANCE' - | 'INVALIDATED' - | 'ACTIVE' - | 'INACTIVE'; +import type { DeltaOrderType, OnChainOrderType } from './helpers/types'; +import type { DeltaOrderStatus, DeltaAuction } from './types'; type GetDeltaOrderById = ( orderId: string, @@ -33,43 +20,31 @@ type GetDeltaOrderByHash = ( ) => Promise; type OrdersFilter = { - /** @description Order.owner to fetch Delta Order for */ + /** @description `order.owner` to fetch Delta Orders for. */ userAddress: Address; - /** @description Pagination option, page. Default 1 */ + /** @description Pagination option. Default 1. */ page?: number; - /** @description Pagination option, limit. Default 100 */ + /** @description Pagination option. Default 100, max 1000. */ limit?: number; - /** @description Filter by chainId, without this filter, orders from all chains are returned */ + /** @description Filter by chainId. Omitted = orders across all chains. */ chainId?: number[]; - /** - * @description - * Filter by any known DeltaAuctionStatus and some custom statuses: - * - **INSUFFICIENT_BALANCE** — returned as SUSPENDED from API - * - **INSUFFICIENT_ALLOWANCE** — returned as SUSPENDED from API - * - **INVALIDATED** — returned as FAILED from API - * - **ACTIVE** — All orders with NOT_STARTED, RUNNING, EXECUTING, CANCELLING or SUSPENDED statuses. - * - **INACTIVE** — All orders with EXECUTED, FAILED, EXPIRED, CANCELLED or INVALIDATED statuses. - */ - status?: DeltaOrderFilterByStatus[]; - /** @description Filter by type. MARKET, LIMIT. Orders with both types are returned if not specified */ - type?: 'MARKET' | 'LIMIT'; - /** @description Filter by on-chain order type. Order, ExternalOrder. Orders of all types are returned if not specified */ + /** @description Filter by integrator-facing status. */ + status?: DeltaOrderStatus[]; + /** @description Filter by order type. MARKET or LIMIT. */ + type?: DeltaOrderType; + /** @description Filter by on-chain order type. Narrows the returned `DeltaAuction`. */ onChainOrderType?: T; }; + type OrderFiltersQuery = Omit & { chainId?: string; status?: string; }; -type GetDeltaOrders = { - ( - options: OrdersFilter & { onChainOrderType: T }, - requestParams?: RequestParameters - ): Promise[]>; - (options: OrdersFilter, requestParams?: RequestParameters): Promise< - DeltaAuction[] - >; -}; +type GetDeltaOrders = ( + options: OrdersFilter, + requestParams?: RequestParameters +) => Promise>>; type GetRequiredBalanceParams = { userAddress: Address; @@ -79,13 +54,17 @@ type GetRequiredBalanceParams = { type GetRequiredBalance = ( userParams: GetRequiredBalanceParams, requestParams?: RequestParameters -) => Promise>; // token -> balance in Limit Orders +) => Promise>; // token -> required balance across open Delta orders export type GetDeltaOrdersFunctions = { + /** @description Fetch a single order by its UUID. */ getDeltaOrderById: GetDeltaOrderById; + /** @description Fetch a single order by its EIP-712 order hash. */ getDeltaOrderByHash: GetDeltaOrderByHash; + /** @description List Delta orders with the v2 pagination envelope. */ getDeltaOrders: GetDeltaOrders; - getRequiredBalanceForDeltaLimitOrders: GetRequiredBalance; + /** @description Required balance per token across the user's open Delta v2 orders. Pass `tokenAddress` to narrow the result to a single token. */ + getRequiredBalanceForDeltaOrders: GetRequiredBalance; }; export const constructGetDeltaOrders = ({ @@ -93,21 +72,18 @@ export const constructGetDeltaOrders = ({ fetcher, chainId, }: ConstructFetchInput): GetDeltaOrdersFunctions => { - const baseUrl = `${apiURL}/delta/orders` as const; + const baseUrl = `${apiURL}/v2/delta/orders` as const; const getDeltaOrderById: GetDeltaOrderById = async ( orderId, requestParams ) => { const fetchURL = `${baseUrl}/${orderId}` as const; - - const order = await fetcher({ + return fetcher({ url: fetchURL, method: 'GET', requestParams, }); - - return order; }; const getDeltaOrderByHash: GetDeltaOrderByHash = async ( @@ -115,14 +91,11 @@ export const constructGetDeltaOrders = ({ requestParams ) => { const fetchURL = `${baseUrl}/hash/${orderHash}` as const; - - const order = await fetcher({ + return fetcher({ url: fetchURL, method: 'GET', requestParams, }); - - return order; }; const getDeltaOrders: GetDeltaOrders = async < @@ -130,7 +103,7 @@ export const constructGetDeltaOrders = ({ >( options: OrdersFilter, requestParams?: RequestParameters - ) => { + ): Promise>> => { const chainIdString = options.chainId?.join(','); const statusString = options.status?.join(','); @@ -146,16 +119,14 @@ export const constructGetDeltaOrders = ({ const fetchURL = `${baseUrl}${search}` as const; - const orders = await fetcher[]>({ + return fetcher>>({ url: fetchURL, method: 'GET', requestParams, }); - - return orders; }; - const getRequiredBalanceForDeltaLimitOrders: GetRequiredBalance = async ( + const getRequiredBalanceForDeltaOrders: GetRequiredBalance = async ( userParams, requestParams ) => { @@ -178,6 +149,6 @@ export const constructGetDeltaOrders = ({ getDeltaOrderById, getDeltaOrderByHash, getDeltaOrders, - getRequiredBalanceForDeltaLimitOrders, + getRequiredBalanceForDeltaOrders, }; }; diff --git a/src/methods/delta/getDeltaPrice.ts b/src/methods/delta/getDeltaPrice.ts index 70e69c658..34942ac75 100644 --- a/src/methods/delta/getDeltaPrice.ts +++ b/src/methods/delta/getDeltaPrice.ts @@ -1,5 +1,3 @@ -import { Prettify } from 'viem'; -import { Bridge } from '../..'; import { API_URL, SwapSide } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; import type { @@ -7,14 +5,14 @@ import type { EnumerateLiteral, RequestParameters, } from '../../types'; -import { BridgePriceInfo } from './helpers/types'; +import type { DeltaPrice } from './types'; type SwapSideUnion = EnumerateLiteral; export type DeltaPriceParams = { - /** @description Source Token Address. Not Native Token */ + /** @description Source Token Address */ srcToken: string; - /** @description Destination Token Address */ + /** @description Destination Token Address. For Crosschain Orders, the destination token on the destination chain */ destToken: string; /** @description srcToken amount in wei */ amount: string; @@ -25,16 +23,16 @@ export type DeltaPriceParams = { /** @description User's Wallet Address */ userAddress?: string; /** @description Beneficiary Address */ - beneficiary?: string; // beneficiary==owner if no transferTo + beneficiary?: string; /** @description Partner string. */ partner?: string; - /** @description Used together with `partner` if provided. Represented in basis points, 50bps=0.5% */ + /** @description Partner fee in basis points (bps), 50bps=0.5% */ partnerFeeBps?: number; /** @description Destination Chain ID for Crosschain Orders */ destChainId?: number; /** @description SELL or BUY, default is SELL */ side?: SwapSideUnion; - /** @description In %. It's a way to bypass the API price impact check (default = 15%) */ + /** @description In %. Bypasses the API price impact check (default = 15%) */ maxImpact?: number; maxUSDImpact?: number; @@ -52,101 +50,20 @@ type DeltaPriceQueryOptions = Omit< DeltaPriceParams, 'includeAgents' | 'excludeAgents' | 'includeBridges' | 'excludeBridges' > & { - chainId: number; // will return error from API on unsupported chains + chainId: number; includeAgents?: string; excludeAgents?: string; includeBridges?: string; excludeBridges?: string; }; -export type DeltaPrice = { - srcToken: string; - destToken: string; - srcAmount: string; - /** @description Available for BUY side */ - srcAmountBeforeFee?: string; - destAmount: string; - /** @description Available for SELL side */ - destAmountBeforeFee?: string; - /** @description amount of the final outcome token */ - receivedDestAmount: string; - receivedDestUSD: string; - /** @description Available for SELL side */ - receivedDestAmountBeforeFee?: string; - /** @description Available for SELL side */ - receivedDestUSDBeforeFee?: string; - gasCost: string; - gasCostBeforeFee: string; - gasCostUSD: string; - gasCostUSDBeforeFee: string; - srcUSD: string; - /** @description Available for BUY side */ - srcUSDBeforeFee?: string; - destUSD: string; - /** @description Available for SELL side */ - destUSDBeforeFee?: string; - partner: string; - partnerFee: number; // in % - hmac: string; - bridge: Bridge; // for single-chain DeltaPrice, it's DEFAULT_BRIDGE -}; - -type AvailableBridgePrice = Pick< - DeltaPrice, - | 'srcAmount' - | 'srcAmountBeforeFee' // Available for BUY side - | 'srcUSD' - | 'srcUSDBeforeFee' // Available for BUY side - | 'destToken' - | 'destAmount' - | 'destAmountBeforeFee' // Available for SELL side - | 'destUSD' - | 'destUSDBeforeFee' // Available for SELL side - | 'gasCostUSD' - | 'gasCost' - | 'gasCostUSDBeforeFee' - | 'gasCostBeforeFee' - | 'receivedDestAmount' - | 'receivedDestAmountBeforeFee' - | 'receivedDestUSD' - | 'receivedDestUSDBeforeFee' ->; - -export type AvailableBridge = Prettify< - AvailableBridgePrice & Pick ->; - -export type BridgePrice = Omit & { - // destAmountAfterBridge: string; // became bridgeInfo.destAmountAfterBridge - // destUSDAfterBridge: string; // became bridgeInfo.destUSDAfterBridge - // bridgeFee: string; // became bridgeInfo.fees[0].amount - // bridgeFeeUSD: string; // became bridgeInfo.fees[0].amountInUSD - // poolAddress: string; - bridge: Bridge; - bridgeInfo: BridgePriceInfo; - availableBridges: AvailableBridge[]; -}; - -type DeltaPriceResponse = { - price: DeltaPrice | BridgePrice; - deltaAddress: string; -}; - -interface GetDeltaPrice { - ( - options: DeltaPriceParams & { destChainId: number }, - requestParams?: RequestParameters - ): Promise; - ( - options: DeltaPriceParams & { destChainId?: undefined }, - requestParams?: RequestParameters - ): Promise; - (options: DeltaPriceParams, requestParams?: RequestParameters): Promise< - DeltaPrice | BridgePrice - >; -} +type GetDeltaPrice = ( + options: DeltaPriceParams, + requestParams?: RequestParameters +) => Promise; export type GetDeltaPriceFunctions = { + /** @description Fetch a v2 price quote (route-based response). */ getDeltaPrice: GetDeltaPrice; }; @@ -155,24 +72,9 @@ export const constructGetDeltaPrice = ({ chainId, fetcher, }: ConstructFetchInput): GetDeltaPriceFunctions => { - const pricesUrl = `${apiURL}/delta/prices` as const; + const pricesUrl = `${apiURL}/v2/delta/prices` as const; - async function getDeltaPrice( - options: DeltaPriceParams & { destChainId: number }, - requestParams?: RequestParameters - ): Promise; - async function getDeltaPrice( - options: DeltaPriceParams & { destChainId?: undefined }, - requestParams?: RequestParameters - ): Promise; - async function getDeltaPrice( - options: DeltaPriceParams, - requestParams?: RequestParameters - ): Promise; - async function getDeltaPrice( - options: DeltaPriceParams, - requestParams?: RequestParameters - ): Promise { + const getDeltaPrice: GetDeltaPrice = async (options, requestParams) => { const { includeAgents, excludeAgents, @@ -180,41 +82,27 @@ export const constructGetDeltaPrice = ({ excludeBridges, ...rest } = options; - const includeAgentsString = includeAgents - ? includeAgents.join(',') - : undefined; - const excludeAgentsString = excludeAgents - ? excludeAgents.join(',') - : undefined; - const includeBridgesString = includeBridges - ? includeBridges.join(',') - : undefined; - const excludeBridgesString = excludeBridges - ? excludeBridges.join(',') - : undefined; const search = constructSearchString({ ...rest, chainId, side: options.side ?? SwapSide.SELL, - includeAgents: includeAgentsString, - excludeAgents: excludeAgentsString, - includeBridges: includeBridgesString, - excludeBridges: excludeBridgesString, + includeAgents: includeAgents?.join(','), + excludeAgents: excludeAgents?.join(','), + includeBridges: includeBridges?.join(','), + excludeBridges: excludeBridges?.join(','), }); const fetchURL = `${pricesUrl}${search}` as const; - const data = await fetcher({ + const data = await fetcher({ url: fetchURL, method: 'GET', requestParams, }); - return data.price; - } - - return { - getDeltaPrice, + return data; }; + + return { getDeltaPrice }; }; diff --git a/src/methods/delta/helpers/buildDeltaOrderData.ts b/src/methods/delta/helpers/buildDeltaOrderData.ts index 3913c3e70..74ed03820 100644 --- a/src/methods/delta/helpers/buildDeltaOrderData.ts +++ b/src/methods/delta/helpers/buildDeltaOrderData.ts @@ -1,7 +1,5 @@ -import { MarkOptional } from 'ts-essentials'; import { Domain } from '../../common/orders/buildOrderData'; -import { Bridge, DeltaAuctionOrder } from './types'; -import { DELTA_DEFAULT_EXPIRY, producePartnerAndFee } from './misc'; +import { DeltaAuctionOrder } from './types'; // Order(address owner,address beneficiary,address srcToken,address destToken,uint256 srcAmount,uint256 destAmount,uint256 deadline,uint256 nonce,bytes permit, bridge Bridge)"; const SWAP_ORDER_EIP_712_TYPES = { @@ -79,77 +77,3 @@ export function produceDeltaOrderTypedData({ data: orderInput, }; } - -export type DeltaOrderDataInput = MarkOptional< - Omit, - 'beneficiary' | 'deadline' | 'nonce' | 'permit' ->; - -export type BuildDeltaOrderDataInput = MarkOptional< - DeltaOrderDataInput, - 'metadata' -> & { - partnerAddress: string; - paraswapDeltaAddress: string; - partnerFeeBps: number; - partnerTakesSurplus?: boolean; - capSurplus?: boolean; - chainId: number; - bridge: Bridge; -}; - -export function buildDeltaSignableOrderData({ - owner, - beneficiary = owner, - - srcToken, - destToken, - srcAmount, - destAmount, - expectedAmount, - - deadline = Math.floor(Date.now() / 1000 + DELTA_DEFAULT_EXPIRY), - nonce = Date.now().toString(10), // random enough to not cause collisions - - permit = '0x', - - kind, - metadata = '0x', - - partnerAddress, - partnerFeeBps, - partnerTakesSurplus = false, - capSurplus = true, - - chainId, - paraswapDeltaAddress, - bridge, -}: BuildDeltaOrderDataInput): SignableDeltaOrderData { - const orderInput: DeltaAuctionOrder = { - owner, - beneficiary, - srcToken, - destToken, - srcAmount, - destAmount, - expectedAmount, - deadline, - nonce, - permit, - partnerAndFee: producePartnerAndFee({ - partnerFeeBps, - partnerAddress, - partnerTakesSurplus, - capSurplus, - }), - bridge, - kind, - metadata, - }; - - return produceDeltaOrderTypedData({ - orderInput, - chainId, - paraswapDeltaAddress, - }); -} diff --git a/src/methods/delta/helpers/buildExternalOrderData.ts b/src/methods/delta/helpers/buildExternalOrderData.ts index 75d70a321..16709e763 100644 --- a/src/methods/delta/helpers/buildExternalOrderData.ts +++ b/src/methods/delta/helpers/buildExternalOrderData.ts @@ -1,7 +1,5 @@ -import { MarkOptional } from 'ts-essentials'; import { Domain } from '../../common/orders/buildOrderData'; import { ExternalDeltaOrder } from './types'; -import { DELTA_DEFAULT_EXPIRY, producePartnerAndFee } from './misc'; const EXTERNAL_ORDER_EIP_712_TYPES = { ExternalOrder: [ @@ -54,76 +52,3 @@ export function produceExternalOrderTypedData({ data: orderInput, }; } - -export type ExternalOrderDataInput = MarkOptional< - Omit, - 'deadline' | 'nonce' | 'permit' ->; - -export type BuildExternalOrderDataInput = MarkOptional< - ExternalOrderDataInput, - 'metadata' -> & { - partnerAddress: string; - paraswapDeltaAddress: string; - partnerFeeBps: number; - partnerTakesSurplus?: boolean; - capSurplus?: boolean; - chainId: number; -}; - -export function buildExternalOrderSignableData({ - owner, - handler, - - srcToken, - destToken, - srcAmount, - destAmount, - expectedAmount, - - deadline = Math.floor(Date.now() / 1000 + DELTA_DEFAULT_EXPIRY), - nonce = Date.now().toString(10), - - permit = '0x', - - kind, - metadata = '0x', - data, - - partnerAddress, - partnerFeeBps, - partnerTakesSurplus = false, - capSurplus = true, - - chainId, - paraswapDeltaAddress, -}: BuildExternalOrderDataInput): SignableExternalOrderData { - const orderInput: ExternalDeltaOrder = { - owner, - handler, - srcToken, - destToken, - srcAmount, - destAmount, - expectedAmount, - deadline, - nonce, - permit, - partnerAndFee: producePartnerAndFee({ - partnerFeeBps, - partnerAddress, - partnerTakesSurplus, - capSurplus, - }), - kind, - metadata, - data, - }; - - return produceExternalOrderTypedData({ - orderInput, - chainId, - paraswapDeltaAddress, - }); -} diff --git a/src/methods/delta/helpers/buildTWAPOrderData.ts b/src/methods/delta/helpers/buildTWAPOrderData.ts index ffed266a2..8a53ad0d6 100644 --- a/src/methods/delta/helpers/buildTWAPOrderData.ts +++ b/src/methods/delta/helpers/buildTWAPOrderData.ts @@ -1,12 +1,10 @@ import { Domain } from '../../common/orders/buildOrderData'; import { - Bridge, TWAPDeltaOrder, TWAPBuyDeltaOrder, TWAPOnChainOrderType, OnChainOrderMap, } from './types'; -import { DELTA_DEFAULT_EXPIRY, producePartnerAndFee } from './misc'; const BRIDGE_EIP_712_TYPE = [ { name: 'protocolSelector', type: 'bytes4' }, @@ -112,122 +110,3 @@ export function produceTWAPOrderTypedData({ data: orderInput, }; } - -export type TWAPOrderCommonInput = { - owner: string; - beneficiary?: string; - srcToken: string; - destToken: string; - nonce?: string; - deadline?: number; - permit?: string; - metadata?: string; - interval: number; - numSlices: number; - bridge: Bridge; - - partnerAddress: string; - paraswapDeltaAddress: string; - partnerFeeBps: number; - partnerTakesSurplus?: boolean; - capSurplus?: boolean; - chainId: number; -}; - -export type BuildTWAPSellOrderDataInput = TWAPOrderCommonInput & { - onChainOrderType: 'TWAPOrder'; - destAmountPerSlice: string; - totalSrcAmount: string; -}; - -export type BuildTWAPBuyOrderDataInput = TWAPOrderCommonInput & { - onChainOrderType: 'TWAPBuyOrder'; - totalDestAmount: string; - maxSrcAmount: string; -}; - -export type BuildTWAPOrderDataInput = - | BuildTWAPSellOrderDataInput - | BuildTWAPBuyOrderDataInput; - -export function buildTWAPSignableOrderData( - input: BuildTWAPOrderDataInput -): SignableTWAPOrderData { - const { - owner, - beneficiary = owner, - srcToken, - destToken, - nonce = Date.now().toString(10), - permit = '0x', - metadata = '0x', - interval, - numSlices, - bridge, - - partnerAddress, - partnerFeeBps, - partnerTakesSurplus = false, - capSurplus = true, - chainId, - paraswapDeltaAddress, - onChainOrderType, - } = input; - - const deadline = - input.deadline ?? - // all slices must execute before the deadline, - // so we add the total duration of the TWAP (interval * numSlices) to the current time, - // plus a buffer defined by DELTA_DEFAULT_EXPIRY - Math.floor(Date.now() / 1000 + interval * numSlices + DELTA_DEFAULT_EXPIRY); - - const partnerAndFee = producePartnerAndFee({ - partnerFeeBps, - partnerAddress, - partnerTakesSurplus, - capSurplus, - }); - - const commonFields = { - owner, - beneficiary, - srcToken, - destToken, - nonce, - partnerAndFee, - deadline, - interval, - numSlices, - permit, - metadata, - bridge, - }; - - if (onChainOrderType === 'TWAPOrder') { - const orderInput: TWAPDeltaOrder = { - ...commonFields, - destAmountPerSlice: input.destAmountPerSlice, - totalSrcAmount: input.totalSrcAmount, - }; - - return produceTWAPOrderTypedData({ - orderInput, - chainId, - paraswapDeltaAddress, - onChainOrderType: 'TWAPOrder', - }); - } - - const orderInput: TWAPBuyDeltaOrder = { - ...commonFields, - totalDestAmount: input.totalDestAmount, - maxSrcAmount: input.maxSrcAmount, - }; - - return produceTWAPOrderTypedData({ - orderInput, - chainId, - paraswapDeltaAddress, - onChainOrderType: 'TWAPBuyOrder', - }); -} diff --git a/src/methods/delta/helpers/misc.ts b/src/methods/delta/helpers/misc.ts index 6d7cf954f..fd8cc3584 100644 --- a/src/methods/delta/helpers/misc.ts +++ b/src/methods/delta/helpers/misc.ts @@ -1,180 +1,6 @@ -import { ZERO_ADDRESS } from '../../common/orders/buildOrderData'; import type { SignableDeltaOrderData } from './buildDeltaOrderData'; import type { SignableExternalOrderData } from './buildExternalOrderData'; import type { SignableTWAPOrderData } from './buildTWAPOrderData'; -import type { GetPartnerFeeFunctions } from '../getPartnerFee'; -import type { RequestParameters } from '../../../types'; -import type { DeltaAmountsWithSlippage, SwapSideUnion } from './types'; -import { SwapSide } from '../../../constants'; -import { assert } from 'ts-essentials'; - -// default deadline = 10 min -export const DELTA_DEFAULT_EXPIRY = 10 * 60; // seconds - -type ProducePartnerAndFeeInput = { - partnerFeeBps: number; - partnerAddress: string; - partnerTakesSurplus: boolean; - capSurplus: boolean; -}; - -// fee and address are encoded together -export function producePartnerAndFee({ - partnerFeeBps, - partnerAddress, - partnerTakesSurplus, - capSurplus, -}: ProducePartnerAndFeeInput): string { - const capSurplusShifted = BigInt(capSurplus) << BigInt(9); - if (partnerAddress === ZERO_ADDRESS) { - return capSurplusShifted.toString(10); - } else { - const partnerAndFee = - (BigInt(partnerAddress) << BigInt(96)) | - BigInt(partnerFeeBps.toFixed(0)) | - (BigInt(partnerTakesSurplus) << BigInt(8)) | - capSurplusShifted; - - return partnerAndFee.toString(10); - } -} - -type ApplySlippageInput = { - amount: string; - slippageBps: number; - increase: boolean; -}; - -export function applySlippage({ - amount, - slippageBps, - increase, -}: ApplySlippageInput): string { - assert( - Number.isInteger(slippageBps) && slippageBps >= 0 && slippageBps <= 10_000, - 'slippageBps must be an integer between 0 and 10_000' - ); - - const BPS_BASE = 10_000n; - const amt = BigInt(amount); - const bps = BigInt(slippageBps); - - return increase - ? ((amt * (BPS_BASE + bps)) / BPS_BASE).toString(10) - : ((amt * (BPS_BASE - bps)) / BPS_BASE).toString(10); -} - -export type ResolvePartnerFeeInput = { - partnerAddress?: string; - partnerFeeBps?: number; - partnerTakesSurplus?: boolean; - partner?: string; - deltaPrice: { partner?: string; partnerFee?: number }; -}; - -export type ResolvedPartnerFee = { - partnerAddress: string; - partnerFeeBps: number; - partnerTakesSurplus: boolean; -}; - -export async function resolvePartnerFee( - options: ResolvePartnerFeeInput, - getPartnerFee: GetPartnerFeeFunctions['getPartnerFee'], - requestParams?: RequestParameters -): Promise { - // externally supplied partner fee data takes precedence - let partnerAddress = options.partnerAddress; - let partnerFeeBps = - options.partnerFeeBps ?? - (options.deltaPrice.partnerFee !== undefined - ? options.deltaPrice.partnerFee * 100 - : undefined); - let partnerTakesSurplus = options.partnerTakesSurplus; - - // if fee given, takeSurplus is ignored - const feeOrTakeSurplusSupplied = - partnerFeeBps !== undefined || partnerTakesSurplus !== undefined; - - if (partnerAddress === undefined || feeOrTakeSurplusSupplied) { - const partner = options.partner || options.deltaPrice.partner; - if (!partner) { - // if no partner given in options or deltaPrice, default partnerAddress to zero, - // unless supplied explicitly - partnerAddress = partnerAddress ?? ZERO_ADDRESS; - } else { - const partnerFeeResponse = await getPartnerFee( - { partner }, - requestParams - ); - - partnerAddress = partnerAddress ?? partnerFeeResponse.partnerAddress; - // deltaPrice.partnerFee and partnerFeeResponse.partnerFee should be the same, but give priority to externally provided - partnerFeeBps = partnerFeeBps ?? partnerFeeResponse.partnerFee * 100; - partnerTakesSurplus = - partnerTakesSurplus ?? partnerFeeResponse.takeSurplus; - } - } - - return { - partnerAddress, - partnerFeeBps: partnerFeeBps ?? 0, - partnerTakesSurplus: partnerTakesSurplus ?? false, - }; -} - -export type ResolveAmountsInput = DeltaAmountsWithSlippage & { - deltaPrice: { destAmount: string; srcAmount: string }; -}; - -export type ResolvedAmounts = { - srcAmount: string; - destAmount: string; - expectedAmount: string; - swapSide: SwapSideUnion; -}; - -export function resolveAmounts(options: ResolveAmountsInput): ResolvedAmounts { - let srcAmount: string; - let destAmount: string; - - const swapSide: SwapSideUnion = - options.slippage !== undefined - ? options.srcAmount !== undefined - ? SwapSide.SELL - : SwapSide.BUY - : options.side ?? SwapSide.SELL; - - if (options.slippage !== undefined) { - if (options.srcAmount !== undefined) { - // SELL with slippage: destAmount auto-computed - srcAmount = options.srcAmount; - destAmount = applySlippage({ - amount: options.deltaPrice.destAmount, - slippageBps: options.slippage, - increase: false, - }); - } else { - // BUY with slippage: srcAmount auto-computed - destAmount = options.destAmount; - srcAmount = applySlippage({ - amount: options.deltaPrice.srcAmount, - slippageBps: options.slippage, - increase: true, - }); - } - } else { - srcAmount = options.srcAmount; - destAmount = options.destAmount; - } - - const expectedAmount = - swapSide === SwapSide.SELL - ? options.deltaPrice.destAmount - : options.deltaPrice.srcAmount; - - return { srcAmount, destAmount, expectedAmount, swapSide }; -} export function sanitizeDeltaOrderData({ owner, @@ -280,3 +106,15 @@ export function sanitizeTWAPOrderData( maxSrcAmount: orderData.maxSrcAmount, }; } + +// export function sanitizeArbitraryOrderData( +// orderData: T +// ): T { +// if ('handler' in orderData) { +// return sanitizeExternalOrderData(orderData) as T; +// } else if ('interval' in orderData) { +// return sanitizeTWAPOrderData(orderData) as T; +// } else { +// return sanitizeDeltaOrderData(orderData) as T; +// } +// } diff --git a/src/methods/delta/helpers/orders.ts b/src/methods/delta/helpers/orders.ts index 6c5c45a21..0ed49bcd2 100644 --- a/src/methods/delta/helpers/orders.ts +++ b/src/methods/delta/helpers/orders.ts @@ -1,23 +1,40 @@ import type { NonEmptyArray, Prettify } from 'ts-essentials'; import { Bridge, - DeltaAuction, DeltaAuctionOrder, - DeltaAuctionStatus, - DeltaAuctionTransaction, - DeltaAuctionTWAP, - DeltaAuctionTWAPBuy, - DeltaOrderUnion, ExternalDeltaOrder, OnChainOrderType, OrderKind, + ProductiveDeltaOrder, SwapSideUnion, TWAPBuyDeltaOrder, TWAPDeltaOrder, + DeltaOrderUnion, UnifiedDeltaOrderData, } from './types'; +import type { + DeltaAuction, + DeltaOrderStatus, + DeltaTokenSide, + DeltaTransaction, +} from '../types'; + +/** + * Delta order helpers. + * + * The on-chain order structs (`auction.order`) and the `onChainOrderType` union + * are shared across all order families, so the order-struct guards, auction + * discriminant guards, and order-level getters operate purely on those shapes. + * + * The *auction* envelope is the integrator-facing v2 shape: + * - `status` is the integrator-facing `DeltaOrderStatus` + * (PENDING/ACTIVE/COMPLETED/…), + * - amounts live on `input`/`output` (`DeltaTokenSide`) and `transactions` + * (`DeltaTransaction`), + * - `side` is carried explicitly on the auction. + */ -///// CHECKS ////// +///// CHECKS — order structs ////// /** * @description Checks whether an order is a TWAP Sell or TWAP Buy order. @@ -38,6 +55,7 @@ function isTWAPSellOrder(order: DeltaOrderUnion): order is TWAPDeltaOrder { typeof order.totalSrcAmount === 'string' ); } + /** * @description Checks whether an order is a TWAP Buy order. */ @@ -65,6 +83,18 @@ function isDeltaOrder(order: DeltaOrderUnion): order is DeltaAuctionOrder { ); } +/** + * @description Checks whether an order is a Productive Delta order + * (strategy-routed order without an explicit OrderKind). + */ +function isProductiveOrder( + order: DeltaOrderUnion +): order is ProductiveDeltaOrder { + return 'strategy' in order && typeof order.strategy === 'string'; +} + +///// CHECKS — auction discriminants ////// + /** * @description Checks whether an auction is a TWAP auction. */ @@ -110,27 +140,199 @@ function isExternalAuction(auction: { return auction.onChainOrderType === 'ExternalOrder'; } +/** + * @description Checks whether an auction is a Productive auction. + */ +function isProductiveAuction(auction: { + onChainOrderType: T; +}): auction is { onChainOrderType: 'ProductiveOrder' & T } { + return auction.onChainOrderType === 'ProductiveOrder'; +} + +/** + * @description Checks whether an auction is a Fillable auction. + * `FillableOrder` is the `onChainOrderType` the server reports for a + * `partiallyFillable` Standard order; it carries the same order struct as + * `Order`. Consumers that don't distinguish the two should treat + * `isDeltaAuction(a) || isFillableAuction(a)` as "is a standard order". + */ +function isFillableAuction>( + auction: T +): auction is T & { onChainOrderType: 'FillableOrder' } { + return auction.onChainOrderType === 'FillableOrder'; +} + +///// CHECKS — status / execution (v2 envelope) ////// + +/** + * @description Checks whether an auction is fully executed (settled on every chain). + */ +function isCompletedAuction>( + auction: T +): auction is T & { status: 'COMPLETED' } { + return auction.status === 'COMPLETED'; +} + +const failedAuctionStatuses = [ + 'FAILED', + 'EXPIRED', + 'CANCELLED', + 'REFUNDED', + 'REFUNDING', +] as const; + +const failedAuctionStatusesSet = new Set( + failedAuctionStatuses +); + +/** + * @description Checks whether an auction is in a terminal failure state + * (failed, expired, cancelled, or refunded). + */ +function isFailedAuction>( + auction: T +): auction is T & { status: (typeof failedAuctionStatuses)[number] } { + return failedAuctionStatusesSet.has(auction.status); +} + +/** + * @description Checks whether an auction status is cancelled. + */ +function isCanceledAuction>( + auction: T +): auction is T & { status: 'CANCELLED' } { + return auction.status === 'CANCELLED'; +} + +/** + * @description Checks whether an auction status is expired. + */ +function isExpiredAuction>( + auction: T +): auction is T & { status: 'EXPIRED' } { + return auction.status === 'EXPIRED'; +} + +const pendingAuctionStatuses = [ + 'PENDING', + 'AWAITING_SIGNATURE', + 'ACTIVE', + 'BRIDGING', +] as const; + +const pendingAuctionStatusesSet = new Set( + pendingAuctionStatuses +); + +/** + * @description Checks whether an auction is still in flight (not yet settled + * and not failed): awaiting signature, pending, actively executing, or bridging. + */ +function isPendingAuction>( + auction: T +): auction is T & { status: (typeof pendingAuctionStatuses)[number] } { + return pendingAuctionStatusesSet.has(auction.status); +} + +/** + * @description Checks whether an auction has been partially executed: + * it has at least one transaction and an overall filled percent strictly + * between 0 and 100. + */ +function isPartiallyExecutedAuction< + T extends Pick +>( + auction: T +): auction is T & { transactions: NonEmptyArray } { + if (auction.transactions.length === 0) return false; + + const filledPercent = getFilledPercent(auction); + + return filledPercent > 0 && filledPercent < 100; +} + +/** + * @description Checks whether an order includes valid cross-chain bridge details. + */ +function isOrderCrosschain( + order: T +): order is Prettify & { bridge: Bridge }> { + return ( + 'bridge' in order && !!order.bridge && order.bridge.destinationChainId !== 0 + ); +} + const checks = { + // order-struct guards isTWAPOrder, isTWAPSellOrder, isTWAPBuyOrder, isExternalOrder, isDeltaOrder, + isProductiveOrder, + isOrderCrosschain, + + // auction discriminant guards isTWAPAuction, isTWAPSellAuction, isTWAPBuyAuction, isDeltaAuction, isExternalAuction, - isOrderCrosschain, - isExecutedAuction, - isPartiallyExecutedAuction, + isProductiveAuction, + isFillableAuction, + + // status / execution guards (v2 envelope) + isCompletedAuction, isFailedAuction, isCanceledAuction, isExpiredAuction, isPendingAuction, + isPartiallyExecutedAuction, }; -///// GETTERS ////// +///// GETTERS — order structs ////// + +const OrderKindToSwapSide = { + [OrderKind.Sell]: 'SELL', + [OrderKind.Buy]: 'BUY', +} as const; + +/** + * @description Returns swap side from a Delta or External order kind. + */ +function getSwapSideFromDeltaOrder( + order: DeltaAuctionOrder | ExternalDeltaOrder +): SwapSideUnion { + return OrderKindToSwapSide[order.kind]; +} + +const TwapTypeToSwapSide = { + TWAPOrder: 'SELL', + TWAPBuyOrder: 'BUY', +} as const; + +/** + * @description Returns swap side from TWAP on-chain order type. + */ +function getSwapSideFromTwapOrderType( + onChainOrderType: 'TWAPOrder' | 'TWAPBuyOrder' +): SwapSideUnion { + return TwapTypeToSwapSide[onChainOrderType]; +} + +/** + * @description Returns source and destination token addresses for an order. + */ +function getOrderTokenAddresses(order: DeltaAuction['order']) { + const srcToken = order.srcToken; + const destToken = isOrderCrosschain(order) + ? order.bridge.outputToken + : order.destToken; + return { + srcToken, + destToken, + }; +} /** * @description Returns the expected source amount for a TWAP order. @@ -179,169 +381,88 @@ function getExpectedTwapOrderAmounts( return { srcAmount, destAmount }; } -/** - * @description Returns expected and, when available, final amounts for a TWAP auction. - */ -function getTwapAuctionAmounts( - twapAuction: - | Pick - | Pick -) { - const isExecuted = isExecutedAuction(twapAuction); +function scaleByFactor(amount: bigint, scalingFactor: number): bigint { + if (!amount) return 0n; - const expected = getExpectedTwapOrderAmounts(twapAuction.order); - if (isExecuted) { - const final = getTransactionAmounts(twapAuction.transactions); - return { - final, - expected, - minimal: expected, // TWAP orders don't have more detailed amounts - }; - } - return { - expected, - minimal: expected, // TWAP orders don't have more detailed amounts - }; -} + if (scalingFactor === 0) return amount; -const getters = { - getUnifiedDeltaOrderData, - getExpectedTwapSrcAmount, - getExpectedTwapDestAmount, - getExpectedTwapOrderAmounts, - getTwapAuctionAmounts, - getAuctionDestChainId, - getSwapSideFromDeltaOrder, - getSwapSideFromTwapOrderType, - getAuctionSwapSide, - getOrderTokenAddresses, - getTransactionAmounts, - getAuctionAmounts, - getFilledPercent, -}; + const base = 10n; -export const OrderHelpers = { - checks, - getters, -}; + return scalingFactor < 0 + ? amount / base ** BigInt(-scalingFactor) + : amount * base ** BigInt(scalingFactor); +} -// -------------------- Auction Unified Data -------------------- +///// GETTERS — auction envelope (v2) ////// /** - * @description Returns the destination chain id for the auction. + * @description Reads an amount off a v2 token side. A SELL input / BUY output + * carries an explicit `amount`; the opposite side carries + * `expectedAmount`/`executedAmount`. `prefer` chooses which to read on the + * expected/executed variant. */ -function getAuctionDestChainId({ - order, - chainId, -}: Pick) { - return isOrderCrosschain(order) ? order.bridge.destinationChainId : chainId; -} +function getTokenSideAmount( + side: DeltaTokenSide, + prefer: 'expected' | 'executed' +): string { + if ('amount' in side) return side.amount; -const OrderKindToSwapSide = { - [OrderKind.Sell]: 'SELL', - [OrderKind.Buy]: 'BUY', -} as const; + const value = + prefer === 'executed' ? side.executedAmount : side.expectedAmount; -/** - * @description Returns swap side from a Delta or External order kind. - */ -function getSwapSideFromDeltaOrder( - order: DeltaAuctionOrder | ExternalDeltaOrder -): SwapSideUnion { - return OrderKindToSwapSide[order.kind]; + return value ?? '0'; } -const TwapTypeToSwapSide = { - TWAPOrder: 'SELL', - TWAPBuyOrder: 'BUY', -} as const; - /** - * @description Returns swap side from TWAP on-chain order type. + * @description Returns the source chain id for the auction (the input side's chain). */ -function getSwapSideFromTwapOrderType( - onChainOrderType: 'TWAPOrder' | 'TWAPBuyOrder' -): SwapSideUnion { - return TwapTypeToSwapSide[onChainOrderType]; +function getAuctionSrcChainId(auction: Pick): number { + return auction.input.chainId; } /** - * @description Returns swap side for any auction type. + * @description Returns the destination chain id for the auction (the output side's chain). + * Equals the source chain id for same-chain orders. */ -function getAuctionSwapSide(auction: DeltaAuction): SwapSideUnion { - if (isTWAPAuction(auction)) { - // TWAP orders have onChainOrderType instead of kind - return getSwapSideFromTwapOrderType(auction.onChainOrderType); - } - return getSwapSideFromDeltaOrder(auction.order); +function getAuctionDestChainId(auction: Pick): number { + return auction.output.chainId; } /** - * @description Returns unified order data with normalized amounts, tokens, and side. + * @description Returns the swap side for any auction. The auction carries `side` + * directly, so no order introspection is needed. */ -function getUnifiedDeltaOrderData( - auction: DeltaAuction -): UnifiedDeltaOrderData { - const { order, chainId } = auction; - - const { srcToken, destToken } = getOrderTokenAddresses(order); - const { expected, final, minimal } = getAuctionAmounts(auction); - - const srcChainId = chainId; - const destChainId = getAuctionDestChainId({ order, chainId }); - - const swapSide = getAuctionSwapSide(auction); - - const filledPercent = getFilledPercent(auction); - - return { - srcChainId, - destChainId, - srcAmount: final?.srcAmount || expected.srcAmount, - destAmount: final?.destAmount || expected.destAmount, - amounts: { - expected, - final, - minimal, - }, - srcToken, - destToken, - swapSide, - filledPercent, - }; +function getAuctionSwapSide( + auction: Pick +): SwapSideUnion { + return auction.side; } /** - * @description Returns source and destination token addresses for an order. + * @description Returns source and destination token addresses for the auction, + * read from the input/output sides (already resolved to the dest-chain token + * for cross-chain orders). */ -function getOrderTokenAddresses(order: DeltaAuction['order']) { - const srcToken = order.srcToken; - const destToken = isOrderCrosschain(order) - ? order.bridge.outputToken - : order.destToken; +function getAuctionTokenAddresses( + auction: Pick +) { return { - srcToken, - destToken, + srcToken: auction.input.token, + destToken: auction.output.token, }; } /** - * @description Aggregates transaction amounts into total source and destination values. + * @description Aggregates transaction amounts into total spent (src) and + * received (dest) values. */ -function getTransactionAmounts(transactions: DeltaAuctionTransaction[]) { +function getTransactionAmounts(transactions: DeltaTransaction[]) { const { srcAmount, destAmount } = transactions.reduce( - (acc, { spentAmount, receivedAmount, bridgeMetadata }) => { - return { - srcAmount: acc.srcAmount + BigInt(spentAmount), - destAmount: - acc.destAmount + - BigInt(bridgeMetadata ? bridgeMetadata.outputAmount : receivedAmount), - }; - }, - { - srcAmount: 0n, - destAmount: 0n, - } + (acc, { spentAmount, receivedAmount }) => ({ + srcAmount: acc.srcAmount + BigInt(spentAmount ?? 0), + destAmount: acc.destAmount + BigInt(receivedAmount ?? 0), + }), + { srcAmount: 0n, destAmount: 0n } ); return { @@ -351,224 +472,144 @@ function getTransactionAmounts(transactions: DeltaAuctionTransaction[]) { } /** - * @description Returns expected and, when available, final amounts for an auction. + * @description Calculates the overall filled percent (0–100) from the + * per-transaction `filledPercent` values. For cross-chain orders, + * only transactions with a `destinationTx` are counted towards the filled percent. */ -function getAuctionAmounts(auction: DeltaAuction) { - const isTwap = checks.isTWAPAuction(auction); - if (isTwap) { - return getTwapAuctionAmounts(auction); - } - - let expected = { - srcAmount: auction.order.srcAmount, - // defensive fallback in case Order shape changes or legacy Orders don't have all fields - destAmount: auction.order.expectedAmount || auction.order.destAmount, - }; - - let minimal = { - srcAmount: auction.order.srcAmount, - destAmount: auction.order.destAmount, - }; - - const order = auction.order; - - if (isOrderCrosschain(order)) { - expected = { - srcAmount: expected.srcAmount, - destAmount: scaleByFactor( - BigInt(expected.destAmount), - order.bridge.scalingFactor - ).toString(), - }; - - minimal = { - srcAmount: minimal.srcAmount, - destAmount: scaleByFactor( - BigInt(minimal.destAmount), - order.bridge.scalingFactor - ).toString(), - }; - } +function getFilledPercent({ + order, + transactions, +}: Pick): number { + if (transactions.length === 0) return 0; - const isExecuted = isExecutedAuction(auction); - if (isExecuted) { - const final = getTransactionAmounts(auction.transactions); - return { - final, - expected, - minimal, - }; - } - return { - expected, - minimal, - }; -} + const completedTransactions = !isOrderCrosschain(order) + ? transactions + : transactions.filter((transaction) => !!transaction.destinationTx); -/** - * @description Checks whether an order includes valid cross-chain bridge details. - */ -function isOrderCrosschain( - order: T - // Extract == never -): order is Prettify & { bridge: Bridge }> { - return ( - 'bridge' in order && !!order.bridge && order.bridge.destinationChainId !== 0 + const total = completedTransactions.reduce( + (acc, { filledPercent }) => acc + filledPercent, + 0 ); -} - -function scaleByFactor(amount: bigint, scalingFactor: number): bigint { - if (!amount) return 0n; - - if (scalingFactor === 0) return amount; - const base = 10n; - - return scalingFactor < 0 - ? amount / base ** BigInt(-scalingFactor) - : amount * base ** BigInt(scalingFactor); + return total; } -type ExecutedDeltaAuctionProps = { - status: 'EXECUTED'; - transactions: NonEmptyArray; -}; - /** - * @description Checks whether an auction is fully executed. + * @description Returns the executed amount of a token side when present, + * otherwise the provided fallback (typically summed from transactions). */ -function isExecutedAuction< - T extends Pick ->(auction: T): auction is T & ExecutedDeltaAuctionProps { - if (auction.status !== 'EXECUTED') return false; - - if (isOrderCrosschain(auction.order)) { - const filledPercent = getFilledPercent(auction); - return filledPercent === 100; +function getExecutedAmount(side: DeltaTokenSide, fallback: string): string { + if ('executedAmount' in side && side.executedAmount != null) { + return side.executedAmount; } - return true; + return fallback; } -const failedAuctionStatuses = [ - 'FAILED', - 'EXPIRED', - 'CANCELLED', - 'REFUNDED', -] as const; - -const failedAuctionStatusesSet = new Set( - failedAuctionStatuses -); - -type FailedDeltaAuctionProps = - | { - status: (typeof failedAuctionStatuses)[number]; - } - | { - status: 'EXECUTED'; // srcChain tx succeeded - bridgeStatus: 'expired' | 'refunded'; // destChain tx failed or relayer didn't deliver - }; - /** - * @description Checks whether an auction is failed on source or destination chain. + * @description Returns expected and minimal amounts and, once the auction is completed, + * executed amounts. Executed amounts prefer the `executedAmount` baked onto the + * token sides and fall back to summing transactions. */ -function isFailedAuction< - T extends Pick ->(auction: T): auction is T & FailedDeltaAuctionProps { - // already failed on srcChain, whether Order is crosschain or not - if (failedAuctionStatusesSet.has(auction.status)) return true; +function getAuctionAmounts( + auction: Pick< + DeltaAuction, + 'status' | 'order' | 'input' | 'output' | 'transactions' + > +) { + const expected = { + srcAmount: getTokenSideAmount(auction.input, 'expected'), + destAmount: getTokenSideAmount(auction.output, 'expected'), + }; - // crosschain Order is executed on srcChain, but failed on destChain - if (auction.status === 'EXECUTED' && isOrderCrosschain(auction.order)) { - return ( - auction.bridgeStatus === 'expired' || auction.bridgeStatus === 'refunded' - ); - } + const order = auction.order; - return false; -} + let minimal; + if (isTWAPOrder(order)) { + minimal = expected; // TWAP doesn't carry explicit min amounts + } else if (isOrderCrosschain(order)) { + minimal = { + srcAmount: order.srcAmount, + destAmount: scaleByFactor( + BigInt(order.destAmount), + order.bridge.scalingFactor + ).toString(), + }; + } else { + minimal = { + srcAmount: order.srcAmount, + destAmount: order.destAmount, + }; + } -/** - * @description Checks whether an auction status is cancelled. - */ -function isCanceledAuction>( - auction: T -): auction is T & { - status: 'CANCELLED'; -} { - return auction.status === 'CANCELLED'; -} + if (!isCompletedAuction(auction)) { + return { expected, minimal }; + } -/** - * @description Checks whether an auction status is expired. - */ -function isExpiredAuction>( - auction: T -): auction is T & { - status: 'EXPIRED'; -} { - return auction.status === 'EXPIRED'; -} + const txAmounts = getTransactionAmounts(auction.transactions); -const pendingAuctionStatuses = [ - 'NOT_STARTED', - 'AWAITING_PRE_SIGNATURE', - 'RUNNING', - 'EXECUTING', -] as const; + const executed = { + srcAmount: getExecutedAmount(auction.input, txAmounts.srcAmount), + destAmount: getExecutedAmount(auction.output, txAmounts.destAmount), + }; -const pendingAuctionStatusesSet = new Set( - pendingAuctionStatuses -); -/** - * @description Checks whether an auction status is in pending execution states. - */ -function isPendingAuction>( - auction: T -): auction is T & { - status: (typeof pendingAuctionStatuses)[number]; -} { - return pendingAuctionStatusesSet.has(auction.status); + return { expected, executed, minimal }; } /** - * @description Auction can be cancelled in the middle of execution, - * or crosschain-TWAP slices may not all be bridged, - * or order can be suspended if it runs out of user balance/allowance. - * Orders in the middle of normal execution can also be considered partially executed if they have any transactions. + * @description Returns unified order data with normalized amounts, tokens, + * chain ids, and side, built from the auction envelope. */ -function isPartiallyExecutedAuction< - T extends Pick ->( - auction: T -): auction is T & { transactions: NonEmptyArray } { - if (auction.transactions.length === 0) return false; +function getUnifiedDeltaOrderData( + auction: DeltaAuction +): UnifiedDeltaOrderData { + const { srcToken, destToken } = getAuctionTokenAddresses(auction); + const { expected, executed, minimal } = getAuctionAmounts(auction); + const srcChainId = getAuctionSrcChainId(auction); + const destChainId = getAuctionDestChainId(auction); + const swapSide = getAuctionSwapSide(auction); const filledPercent = getFilledPercent(auction); - return filledPercent > 0 && filledPercent < 100; + return { + srcChainId, + destChainId, + srcAmount: executed?.srcAmount || expected.srcAmount, + destAmount: executed?.destAmount || expected.destAmount, + amounts: { + minimal, + expected, + final: executed, + }, + srcToken, + destToken, + swapSide, + filledPercent, + }; } -/** - * @description Calculates filled percentage from auction transaction filled bps values. - */ -function getFilledPercent( - auction: Pick -): number { - const completeTransactions = !isOrderCrosschain(auction.order) - ? auction.transactions - : auction.transactions.filter( - (transaction) => transaction.bridgeStatus === 'filled' - ); +const getters = { + getUnifiedDeltaOrderData, - const filledPercentBps = completeTransactions.reduce( - (acc, { filledPercent }) => { - return acc + filledPercent; - }, - 0 - ); + // auction-level getters — v2 envelope shape. + getAuctionTokenAddresses, + getAuctionSrcChainId, + getAuctionDestChainId, + getAuctionSwapSide, + getTransactionAmounts, + getAuctionAmounts, + getFilledPercent, - const filledPercent = filledPercentBps / 100; - return filledPercent; -} + // order-level getters — order structs shared across families. + getOrderTokenAddresses, + getSwapSideFromDeltaOrder, + getSwapSideFromTwapOrderType, + getExpectedTwapSrcAmount, + getExpectedTwapDestAmount, + getExpectedTwapOrderAmounts, +}; + +export const OrderHelpers = { + checks, + getters, +}; diff --git a/src/methods/delta/helpers/types.ts b/src/methods/delta/helpers/types.ts index 9d86178a0..7c036e98b 100644 --- a/src/methods/delta/helpers/types.ts +++ b/src/methods/delta/helpers/types.ts @@ -1,6 +1,5 @@ import type { EnumerateLiteral } from '../../../types'; import { SwapSide } from '../../../constants'; -import { Prettify } from 'ts-essentials'; export type SwapSideUnion = EnumerateLiteral; @@ -45,11 +44,6 @@ export enum OrderKind { Buy = 1, } -export const SwapSideToOrderKind = { - [SwapSide.SELL]: OrderKind.Sell, - [SwapSide.BUY]: OrderKind.Buy, -} as const; - export type DeltaAuctionOrder = { /** @description The address of the order owner */ owner: string; @@ -123,6 +117,41 @@ export type ExternalDeltaOrder = { data: string; }; +export type ProductiveDeltaOrder = { + /** @description The address of the order owner */ + owner: string; + /** @description The address of the order beneficiary */ + beneficiary: string; + /** @description The address of the src token */ + srcToken: string; + /** @description The address of the dest token */ + destToken: string; + /** @description The amount of src token to swap */ + srcAmount: string; + /** @description The minimum amount of dest token to receive */ + destAmount: string; + /** @description The expected amount of token to receive */ + expectedAmount: string; + /** @description The deadline for the order */ + deadline: number; + /** @description The nonce of the order */ + nonce: string; + /** @description Metadata for the order, hex string */ + metadata: string; + /** @description Encoded partner address, fee bps, and flags for the order. partnerAndFee = (partner << 96) | (partnerTakesSurplus << 8) | fee in bps (max fee is 2%) */ + partnerAndFee: string; + /** @description Optional permit signature for the src token */ + permit: string; + /** @description The strategy address. */ + strategy: string; + /** @description The number of shares to execute for this order. */ + shares: string; + /** @description Whether the order uses shares or raw amounts. */ + useShares: boolean; + /** @description The bridge input */ + bridge: Bridge; +}; + type TWAPDeltaOrderBase = { /** @description The address of the order owner */ owner: string; @@ -165,162 +194,23 @@ export type TWAPBuyDeltaOrder = TWAPDeltaOrderBase & { maxSrcAmount: string; // wei }; -export type DeltaAuctionStatus = - | 'NOT_STARTED' - | 'AWAITING_PRE_SIGNATURE' - | 'RUNNING' - | 'EXECUTING' - | 'EXECUTED' - | 'FAILED' - | 'EXPIRED' - | 'CANCELLED' - | 'CANCELLING' - | 'SUSPENDED' - | 'REFUNDED'; - -export type DeltaAuctionTransaction = { - id: string; - hash: string; - orderId: string; - bidId: string | null; - blockNumber: number; - blockHash: string; - blockTimestamp: string | null; // ISO string, null for older Orders - gasUsed: bigint; - gasPrice: bigint; - blobGasUsed: bigint; - blobGasPrice: bigint; - index: number; - status: number; - from: string; - to: string; - receivedAmount: string; - receivedAmountUSD: number; - spentAmount: string; - spentAmountUSD: number; - filledPercent: number; // in base points - protocolFee: string; - partnerFee: string; - agent: string; - auctionId: string; - - // transactgion.bridge* fields = null for single-chain orders - bridgeMetadata: BridgeMetadata | null; - bridgeStatus: BridgeStatus | null; - bridgeProtocol: string | null; - bridgeOverride: Pick | null; -}; - export type OnChainOrderMap = { Order: DeltaAuctionOrder; + FillableOrder: DeltaAuctionOrder; ExternalOrder: ExternalDeltaOrder; TWAPOrder: TWAPDeltaOrder; TWAPBuyOrder: TWAPBuyDeltaOrder; + ProductiveOrder: ProductiveDeltaOrder; }; -type BaseBridgeAuctionFields = Pick< - DeltaAuctionBase, - 'bridgeMetadata' | 'bridgeStatus' ->; - -type BridgeAuctionFiledsMap = { - Order: BaseBridgeAuctionFields; - ExternalOrder: BaseBridgeAuctionFields; - TWAPOrder: Record; - TWAPBuyOrder: Record; -}; - -type DeltaAuctionBase = { - id: string; - deltaVersion: string; // 1.0 or 2.0 currently - user: string; - status: DeltaAuctionStatus; - orderHash: string | null; // not available on old Orders only - transactions: DeltaAuctionTransaction[]; - chainId: number; - partner: string; - referrerAddress: string | null; - expiresAt: string; - createdAt: string; - updatedAt: string; - partiallyFillable: boolean; - - excludeAgents: string[] | null; - includeAgents: string[] | null; - - // bridge* fields = null for single-chain orders and all TWAP orders - bridgeMetadata: BridgeMetadata | null; - bridgeStatus: BridgeStatus | null; - - type: 'MARKET' | 'LIMIT'; -}; - -export type DeltaAuction = - T extends T - ? Prettify< - DeltaAuctionBase & { - onChainOrderType: T; - order: OnChainOrderMap[T]; - } & BridgeAuctionFiledsMap[T] - > - : never; - -export type DeltaAuctionDelta = DeltaAuction<'Order'>; -export type DeltaAuctionExternal = DeltaAuction<'ExternalOrder'>; -export type DeltaAuctionTWAP = DeltaAuction<'TWAPOrder'>; -export type DeltaAuctionTWAPBuy = DeltaAuction<'TWAPBuyOrder'>; - -export type DeltaAuctionUnion = - | DeltaAuctionDelta - | DeltaAuctionExternal - | DeltaAuctionTWAP - | DeltaAuctionTWAPBuy; - export type DeltaOrderUnion = OnChainOrderMap[keyof OnChainOrderMap]; -export type BridgeMetadata = { - /** @description The amount that user should expect to get */ - outputAmount: string; - /** @description The cross-chain deadline. If deadline passes, the bridgeStatus would be expired */ - fillDeadline?: number; // available for Across protocol - /** @description The deposit id */ - depositId?: number; // available for Across protocol - /** @description The transaction hash on the destination chain that fulfilled the order. When bridgeStatus='filled' */ - fillTx?: string; - /** @description The transaction hash on the source chain that refunded the deposit. When bridgeStatus='refunded' */ - depositRefundTxHash?: string; -}; - -// refunded is basically failed -export type BridgeStatus = 'pending' | 'filled' | 'expired' | 'refunded'; - -export type OnChainOrderType = - | 'Order' - | 'ExternalOrder' - | 'TWAPOrder' - | 'TWAPBuyOrder'; +export type OnChainOrderType = keyof OnChainOrderMap; export type TWAPOnChainOrderType = 'TWAPOrder' | 'TWAPBuyOrder'; -//// available on BridgePrice //// - -type BridgeQuoteFee = { - feeToken: string; - amount: string; - amountInSrcToken: string; - amountInUSD: string; -}; - -export type BridgePriceInfo = { - protocolName: string; - destAmountAfterBridge: string; - destUSDAfterBridge: string; - fees: BridgeQuoteFee[]; - estimatedTimeMs: number; - fastest: boolean; - bestReturn: boolean; - recommended: boolean; -}; +/** @description Order kind: MARKET (immediate) vs LIMIT (rate-pegged). */ +export type DeltaOrderType = 'MARKET' | 'LIMIT'; export type UnifiedDeltaOrderData = { /** @description amounts at the start of Order execution and after Order execution. May differ from each other */ diff --git a/src/methods/delta/index.ts b/src/methods/delta/index.ts index dd0a1452f..4b56c7ba3 100644 --- a/src/methods/delta/index.ts +++ b/src/methods/delta/index.ts @@ -1,31 +1,11 @@ import type { ConstructProviderFetchInput } from '../../types'; -import type { DeltaAuction } from './helpers/types'; -import { - BuildDeltaOrderDataParams, - BuildDeltaOrderFunctions, - constructBuildDeltaOrder, -} from './buildDeltaOrder'; -import { - constructPostDeltaOrder, - DeltaOrderToPost, - PostDeltaOrderFunctions, -} from './postDeltaOrder'; -import { - constructSignDeltaOrder, - SignDeltaOrderFunctions, -} from './signDeltaOrder'; +import type { DeltaAuction } from './types'; + +// reused v1 modules import { GetDeltaContractFunctions, constructGetDeltaContract, } from './getDeltaContract'; -import { - constructGetDeltaPrice, - GetDeltaPriceFunctions, -} from './getDeltaPrice'; -import { - constructGetDeltaOrders, - GetDeltaOrdersFunctions, -} from './getDeltaOrders'; import { constructGetPartnerFee, GetPartnerFeeFunctions, @@ -34,64 +14,122 @@ import { ApproveTokenForDeltaFunctions, constructApproveTokenForDelta, } from './approveForDelta'; -import { - constructGetBridgeInfo, - GetBridgeInfoFunctions, -} from './getBridgeInfo'; -import { - constructIsTokenSupportedInDelta, - IsTokenSupportedInDeltaFunctions, -} from './isTokenSupportedInDelta'; -import { - CancelDeltaOrderFunctions, - constructCancelDeltaOrder, -} from './cancelDeltaOrder'; import { constructPreSignDeltaOrder, PreSignDeltaOrderFunctions, } from './preSignDeltaOrder'; +import { + constructPreSignExternalDeltaOrder, + PreSignExternalDeltaOrderFunctions, +} from './preSignExternalDeltaOrder'; +import { + constructPreSignTWAPDeltaOrder, + PreSignTWAPDeltaOrderFunctions, +} from './preSignTWAPDeltaOrder'; import { DeltaTokenModuleFunctions, constructDeltaTokenModule, } from './deltaTokenModule'; + +// new v2 modules +import { + BuildDeltaOrderFunctions, + BuildDeltaOrderParams, + BuiltDeltaOrder, + constructBuildDeltaOrder, +} from './buildDeltaOrder'; import { - BuildExternalDeltaOrderParams, BuildExternalDeltaOrderFunctions, + BuildExternalDeltaOrderParams, constructBuildExternalDeltaOrder, } from './buildExternalDeltaOrder'; import { - constructSignExternalDeltaOrder, - SignExternalDeltaOrderFunctions, -} from './signExternalDeltaOrder'; -import { - constructPostExternalDeltaOrder, - PostExternalDeltaOrderFunctions, -} from './postExternalDeltaOrder'; -import { - constructPreSignExternalDeltaOrder, - PreSignExternalDeltaOrderFunctions, -} from './preSignExternalDeltaOrder'; -import { - BuildTWAPDeltaOrderParams, BuildTWAPDeltaOrderFunctions, + BuildTWAPDeltaOrderParams, constructBuildTWAPDeltaOrder, } from './buildTWAPDeltaOrder'; import { - constructSignTWAPDeltaOrder, - SignTWAPDeltaOrderFunctions, -} from './signTWAPDeltaOrder'; + constructPostDeltaOrder, + DeltaOrderToPost, + PostDeltaOrderFunctions, +} from './postDeltaOrder'; +import { + constructPostExternalDeltaOrder, + PostExternalDeltaOrderFunctions, +} from './postExternalDeltaOrder'; import { constructPostTWAPDeltaOrder, PostTWAPDeltaOrderFunctions, } from './postTWAPDeltaOrder'; import { - constructPreSignTWAPDeltaOrder, - PreSignTWAPDeltaOrderFunctions, -} from './preSignTWAPDeltaOrder'; + constructGetDeltaPrice, + GetDeltaPriceFunctions, +} from './getDeltaPrice'; +import { + constructGetDeltaOrders, + GetDeltaOrdersFunctions, +} from './getDeltaOrders'; +import { + constructGetBridgeRoutes, + GetBridgeRoutesFunctions, +} from './getBridgeRoutes'; +import { + constructIsTokenSupportedInDelta, + IsTokenSupportedInDeltaFunctions, +} from './isTokenSupportedInDelta'; +import { + CancelDeltaOrderFunctions, + constructCancelDeltaOrder, +} from './cancelDeltaOrder'; +import { + constructGetAgentsList, + GetAgentsListFunctions, +} from './getAgentsList'; + +// Re-export the public surface so consumers can reach every leaf module. +export * from './types'; +export * from './buildDeltaOrder'; +export * from './buildExternalDeltaOrder'; +export * from './buildTWAPDeltaOrder'; +export * from './postDeltaOrder'; +export * from './postExternalDeltaOrder'; +export * from './postTWAPDeltaOrder'; +export * from './getDeltaPrice'; +export * from './getDeltaOrders'; +export * from './getBridgeRoutes'; +export * from './isTokenSupportedInDelta'; +export * from './cancelDeltaOrder'; +export * from './getAgentsList'; +export { OrderHelpers } from './helpers/orders'; + +// ── Sign v2 ───────────────────────────────────────────────────────────────── + +type SignDeltaOrder = (builtOrder: BuiltDeltaOrder) => Promise; + +export type SignDeltaOrderFunctions = { + /** @description Sign a BuiltDeltaOrder (any order type) using EIP-712 typed data. */ + signDeltaOrder: SignDeltaOrder; +}; -export type SubmitDeltaOrderParams = BuildDeltaOrderDataParams & { - /** @description designates the Order as being able to be partially filled, as opposed to fill-or-kill */ - partiallyFillable?: boolean; +export const constructSignDeltaOrder = ( + options: Pick< + ConstructProviderFetchInput, + 'contractCaller' + > +): SignDeltaOrderFunctions => { + const signDeltaOrder: SignDeltaOrder = async (builtOrder) => { + return options.contractCaller.signTypedDataCall({ + types: builtOrder.toSign.types, + domain: builtOrder.toSign.domain, + data: builtOrder.toSign.value, + }); + }; + return { signDeltaOrder }; +}; + +// ── Submit orchestrators ───────────────────────────────────────────────────── + +export type SubmitDeltaOrderParams = BuildDeltaOrderParams & { /** @description Referrer address */ referrerAddress?: string; degenMode?: boolean; @@ -109,7 +147,6 @@ export const constructSubmitDeltaOrder = ( options: ConstructProviderFetchInput ): SubmitDeltaOrderFuncs => { const { buildDeltaOrder } = constructBuildDeltaOrder(options); - // in the normal submitOrderFlow preSign tx is not involved const { signDeltaOrder } = constructSignDeltaOrder(options); const { postDeltaOrder } = constructPostDeltaOrder(options); @@ -117,10 +154,10 @@ export const constructSubmitDeltaOrder = ( const orderData = await buildDeltaOrder(orderParams); const signature = await signDeltaOrder(orderData); - const response = await postDeltaOrder({ + return postDeltaOrder({ signature, partner: orderParams.partner, - order: orderData.data, + order: orderData.toSign.value, partiallyFillable: orderParams.partiallyFillable, referrerAddress: orderParams.referrerAddress, type: orderParams.type, @@ -128,17 +165,12 @@ export const constructSubmitDeltaOrder = ( excludeAgents: orderParams.excludeAgents, degenMode: orderParams.degenMode, }); - - return response; }; return { submitDeltaOrder }; }; export type SubmitExternalDeltaOrderParams = BuildExternalDeltaOrderParams & { - /** @description designates the Order as being able to be partially filled, as opposed to fill-or-kill */ - partiallyFillable?: boolean; - /** @description Referrer address */ referrerAddress?: string; } & Pick; @@ -154,36 +186,31 @@ export const constructSubmitExternalDeltaOrder = ( options: ConstructProviderFetchInput ): SubmitExternalDeltaOrderFuncs => { const { buildExternalDeltaOrder } = constructBuildExternalDeltaOrder(options); - const { signExternalDeltaOrder } = constructSignExternalDeltaOrder(options); + const { signDeltaOrder } = constructSignDeltaOrder(options); const { postExternalDeltaOrder } = constructPostExternalDeltaOrder(options); const submitExternalDeltaOrder: SubmitExternalDeltaOrder = async ( orderParams ) => { const orderData = await buildExternalDeltaOrder(orderParams); - const signature = await signExternalDeltaOrder(orderData); + const signature = await signDeltaOrder(orderData); - const response = await postExternalDeltaOrder({ + return postExternalDeltaOrder({ signature, partner: orderParams.partner, - order: orderData.data, + order: orderData.toSign.value, partiallyFillable: orderParams.partiallyFillable, referrerAddress: orderParams.referrerAddress, type: orderParams.type, includeAgents: orderParams.includeAgents, excludeAgents: orderParams.excludeAgents, }); - - return response; }; return { submitExternalDeltaOrder }; }; export type SubmitTWAPDeltaOrderParams = BuildTWAPDeltaOrderParams & { - /** @description designates the Order as being able to be partially filled, as opposed to fill-or-kill */ - partiallyFillable?: boolean; - /** @description Referrer address */ referrerAddress?: string; degenMode?: boolean; } & Pick; @@ -200,17 +227,17 @@ export const constructSubmitTWAPDeltaOrder = ( options: ConstructProviderFetchInput ): SubmitTWAPDeltaOrderFuncs => { const { buildTWAPDeltaOrder } = constructBuildTWAPDeltaOrder(options); - const { signTWAPDeltaOrder } = constructSignTWAPDeltaOrder(options); + const { signDeltaOrder } = constructSignDeltaOrder(options); const { postTWAPDeltaOrder } = constructPostTWAPDeltaOrder(options); const submitTWAPDeltaOrder: SubmitTWAPDeltaOrder = async (orderParams) => { const orderData = await buildTWAPDeltaOrder(orderParams); - const signature = await signTWAPDeltaOrder(orderData); + const signature = await signDeltaOrder(orderData); - const response = await postTWAPDeltaOrder({ + return postTWAPDeltaOrder({ signature, partner: orderParams.partner, - order: orderData.data, + order: orderData.toSign.value, onChainOrderType: orderParams.onChainOrderType, partiallyFillable: orderParams.partiallyFillable, referrerAddress: orderParams.referrerAddress, @@ -219,39 +246,38 @@ export const constructSubmitTWAPDeltaOrder = ( excludeAgents: orderParams.excludeAgents, degenMode: orderParams.degenMode, }); - - return response; }; return { submitTWAPDeltaOrder }; }; -export type DeltaOrderHandlers = SubmitDeltaOrderFuncs & - ApproveTokenForDeltaFunctions & - BuildDeltaOrderFunctions & - GetDeltaOrdersFunctions & - GetDeltaPriceFunctions & - GetDeltaContractFunctions & - GetPartnerFeeFunctions & - GetBridgeInfoFunctions & - IsTokenSupportedInDeltaFunctions & - PostDeltaOrderFunctions & - SignDeltaOrderFunctions & - PreSignDeltaOrderFunctions & - CancelDeltaOrderFunctions & - DeltaTokenModuleFunctions & +// ── Handler bundle ─────────────────────────────────────────────────────────── + +export type DeltaOrderHandlers = SubmitDeltaOrderFuncs & SubmitExternalDeltaOrderFuncs & - BuildExternalDeltaOrderFunctions & - SignExternalDeltaOrderFunctions & - PostExternalDeltaOrderFunctions & - PreSignExternalDeltaOrderFunctions & SubmitTWAPDeltaOrderFuncs & + BuildDeltaOrderFunctions & + BuildExternalDeltaOrderFunctions & BuildTWAPDeltaOrderFunctions & - SignTWAPDeltaOrderFunctions & + PostDeltaOrderFunctions & + PostExternalDeltaOrderFunctions & PostTWAPDeltaOrderFunctions & - PreSignTWAPDeltaOrderFunctions; + SignDeltaOrderFunctions & + PreSignDeltaOrderFunctions & + PreSignExternalDeltaOrderFunctions & + PreSignTWAPDeltaOrderFunctions & + GetDeltaPriceFunctions & + GetDeltaOrdersFunctions & + GetBridgeRoutesFunctions & + IsTokenSupportedInDeltaFunctions & + GetAgentsListFunctions & + GetDeltaContractFunctions & + GetPartnerFeeFunctions & + ApproveTokenForDeltaFunctions & + DeltaTokenModuleFunctions & + CancelDeltaOrderFunctions; -/** @description construct SDK with every Delta Order-related method, fetching from API and Order signing */ +/** @description Construct an SDK bundle exposing every Delta v2 method (queries, build/sign/post, on-chain helpers). */ export const constructAllDeltaOrdersHandlers = ( options: ConstructProviderFetchInput< TxResponse, @@ -263,15 +289,17 @@ export const constructAllDeltaOrdersHandlers = ( const deltaPrice = constructGetDeltaPrice(options); const partnerFee = constructGetPartnerFee(options); - const bridgeInfo = constructGetBridgeInfo(options); + const bridgeRoutes = constructGetBridgeRoutes(options); const isTokenSupportedInDelta = constructIsTokenSupportedInDelta(options); + const agentsList = constructGetAgentsList(options); const approveTokenForDelta = constructApproveTokenForDelta(options); - const deltaOrdersSubmit = constructSubmitDeltaOrder(options); + // single signer for every order family + const deltaOrdersSign = constructSignDeltaOrder(options); + const deltaOrdersSubmit = constructSubmitDeltaOrder(options); const deltaOrdersBuild = constructBuildDeltaOrder(options); - const deltaOrdersSign = constructSignDeltaOrder(options); const deltaOrdersPreSign = constructPreSignDeltaOrder(options); const deltaOrdersPost = constructPostDeltaOrder(options); @@ -281,14 +309,12 @@ export const constructAllDeltaOrdersHandlers = ( const externalDeltaOrdersSubmit = constructSubmitExternalDeltaOrder(options); const externalDeltaOrdersBuild = constructBuildExternalDeltaOrder(options); - const externalDeltaOrdersSign = constructSignExternalDeltaOrder(options); const externalDeltaOrdersPost = constructPostExternalDeltaOrder(options); const externalDeltaOrdersPreSign = constructPreSignExternalDeltaOrder(options); const twapDeltaOrdersSubmit = constructSubmitTWAPDeltaOrder(options); const twapDeltaOrdersBuild = constructBuildTWAPDeltaOrder(options); - const twapDeltaOrdersSign = constructSignTWAPDeltaOrder(options); const twapDeltaOrdersPost = constructPostTWAPDeltaOrder(options); const twapDeltaOrdersPreSign = constructPreSignTWAPDeltaOrder(options); @@ -297,24 +323,23 @@ export const constructAllDeltaOrdersHandlers = ( ...deltaOrdersContractGetter, ...deltaPrice, ...partnerFee, - ...bridgeInfo, + ...bridgeRoutes, ...isTokenSupportedInDelta, + ...agentsList, ...approveTokenForDelta, + ...deltaOrdersSign, ...deltaOrdersSubmit, ...deltaOrdersBuild, - ...deltaOrdersSign, ...deltaOrdersPreSign, ...deltaOrdersPost, ...deltaOrdersCancel, ...deltaTokenModule, ...externalDeltaOrdersSubmit, ...externalDeltaOrdersBuild, - ...externalDeltaOrdersSign, ...externalDeltaOrdersPost, ...externalDeltaOrdersPreSign, ...twapDeltaOrdersSubmit, ...twapDeltaOrdersBuild, - ...twapDeltaOrdersSign, ...twapDeltaOrdersPost, ...twapDeltaOrdersPreSign, }; diff --git a/src/methods/delta/isTokenSupportedInDelta.ts b/src/methods/delta/isTokenSupportedInDelta.ts index c0ae668ed..cc4c34375 100644 --- a/src/methods/delta/isTokenSupportedInDelta.ts +++ b/src/methods/delta/isTokenSupportedInDelta.ts @@ -6,8 +6,8 @@ import type { RequestParameters, } from '../../types'; -type TokenSupportedInDeltaResponse = { supported: boolean }; -type IsTokenSupportedInDeltaQueryOptions = { +type TokenSupportedResponse = { supported: boolean }; +type IsTokenSupportedQuery = { token: Address; chainId: number; }; @@ -26,20 +26,20 @@ export const constructIsTokenSupportedInDelta = ({ chainId, fetcher, }: ConstructFetchInput): IsTokenSupportedInDeltaFunctions => { - const bridgeInfoUrl = `${apiURL}/delta/prices/is-token-supported` as const; + const baseUrl = `${apiURL}/v2/delta/prices/is-token-supported` as const; const isTokenSupportedInDelta: IsTokenSupportedInDelta = async ( token, requestParams ) => { - const search = constructSearchString({ + const search = constructSearchString({ token, chainId, }); - const fetchURL = `${bridgeInfoUrl}/${search}` as const; + const fetchURL = `${baseUrl}/${search}` as const; - const data = await fetcher({ + const data = await fetcher({ url: fetchURL, method: 'GET', requestParams, @@ -48,7 +48,5 @@ export const constructIsTokenSupportedInDelta = ({ return data.supported; }; - return { - isTokenSupportedInDelta, - }; + return { isTokenSupportedInDelta }; }; diff --git a/src/methods/delta/postDeltaOrder.ts b/src/methods/delta/postDeltaOrder.ts index 3956a32c5..ab37816c8 100644 --- a/src/methods/delta/postDeltaOrder.ts +++ b/src/methods/delta/postDeltaOrder.ts @@ -1,13 +1,10 @@ import { API_URL } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import type { - DeltaAuction, - OnChainOrderMap, - OnChainOrderType, -} from './helpers/types'; +import type { DeltaOrderType, OnChainOrderMap } from './helpers/types'; +import type { DeltaAuction } from './types'; -export type DeltaOrderToPost = { +export type DeltaOrderToPost = { /** @description Partner string */ partner?: string; /** @description Referrer address */ @@ -16,12 +13,10 @@ export type DeltaOrderToPost = { /** @description Signature of the order from order.owner address. EOA signatures must be submitted in ERC-2098 Compact Representation. */ signature: string; chainId: number; - /** @description designates the Order as being able to partially filled, as opposed to fill-or-kill */ + /** @description Designates the Order as being able to be partially filled, as opposed to fill-or-kill */ partiallyFillable?: boolean; - /** @description Type of the order. MARKET or LIMIT. Default is MARKET */ - type?: 'MARKET' | 'LIMIT'; - + type?: DeltaOrderType; includeAgents?: string[]; excludeAgents?: string[]; }; @@ -44,7 +39,7 @@ export const constructPostDeltaOrder = ({ chainId, fetcher, }: ConstructFetchInput): PostDeltaOrderFunctions => { - const postOrderUrl = `${apiURL}/delta/orders` as const; + const postOrderUrl = `${apiURL}/v2/delta/orders` as const; const postDeltaOrder: PostDeltaOrder = (_postData, requestParams) => { const { degenMode, ...postData } = _postData; @@ -53,7 +48,7 @@ export const constructPostDeltaOrder = ({ const search = constructSearchString<{ degenMode?: boolean }>({ degenMode, }); - const fetchURL = `${postOrderUrl}/${search}` as const; + const fetchURL = `${postOrderUrl}${search}` as const; return fetcher>({ url: fetchURL, diff --git a/src/methods/delta/postExternalDeltaOrder.ts b/src/methods/delta/postExternalDeltaOrder.ts index e3257d6d2..6616f4666 100644 --- a/src/methods/delta/postExternalDeltaOrder.ts +++ b/src/methods/delta/postExternalDeltaOrder.ts @@ -1,7 +1,7 @@ import { API_URL } from '../../constants'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import type { DeltaAuction } from './helpers/types'; import type { DeltaOrderToPost } from './postDeltaOrder'; +import type { DeltaAuction } from './types'; export type PostExternalDeltaOrderParams = Omit< DeltaOrderToPost<'ExternalOrder'>, @@ -22,7 +22,7 @@ export const constructPostExternalDeltaOrder = ({ chainId, fetcher, }: ConstructFetchInput): PostExternalDeltaOrderFunctions => { - const postOrderUrl = `${apiURL}/delta/orders` as const; + const postOrderUrl = `${apiURL}/v2/delta/orders` as const; const postExternalDeltaOrder: PostExternalDeltaOrder = ( postData, diff --git a/src/methods/delta/postTWAPDeltaOrder.ts b/src/methods/delta/postTWAPDeltaOrder.ts index ec2279758..5a3dbbb25 100644 --- a/src/methods/delta/postTWAPDeltaOrder.ts +++ b/src/methods/delta/postTWAPDeltaOrder.ts @@ -1,9 +1,10 @@ -import { Prettify } from 'ts-essentials'; +import type { Prettify } from 'ts-essentials'; import { API_URL } from '../../constants'; +import { constructSearchString } from '../../helpers/misc'; import type { ConstructFetchInput, RequestParameters } from '../../types'; -import type { DeltaAuction, TWAPOnChainOrderType } from './helpers/types'; +import type { TWAPOnChainOrderType } from './helpers/types'; import type { DeltaOrderToPost } from './postDeltaOrder'; -import { constructSearchString } from '../../helpers/misc'; +import type { DeltaAuction } from './types'; export type PostTWAPDeltaOrderParams = Prettify< Omit< @@ -30,7 +31,7 @@ export const constructPostTWAPDeltaOrder = ({ chainId, fetcher, }: ConstructFetchInput): PostTWAPDeltaOrderFunctions => { - const postOrderUrl = `${apiURL}/delta/orders` as const; + const postOrderUrl = `${apiURL}/v2/delta/orders` as const; const postTWAPDeltaOrder: PostTWAPDeltaOrder = (_postData, requestParams) => { const { degenMode, ...postData } = _postData; @@ -43,7 +44,7 @@ export const constructPostTWAPDeltaOrder = ({ degenMode, }); - const fetchURL = `${postOrderUrl}/${search}` as const; + const fetchURL = `${postOrderUrl}${search}` as const; return fetcher | DeltaAuction<'TWAPBuyOrder'>>({ url: fetchURL, diff --git a/src/methods/delta/preSignDeltaOrder.ts b/src/methods/delta/preSignDeltaOrder.ts index ab511dbe6..e2118526d 100644 --- a/src/methods/delta/preSignDeltaOrder.ts +++ b/src/methods/delta/preSignDeltaOrder.ts @@ -37,16 +37,24 @@ export type PreSignDeltaOrder = ( ) => Promise; export type PreSignDeltaOrderFunctions = { + /** @description Compute the EIP-712 order hash from already-built signable order data. Strips any extra fields off `data` before hashing; synchronous, no network call. */ hashDeltaOrderTypedData: HashDeltaOrderTypedData; + /** @description Resolve the Delta contract, build the EIP-712 typed data for the order, and return its order hash. */ hashDeltaOrder: HashDeltaOrder; + /** @description On-chain `setPreSignature(orderHash, true)` on the Delta contract — pre-approves an order hash so it can be filled without an EIP-712 signature. Returns whatever the `contractCaller` returns. */ setDeltaOrderPreSignature: SetDeltaOrderPreSignature; + /** @description Hash the signable order data and pre-sign it on-chain in one call (`hashDeltaOrderTypedData` → `setDeltaOrderPreSignature`). */ preSignDeltaOrder: PreSignDeltaOrder; }; type AvailableMethods = ExtractAbiMethodNames; -// returns whatever `contractCaller` returns -// to allow for better versatility +/** + * @description Construct on-chain pre-signing helpers for standard Delta orders: + * order hashing (`hashDeltaOrder` / `hashDeltaOrderTypedData`) and `setPreSignature` + * transactions (`setDeltaOrderPreSignature` / `preSignDeltaOrder`). The transact + * methods return whatever the configured `contractCaller` returns, for versatility. + */ export const constructPreSignDeltaOrder = ( options: ConstructProviderFetchInput ): PreSignDeltaOrderFunctions => { diff --git a/src/methods/delta/preSignExternalDeltaOrder.ts b/src/methods/delta/preSignExternalDeltaOrder.ts index 4095aa2a9..93be0e821 100644 --- a/src/methods/delta/preSignExternalDeltaOrder.ts +++ b/src/methods/delta/preSignExternalDeltaOrder.ts @@ -37,16 +37,25 @@ export type PreSignExternalDeltaOrder = ( ) => Promise; export type PreSignExternalDeltaOrderFunctions = { + /** @description Compute the EIP-712 order hash from already-built signable External order data. Strips any extra fields off `data` before hashing; synchronous, no network call. */ hashExternalDeltaOrderTypedData: HashExternalDeltaOrderTypedData; + /** @description Resolve the Delta contract, build the EIP-712 typed data for the External order, and return its order hash. */ hashExternalDeltaOrder: HashExternalDeltaOrder; + /** @description On-chain `setPreSignature(orderHash, true)` on the Delta contract — pre-approves an External order hash so it can be filled without an EIP-712 signature. Returns whatever the `contractCaller` returns. */ setExternalDeltaOrderPreSignature: SetExternalDeltaOrderPreSignature; + /** @description Hash the signable External order data and pre-sign it on-chain in one call (`hashExternalDeltaOrderTypedData` → `setExternalDeltaOrderPreSignature`). */ preSignExternalDeltaOrder: PreSignExternalDeltaOrder; }; type AvailableMethods = ExtractAbiMethodNames; -// returns whatever `contractCaller` returns -// to allow for better versatility +/** + * @description Construct on-chain pre-signing helpers for External Delta orders: + * order hashing (`hashExternalDeltaOrder` / `hashExternalDeltaOrderTypedData`) and + * `setPreSignature` transactions (`setExternalDeltaOrderPreSignature` / + * `preSignExternalDeltaOrder`). The transact methods return whatever the configured + * `contractCaller` returns, for versatility. + */ export const constructPreSignExternalDeltaOrder = ( options: ConstructProviderFetchInput ): PreSignExternalDeltaOrderFunctions => { diff --git a/src/methods/delta/preSignTWAPDeltaOrder.ts b/src/methods/delta/preSignTWAPDeltaOrder.ts index 17a03f9ea..691877a6a 100644 --- a/src/methods/delta/preSignTWAPDeltaOrder.ts +++ b/src/methods/delta/preSignTWAPDeltaOrder.ts @@ -47,14 +47,25 @@ export type PreSignTWAPDeltaOrder = ( ) => Promise; export type PreSignTWAPDeltaOrderFunctions = { + /** @description Compute the EIP-712 order hash from already-built signable TWAP order data. Strips any extra fields off `data` before hashing; synchronous, no network call. */ hashTWAPDeltaOrderTypedData: HashTWAPDeltaOrderTypedData; + /** @description Resolve the Delta contract, build the EIP-712 typed data for the TWAP order (`'TWAPOrder'` sell or `'TWAPBuyOrder'` buy), and return its order hash. */ hashTWAPDeltaOrder: HashTWAPDeltaOrder; + /** @description On-chain `setPreSignature(orderHash, true)` on the Delta contract — pre-approves a TWAP order hash so it can be filled without an EIP-712 signature. Returns whatever the `contractCaller` returns. */ setTWAPDeltaOrderPreSignature: SetTWAPDeltaOrderPreSignature; + /** @description Hash the signable TWAP order data and pre-sign it on-chain in one call (`hashTWAPDeltaOrderTypedData` → `setTWAPDeltaOrderPreSignature`). */ preSignTWAPDeltaOrder: PreSignTWAPDeltaOrder; }; type AvailableMethods = ExtractAbiMethodNames; +/** + * @description Construct on-chain pre-signing helpers for TWAP Delta orders (sell + * and buy): order hashing (`hashTWAPDeltaOrder` / `hashTWAPDeltaOrderTypedData`) and + * `setPreSignature` transactions (`setTWAPDeltaOrderPreSignature` / + * `preSignTWAPDeltaOrder`). The transact methods return whatever the configured + * `contractCaller` returns, for versatility. + */ export const constructPreSignTWAPDeltaOrder = ( options: ConstructProviderFetchInput ): PreSignTWAPDeltaOrderFunctions => { diff --git a/src/methods/delta/signDeltaOrder.ts b/src/methods/delta/signDeltaOrder.ts deleted file mode 100644 index cd13fea1d..000000000 --- a/src/methods/delta/signDeltaOrder.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { ConstructProviderFetchInput } from '../../types'; -import { SignableDeltaOrderData } from './helpers/buildDeltaOrderData'; -import { sanitizeDeltaOrderData } from './helpers/misc'; - -type SignDeltaOrder = ( - signableOrderData: SignableDeltaOrderData -) => Promise; - -export type SignDeltaOrderFunctions = { - signDeltaOrder: SignDeltaOrder; -}; - -// returns whatever `contractCaller` returns -// to allow for better versatility -export const constructSignDeltaOrder = ( - options: Pick< - ConstructProviderFetchInput, - 'contractCaller' - > -): SignDeltaOrderFunctions => { - const signDeltaOrder: SignDeltaOrder = async (typedData) => { - // types allow to pass OrderData & extra_stuff, but tx will break like that - const typedDataOnly: SignableDeltaOrderData = { - ...typedData, - data: sanitizeDeltaOrderData(typedData.data), - }; - const signature = await options.contractCaller.signTypedDataCall( - typedDataOnly - ); - - return signature; - }; - - return { signDeltaOrder }; -}; diff --git a/src/methods/delta/signExternalDeltaOrder.ts b/src/methods/delta/signExternalDeltaOrder.ts deleted file mode 100644 index 2fc4d6e11..000000000 --- a/src/methods/delta/signExternalDeltaOrder.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { ConstructProviderFetchInput } from '../../types'; -import { SignableExternalOrderData } from './helpers/buildExternalOrderData'; -import { sanitizeExternalOrderData } from './helpers/misc'; - -type SignExternalDeltaOrder = ( - signableOrderData: SignableExternalOrderData -) => Promise; - -export type SignExternalDeltaOrderFunctions = { - signExternalDeltaOrder: SignExternalDeltaOrder; -}; - -// returns whatever `contractCaller` returns -// to allow for better versatility -export const constructSignExternalDeltaOrder = ( - options: Pick< - ConstructProviderFetchInput, - 'contractCaller' - > -): SignExternalDeltaOrderFunctions => { - const signExternalDeltaOrder: SignExternalDeltaOrder = async (typedData) => { - // types allow to pass OrderData & extra_stuff, but tx will break like that - const typedDataOnly: SignableExternalOrderData = { - ...typedData, - data: sanitizeExternalOrderData(typedData.data), - }; - const signature = await options.contractCaller.signTypedDataCall( - typedDataOnly - ); - - return signature; - }; - - return { signExternalDeltaOrder }; -}; diff --git a/src/methods/delta/signTWAPDeltaOrder.ts b/src/methods/delta/signTWAPDeltaOrder.ts deleted file mode 100644 index 736491c79..000000000 --- a/src/methods/delta/signTWAPDeltaOrder.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { ConstructProviderFetchInput } from '../../types'; -import { SignableTWAPOrderData } from './helpers/buildTWAPOrderData'; -import { sanitizeTWAPOrderData } from './helpers/misc'; - -type SignTWAPDeltaOrder = ( - signableOrderData: SignableTWAPOrderData -) => Promise; - -export type SignTWAPDeltaOrderFunctions = { - signTWAPDeltaOrder: SignTWAPDeltaOrder; -}; - -export const constructSignTWAPDeltaOrder = ( - options: Pick< - ConstructProviderFetchInput, - 'contractCaller' - > -): SignTWAPDeltaOrderFunctions => { - const signTWAPDeltaOrder: SignTWAPDeltaOrder = async (typedData) => { - const typedDataOnly = { - ...typedData, - data: sanitizeTWAPOrderData(typedData.data), - } as SignableTWAPOrderData; - const signature = await options.contractCaller.signTypedDataCall( - typedDataOnly - ); - - return signature; - }; - - return { signTWAPDeltaOrder }; -}; diff --git a/src/methods/delta/types.ts b/src/methods/delta/types.ts new file mode 100644 index 000000000..bb80fa927 --- /dev/null +++ b/src/methods/delta/types.ts @@ -0,0 +1,211 @@ +import type { Prettify } from 'ts-essentials'; +import type { Address } from '../../types'; +import type { TypedDataField } from '../common/orders/buildOrderData'; +import type { + Bridge, + DeltaOrderType, + DeltaOrderUnion, + OnChainOrderMap, + OnChainOrderType, +} from './helpers/types'; + +/** @description Response from POST /v2/delta/orders/build — EIP-712 typed data ready to sign. */ +export type BuiltDeltaOrder = { + toSign: { + domain: { + name: string; + version: string; + chainId: number; + verifyingContract: string; + }; + /** EIP-712 type definitions keyed by type name. */ + types: Record; + /** The on-chain order struct value to sign. */ + value: T; + }; + /** EIP-712 order hash. */ + orderHash: string; +}; + +/** @description Token identity used across v2 endpoints. */ +export type DeltaPriceToken = { + chainId: number; + address: Address; +}; + +/** @description A token amount with its USD value, used uniformly for inputs, outputs, and fees. */ +export type DeltaTokenAmount = { + token: DeltaPriceToken; + /** @description Amount in wei. */ + amount: string; + /** @description USD value of the amount. */ + amountUSD: string; +}; + +/** @description Bridge tag used to mark routes as recommended / fastest / best-return. */ +export type BridgeTag = 'recommended' | 'fastest' | 'best-return'; + +/** @description Subset of the on-chain Bridge struct returned in v2 price responses. + * (the full `route` object is passed to the server when building an order). */ +export type DeltaRouteBridgeContractParams = Omit; + +/** @description Bridge details on a route. Same-chain routes carry `null` for `route.bridge`. */ +export type DeltaRouteBridge = { + /** @description Bridge protocol identifier (e.g. "Across", "Relay", "Mayan"). */ + protocol: string; + /** @description Estimated bridging time in milliseconds. */ + estimatedTimeMs: number; + /** @description Tags for this route ("recommended", "fastest", "best-return"). May be empty. */ + tags: BridgeTag[]; + /** @description Bridge contract parameters as returned by the server. */ + contractParams: DeltaRouteBridgeContractParams; +}; + +/** @description A single step of a route (origin chain or destination chain). */ +export type DeltaRouteStep = { + /** @description The token amount entering this step (before any per-step swap). */ + input: DeltaTokenAmount; + /** @description The token amount exiting this step (after any per-step swap). */ + output: DeltaTokenAmount; +}; + +/** @description A route describes how the swap flows from origin chain to destination chain. */ +export type DeltaRoute = { + /** @description Source-chain step. The on-chain Delta order's amounts come from `origin.input` and `origin.output`. */ + origin: DeltaRouteStep; + /** @description Destination-chain step. For same-chain routes this mirrors `origin`. */ + destination: DeltaRouteStep; + /** @description Bridge details. `null` for same-chain routes. */ + bridge: DeltaRouteBridge | null; + /** @description Fee breakdown for this route. */ + fees: { + /** @description Gas fee (single DeltaTokenAmount on the source chain). */ + gas: DeltaTokenAmount; + /** @description Bridge fees (empty array for same-chain). */ + bridge: DeltaTokenAmount[]; + }; +}; + +/** @description v2 price response: route-based, cross-chain first. */ +export type DeltaPrice = { + /** @description Unique request ID for tracing. */ + id: string; + /** @description Order side. */ + side: 'SELL' | 'BUY'; + /** @description Token the user trades (identity only — amounts live in route.origin.input). */ + inputToken: DeltaPriceToken; + /** @description Token the user receives (identity only — amounts live in route.destination.output). */ + outputToken: DeltaPriceToken; + /** @description Recommended route with full amounts and bridge details. */ + route: DeltaRoute; + /** @description Partner info attached to this price. */ + partner: { + name: string; + /** @description Partner fee in percent (e.g. 0.12 = 0.12%). */ + feePercent: number; + }; + /** @description Address to approve for spending the input token. */ + spender: Address; + /** @description Alternative routes (other bridges). Each is a full DeltaRoute. */ + alternatives: DeltaRoute[]; +}; + +/** @description + * A flat bridge-routes entry returned by GET /v2/delta/prices/bridge-routes (better version of v1 prices/bridge-info). + * Can be used to populate bridge selection UIs and to validate that bridge is possible for a given src/dest pair before calling GET /v2/delta/prices. + * */ +export type BridgeRoute = { + srcChainId: number; + destChainId: number; + /** @description Output tokens supported on the dest chain for this src→dest pair. */ + tokens: Address[]; +}; + +/* ------------------------------------------------------------------ */ +/* Orders v2 response shape: DeltaAuction, same generic shape as */ +/* v1's DeltaAuction but with v2 base fields. */ +/* ------------------------------------------------------------------ */ + +/** @description Integrator-facing order status returned by v2 order endpoints. */ +const DeltaOrderStatusMap = { + Pending: 'PENDING', + AwaitingSignature: 'AWAITING_SIGNATURE', + Active: 'ACTIVE', + Suspended: 'SUSPENDED', + Cancelling: 'CANCELLING', + Bridging: 'BRIDGING', + Completed: 'COMPLETED', + Failed: 'FAILED', + Expired: 'EXPIRED', + Cancelled: 'CANCELLED', + Refunded: 'REFUNDED', + Refunding: 'REFUNDING', +} as const; + +export type DeltaOrderStatus = + (typeof DeltaOrderStatusMap)[keyof typeof DeltaOrderStatusMap]; + +/** @description Token side on an order. SELL provides an explicit `amount`; BUY provides expected/executed amounts. */ +export type DeltaTokenSide = + | { + chainId: number; + token: Address; + amount: string; + } + | { + chainId: number; + token: Address; + expectedAmount: string | null; + executedAmount: string | null; + }; + +/** @description A single transaction entry on a v2 order. */ +export type DeltaTransaction = { + originTx: string; + destinationTx: string | null; + /** @description Filled percent of the slice (0–100). */ + filledPercent: number; + spentAmount: string | null; + receivedAmount: string | null; +}; + +export type BridgeRefundMetadata = { + tx: string; + chainId: number; + token: Address; + amount: string; +}; + +type DeltaAuctionBase = { + id: string; + status: DeltaOrderStatus; + side: 'SELL' | 'BUY'; + type: DeltaOrderType; + input: DeltaTokenSide; + output: DeltaTokenSide; + owner: Address; + beneficiary: Address; + orderHash: string; + partner: string; + transactions: DeltaTransaction[]; + refunds: BridgeRefundMetadata[]; + /** @description ISO datetime string. */ + createdAt: string; + /** @description ISO datetime string. */ + updatedAt: string; + /** @description ISO datetime string. */ + expiresAt: string; +}; + +/** @description Order shape returned by GET /v2/orders, /v2/orders/:id, /v2/orders/hash/:hash. + * Generic over `onChainOrderType` like v1's `DeltaAuction`: the type distributes over the + * union so that `order` narrows to the matching family (`OnChainOrderMap[T]`). */ +export type DeltaAuction = + T extends T + ? Prettify< + DeltaAuctionBase & { + onChainOrderType: T; + order: OnChainOrderMap[T]; + } + > + : never; diff --git a/src/methods/limitOrders/approveForOrder.ts b/src/methods/limitOrders/approveForOrder.ts deleted file mode 100644 index 95584b2dd..000000000 --- a/src/methods/limitOrders/approveForOrder.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ConstructProviderFetchInput } from '../../types'; -import { ApproveToken, approveTokenMethodFactory } from '../../helpers/approve'; -import { constructApproveToken } from '../swap/approve'; -import { constructGetSpender } from '../swap/spender'; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type ApproveTokenForLimitOrderFunctions = { - /** @description approving AugustusRFQ as spender for makerAsset */ - approveMakerTokenForLimitOrder: ApproveToken; - /** @description approving AugustusRFQ as spender for takerAsset to call SDK.fillOrderDirectly */ - approveTakerTokenForFillingP2POrderDirectly: ApproveToken; - /** @description approving AugustusSwapper as spender for takerAsset for Limit Orders that will be executed through it */ - approveTakerTokenForLimitOrder: ApproveToken; -}; - -// returns whatever `contractCaller` returns -// to allow for better versatility -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructApproveTokenForLimitOrder = ( - options: ConstructProviderFetchInput -): ApproveTokenForLimitOrderFunctions => { - // getAugustusRFQ is cached internally for the same instance of SDK - // so should persist across same apiUrl & network - const { getAugustusRFQ } = constructGetSpender(options); - - const approveMakerTokenForLimitOrder: ApproveToken = - approveTokenMethodFactory(options.contractCaller, getAugustusRFQ); - - // approving TokenTransaferProxy as for the swap - const { approveToken: approveTakerTokenForLimitOrder } = - constructApproveToken(options); - - return { - approveMakerTokenForLimitOrder, - approveTakerTokenForFillingP2POrderDirectly: approveMakerTokenForLimitOrder, - approveTakerTokenForLimitOrder, - }; -}; diff --git a/src/methods/limitOrders/getOrdersContract.ts b/src/methods/limitOrders/getOrdersContract.ts deleted file mode 100644 index ae7c32018..000000000 --- a/src/methods/limitOrders/getOrdersContract.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ConstructFetchInput } from '../../types'; -import { constructGetSpender, GetSpender } from '../swap/spender'; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type GetLimitOrdersContractFunctions = { - getLimitOrdersContract: GetSpender; - getTokenTransferProxy: GetSpender; -}; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructGetLimitOrdersContract = ( - options: ConstructFetchInput -): GetLimitOrdersContractFunctions => { - // analogous to getSpender() but for Limit Orders Contract = AugustusRFQ - - const { - getSpender: getTokenTransferProxy, - getAugustusRFQ: getLimitOrdersContract, - } = constructGetSpender(options); - - return { getLimitOrdersContract, getTokenTransferProxy }; -}; diff --git a/src/methods/limitOrders/index.ts b/src/methods/limitOrders/index.ts deleted file mode 100644 index 624860c48..000000000 --- a/src/methods/limitOrders/index.ts +++ /dev/null @@ -1,160 +0,0 @@ -import type { - ConstructProviderFetchInput, - RequestParameters, -} from '../../types'; -import type { LimitOrderToSend, LimitOrderFromApi } from './helpers/types'; -import { - BuildLimitOrderFunctions, - BuildLimitOrderInput, - constructBuildLimitOrder, -} from './buildOrder'; -import { - CancelLimitOrderFunctions, - constructCancelLimitOrder, -} from './cancelOrder'; -import { constructGetLimitOrders, GetLimitOrdersFunctions } from './getOrders'; -import { constructPostLimitOrder, PostLimitOrderFunctions } from './postOrder'; -import { constructSignLimitOrder, SignLimitOrderFunctions } from './signOrder'; -import { - constructApproveTokenForLimitOrder, - ApproveTokenForLimitOrderFunctions, -} from './approveForOrder'; -import { - GetLimitOrdersContractFunctions, - constructGetLimitOrdersContract, -} from './getOrdersContract'; -import { - BuildLimitOrdersTxFunctions, - constructBuildLimitOrderTx, -} from './transaction'; -import type { Address } from '@paraswap/core'; -import { - FillOrderDirectlyFunctions, - constructFillOrderDirectly, -} from './fillOrderDirectly'; - -type SubmitLimitOrder = ( - buildLimitOrderParams: BuildLimitOrderInput, - extra?: { permitMakerAsset?: string }, - requestParams?: RequestParameters -) => Promise; - -type SubmitP2POrder = ( - buildLimitOrderParams: BuildLimitOrderInput & { taker: Address }, - extra?: { permitMakerAsset?: string }, - requestParams?: RequestParameters -) => Promise; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type SubmitLimitOrderFuncs = { - submitLimitOrder: SubmitLimitOrder; - submitP2POrder: SubmitP2POrder; -}; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructSubmitLimitOrder = ( - options: ConstructProviderFetchInput -): SubmitLimitOrderFuncs => { - const { buildLimitOrder } = constructBuildLimitOrder(options); - const { signLimitOrder } = constructSignLimitOrder(options); - const { postLimitOrder, postP2POrder } = constructPostLimitOrder(options); - - const prepareLimitOrder = async ( - buildLimitOrderParams: BuildLimitOrderInput, - extra?: { permitMakerAsset?: string } - ): Promise => { - const orderData = await buildLimitOrder(buildLimitOrderParams); - const signature = await signLimitOrder(orderData); - - const orderWithSignature: LimitOrderToSend = { - ...orderData.data, - ...extra, - signature, - }; - - return orderWithSignature; - }; - - const submitLimitOrder: SubmitLimitOrder = async ( - buildLimitOrderParams, - extra = {}, - requestParams - ) => { - const orderWithSignature: LimitOrderToSend = await prepareLimitOrder( - buildLimitOrderParams, - extra - ); - - const newOrder = await postLimitOrder(orderWithSignature, requestParams); - - return newOrder; - }; - - const submitP2POrder: SubmitP2POrder = async ( - buildLimitOrderParams, - extra = {}, - requestParams - ) => { - const orderWithSignature: LimitOrderToSend = await prepareLimitOrder( - buildLimitOrderParams, - extra - ); - - const newOrder = await postP2POrder(orderWithSignature, requestParams); - - return newOrder; - }; - - return { submitLimitOrder, submitP2POrder }; -}; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type LimitOrderHandlers = SubmitLimitOrderFuncs & - BuildLimitOrderFunctions & - SignLimitOrderFunctions & - PostLimitOrderFunctions & - GetLimitOrdersFunctions & - GetLimitOrdersContractFunctions & - BuildLimitOrdersTxFunctions & - CancelLimitOrderFunctions & - ApproveTokenForLimitOrderFunctions & - FillOrderDirectlyFunctions; - -/** - * @description construct SDK with every LimitOrders-related method, fetching from API and contract calls - * @deprecated Limit Orders are deprecated and will be removed in a future version. - */ -export const constructAllLimitOrdersHandlers = ( - options: ConstructProviderFetchInput< - TxResponse, - 'signTypedDataCall' | 'transactCall' | 'staticCall' - > -): LimitOrderHandlers => { - const limitOrdersGetters = constructGetLimitOrders(options); - const limitOrdersContractGetter = constructGetLimitOrdersContract(options); - - const limitOrdersSubmit = constructSubmitLimitOrder(options); - const limitOrdersBuild = constructBuildLimitOrder(options); - const limitOrdersSign = constructSignLimitOrder(options); - const limitOrdersPost = constructPostLimitOrder(options); - - const limitOrdersCancel = constructCancelLimitOrder(options); - const limitOrdersApproveToken = constructApproveTokenForLimitOrder(options); - - const limitOrdersFillOrderDirectly = constructFillOrderDirectly(options); - - const limitOrdersBuildTx = constructBuildLimitOrderTx(options); - - return { - ...limitOrdersGetters, - ...limitOrdersContractGetter, - ...limitOrdersSubmit, - ...limitOrdersBuild, - ...limitOrdersSign, - ...limitOrdersPost, - ...limitOrdersCancel, - ...limitOrdersApproveToken, - ...limitOrdersFillOrderDirectly, - ...limitOrdersBuildTx, - }; -}; diff --git a/src/methods/limitOrders/postOrder.ts b/src/methods/limitOrders/postOrder.ts deleted file mode 100644 index 1ef8b973d..000000000 --- a/src/methods/limitOrders/postOrder.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { API_URL } from '../../constants'; -import type { ConstructFetchInput, RequestParameters } from '../../types'; -import { constructBaseFetchUrlGetter, PostOrderURLs } from './helpers/misc'; -import type { - LimitOrderApiResponse, - LimitOrderToSend, - LimitOrderFromApi, - LimitOrderType, -} from './helpers/types'; - -type PostLimitOrder = ( - limitOrderWithSignatureAndPermit: LimitOrderToSend, - requestParams?: RequestParameters -) => Promise; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type PostLimitOrderFunctions = { - postLimitOrder: PostLimitOrder; - postP2POrder: PostLimitOrder; -}; - -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructPostLimitOrder = ({ - apiURL = API_URL, - chainId, - fetcher, -}: ConstructFetchInput): PostLimitOrderFunctions => { - const getBaseFetchURLByOrderType = constructBaseFetchUrlGetter({ - apiURL, - chainId, - }); - - const postTypedOrder = async ( - limitOrderWithSignatureAndPermit: LimitOrderToSend, - type: LimitOrderType, - requestParams?: RequestParameters - ): Promise => { - const fetchURL = getBaseFetchURLByOrderType(type); - - const { order: newOrder } = await fetcher< - LimitOrderApiResponse, - PostOrderURLs - >({ - url: fetchURL, - method: 'POST', - data: limitOrderWithSignatureAndPermit, - requestParams, - }); - - return newOrder; - }; - - const postLimitOrder: PostLimitOrder = ( - limitOrderWithSignatureAndPermit, - requestParams - ) => { - return postTypedOrder( - limitOrderWithSignatureAndPermit, - 'LIMIT', - requestParams - ); - }; - - const postP2POrder: PostLimitOrder = ( - limitOrderWithSignatureAndPermit, - requestParams - ) => { - return postTypedOrder( - limitOrderWithSignatureAndPermit, - 'P2P', - requestParams - ); - }; - - return { postLimitOrder, postP2POrder }; -}; diff --git a/src/methods/nftOrders/cancelOrder.ts b/src/methods/nftOrders/cancelOrder.ts index ef70de7f7..a8b21348d 100644 --- a/src/methods/nftOrders/cancelOrder.ts +++ b/src/methods/nftOrders/cancelOrder.ts @@ -2,8 +2,8 @@ import type { ConstructProviderFetchInput } from '../../types'; import { CancelOrder, CancelOrderBulk, - constructCancelLimitOrder, -} from '../limitOrders/cancelOrder'; + constructCancelOTCOrder, +} from '../otcOrders/cancelOrder'; /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ export type CancelNFTOrderFunctions = { @@ -11,15 +11,15 @@ export type CancelNFTOrderFunctions = { cancelNFTOrderBulk: CancelOrderBulk; }; -// should work the same as for LimitOrders +// should work the same as for OTC Orders /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ export const constructCancelNFTOrder = ( options: ConstructProviderFetchInput ): CancelNFTOrderFunctions => { - const { cancelLimitOrder, cancelLimitOrderBulk } = - constructCancelLimitOrder(options); + const { cancelOTCOrder, cancelOTCOrdersBulk } = + constructCancelOTCOrder(options); return { - cancelNFTOrder: cancelLimitOrder, - cancelNFTOrderBulk: cancelLimitOrderBulk, + cancelNFTOrder: cancelOTCOrder, + cancelNFTOrderBulk: cancelOTCOrdersBulk, }; }; diff --git a/src/methods/nftOrders/getOrdersContract.ts b/src/methods/nftOrders/getOrdersContract.ts index dab457f81..e5c7ace80 100644 --- a/src/methods/nftOrders/getOrdersContract.ts +++ b/src/methods/nftOrders/getOrdersContract.ts @@ -7,7 +7,7 @@ export type GetNFTOrdersContractFunctions = { getTokenTransferProxy: GetSpender; }; -// should work the same as LimitOrders +// should work the same as OTCOrders /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ export const constructGetNFTOrdersContract = ( options: ConstructFetchInput diff --git a/src/methods/nftOrders/helpers/types.ts b/src/methods/nftOrders/helpers/types.ts index 1eea54a67..7b58e00ac 100644 --- a/src/methods/nftOrders/helpers/types.ts +++ b/src/methods/nftOrders/helpers/types.ts @@ -1,10 +1,7 @@ import type { Address } from '../../../types'; -import { OrderTransaction } from '../../common/orders/types'; import type { NFTOrderData } from './buildOrderData'; import type { AssetType } from './misc'; -export type NFTOrderTransaction = OrderTransaction; - export type NFTOrderType = 'LIMIT' | 'P2P'; export type NFTOrderToSend = NFTOrderData & { @@ -34,8 +31,6 @@ export type NFTOrderFromAPI = NFTOrderToSend & { type: NFTOrderType; /** @description transaction with the last event pertaining to the order: OrderFilled or OrderCancelled */ transactionHash: null | string; - // not yet returned - // transactions: NftOrderTransaction[]; }; export type NFTOrdersApiResponse = { diff --git a/src/methods/nftOrders/transaction.ts b/src/methods/nftOrders/transaction.ts index 4cb8c43a2..e9e3213e9 100644 --- a/src/methods/nftOrders/transaction.ts +++ b/src/methods/nftOrders/transaction.ts @@ -18,6 +18,7 @@ import { constructGetRate, GetRateInput, RateOptions } from '../swap/rates'; import type { BigIntAsString, NFTOrderData } from './buildOrder'; import { isFilledArray } from '../../helpers/misc'; import type { RequestParameters } from '../../types'; + type MinBuildSwapAndNFTOrderTxInput = Omit< // these are derived from `orders` BuildSwapAndNFTOrderTxInput, diff --git a/src/methods/otcOrders/approveForOrder.ts b/src/methods/otcOrders/approveForOrder.ts new file mode 100644 index 000000000..8641c9484 --- /dev/null +++ b/src/methods/otcOrders/approveForOrder.ts @@ -0,0 +1,30 @@ +import type { ConstructProviderFetchInput } from '../../types'; +import { ApproveToken, approveTokenMethodFactory } from '../../helpers/approve'; +import { constructGetSpender } from '../swap/spender'; + +export type ApproveTokenForOTCOrderFunctions = { + /** @description approving AugustusRFQ as spender for makerAsset */ + approveMakerTokenForOTCOrder: ApproveToken; + /** @description approving AugustusRFQ as spender for takerAsset to call SDK.fillOrderDirectly */ + approveTakerTokenForOTCOrder: ApproveToken; +}; + +// returns whatever `contractCaller` returns +// to allow for better versatility +export const constructApproveTokenForOTCOrder = ( + options: ConstructProviderFetchInput +): ApproveTokenForOTCOrderFunctions => { + // getAugustusRFQ is cached internally for the same instance of SDK + // so should persist across same apiUrl & network + const { getAugustusRFQ } = constructGetSpender(options); + + const approveTokenForOTCOrder: ApproveToken = approveTokenMethodFactory( + options.contractCaller, + getAugustusRFQ + ); + + return { + approveMakerTokenForOTCOrder: approveTokenForOTCOrder, + approveTakerTokenForOTCOrder: approveTokenForOTCOrder, + }; +}; diff --git a/src/methods/limitOrders/buildOrder.ts b/src/methods/otcOrders/buildOrder.ts similarity index 63% rename from src/methods/limitOrders/buildOrder.ts rename to src/methods/otcOrders/buildOrder.ts index fe3eefb49..f3f3b919d 100644 --- a/src/methods/limitOrders/buildOrder.ts +++ b/src/methods/otcOrders/buildOrder.ts @@ -8,35 +8,32 @@ import { } from './helpers/buildOrderData'; export * from './helpers/buildOrderData'; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type BuildLimitOrderInput = Omit< +export type BuildOTCOrderInput = Omit< BuildOrderDataInput, 'chainId' | 'verifyingContract' | 'AugustusAddress' | 'AppVersion' >; -type BuildLimitOrder = ( - buildLimitOrderParams: BuildLimitOrderInput, +type BuildOTCOrder = ( + buildOTCOrderParams: BuildOTCOrderInput, requestParams?: RequestParameters ) => Promise; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type BuildLimitOrderFunctions = { +export type BuildOTCOrderFunctions = { /** @description Build Orders that will be excuted through AugustusSwapper */ - buildLimitOrder: BuildLimitOrder; + buildOTCOrder: BuildOTCOrder; }; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructBuildLimitOrder = ( +export const constructBuildOTCOrder = ( options: ConstructFetchInput -): BuildLimitOrderFunctions => { +): BuildOTCOrderFunctions => { const { chainId } = options; // getContracts is cached internally for the same instance of SDK // so should persist across same apiUrl & network const { getContracts } = constructGetSpender(options); - const buildLimitOrder: BuildLimitOrder = async ( - buildLimitOrderParams, + const buildOTCOrder: BuildOTCOrder = async ( + buildOTCOrderParams, requestParams ) => { const { AugustusSwapper: AugustusAddress, AugustusRFQ: verifyingContract } = @@ -45,7 +42,7 @@ export const constructBuildLimitOrder = ( const AppVersion = options.version ?? DEFAULT_VERSION; return buildOrderData({ - ...buildLimitOrderParams, + ...buildOTCOrderParams, chainId, verifyingContract, AugustusAddress, @@ -54,6 +51,6 @@ export const constructBuildLimitOrder = ( }; return { - buildLimitOrder, + buildOTCOrder, }; }; diff --git a/src/methods/limitOrders/cancelOrder.ts b/src/methods/otcOrders/cancelOrder.ts similarity index 81% rename from src/methods/limitOrders/cancelOrder.ts rename to src/methods/otcOrders/cancelOrder.ts index 65dbe3eec..84639c072 100644 --- a/src/methods/limitOrders/cancelOrder.ts +++ b/src/methods/otcOrders/cancelOrder.ts @@ -18,10 +18,9 @@ export type CancelOrderBulk = ( requestParams?: RequestParameters ) => Promise; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type CancelLimitOrderFunctions = { - cancelLimitOrder: CancelOrder; - cancelLimitOrderBulk: CancelOrderBulk; +export type CancelOTCOrderFunctions = { + cancelOTCOrder: CancelOrder; + cancelOTCOrdersBulk: CancelOrderBulk; }; // much smaller than the whole AugustusRFQ_ABI @@ -58,15 +57,14 @@ type AvailableMethods = ExtractAbiMethodNames; // returns whatever `contractCaller` returns // to allow for better versatility -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructCancelLimitOrder = ( +export const constructCancelOTCOrder = ( options: ConstructProviderFetchInput -): CancelLimitOrderFunctions => { +): CancelOTCOrderFunctions => { // getAugustusRFQ is cached internally for the same instance of SDK // so should persist across same apiUrl & network const { getAugustusRFQ } = constructGetSpender(options); - const cancelLimitOrder: CancelOrder = async ( + const cancelOTCOrder: CancelOrder = async ( orderHash, overrides = {}, requestParams @@ -86,7 +84,7 @@ export const constructCancelLimitOrder = ( return res; }; - const cancelLimitOrderBulk: CancelOrderBulk = async ( + const cancelOTCOrdersBulk: CancelOrderBulk = async ( orderHashes, overrides = {}, requestParams @@ -107,7 +105,7 @@ export const constructCancelLimitOrder = ( }; return { - cancelLimitOrder, - cancelLimitOrderBulk, + cancelOTCOrder, + cancelOTCOrdersBulk, }; }; diff --git a/src/methods/limitOrders/fillOrderDirectly.ts b/src/methods/otcOrders/fillOrderDirectly.ts similarity index 93% rename from src/methods/limitOrders/fillOrderDirectly.ts rename to src/methods/otcOrders/fillOrderDirectly.ts index 177f30adb..23c07d44b 100644 --- a/src/methods/limitOrders/fillOrderDirectly.ts +++ b/src/methods/otcOrders/fillOrderDirectly.ts @@ -12,9 +12,8 @@ import { encodeEIP_2612PermitFunctionInput, } from '../common/orders/encoding'; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type FillOrderDirectlyFunctions = { - fillOrderDirectly: FillOrderDirectly; +export type FillOTCOrderFunctions = { + fillOTCOrder: FillOTCOrcer; }; type TakerPermitEncodedInputParams = { @@ -40,7 +39,7 @@ type TakerPermitObject = | TakerPermit1Data | TakerDaiPermitData; -export type FillOrderDirectly = ( +export type FillOTCOrcer = ( orderFillData: { order: OrderData; signature: string; @@ -205,15 +204,14 @@ type FillOrderMethods = ExtractAbiMethodNames; // returns whatever `contractCaller` returns // to allow for better versatility -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export function constructFillOrderDirectly( +export function constructFillOTCOrder( options: ConstructProviderFetchInput -): FillOrderDirectlyFunctions { +): FillOTCOrderFunctions { // getAugustusRFQ is cached internally for the same instance of SDK // so should persist across same apiUrl & network const { getAugustusRFQ } = constructGetSpender(options); - const fillOrderDirectly: FillOrderDirectly = async ( + const fillOTCOrder: FillOTCOrcer = async ( { order, signature, takerPermit }, overrides = {}, requestParams @@ -275,5 +273,5 @@ export function constructFillOrderDirectly( return res; }; - return { fillOrderDirectly }; + return { fillOTCOrder }; } diff --git a/src/methods/limitOrders/getOrders.ts b/src/methods/otcOrders/getOrders.ts similarity index 71% rename from src/methods/limitOrders/getOrders.ts rename to src/methods/otcOrders/getOrders.ts index b59db93c4..4ff84ae32 100644 --- a/src/methods/limitOrders/getOrders.ts +++ b/src/methods/otcOrders/getOrders.ts @@ -1,5 +1,3 @@ -// @TODO getOrder, getOrders from API -// onchain from contract can't distinguish between filled or cancelled import { API_URL } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; import type { @@ -13,11 +11,7 @@ import { GetOrderURL, GetRequiredAllowanceURL as GetRequiredBalanceURL, } from './helpers/misc'; -import type { - LimitOrderFromApi, - LimitOrdersApiResponse, - LimitOrderType, -} from './helpers/types'; +import type { OTCOrderFromApi, OTCOrdersApiResponse } from './helpers/types'; type PaginationParams = { limit?: number; @@ -27,10 +21,7 @@ type PaginationParams = { }; // get orders by `maker` or `taker` -export type LimitOrdersUserParams = ( - | { maker: Address; type: LimitOrderType } - | { taker: Address; type: LimitOrderType } -) & +export type OTCOrdersUserParams = ({ maker: Address } | { taker: Address }) & PaginationParams; export type GetRequiredAllowanceParams = { @@ -38,24 +29,23 @@ export type GetRequiredAllowanceParams = { token?: Address; }; -type GetLimitOrderByHash = ( +type GetOTCOrderByHash = ( orderHash: string, requestParams?: RequestParameters -) => Promise; -type GetLimitOrders = ( - userParams: LimitOrdersUserParams, +) => Promise; +type GetOTCOrders = ( + userParams: OTCOrdersUserParams, requestParams?: RequestParameters -) => Promise; +) => Promise; type GetRequiredBalance = ( userParams: GetRequiredAllowanceParams, requestParams?: RequestParameters ) => Promise>; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type GetLimitOrdersFunctions = { - getLimitOrders: GetLimitOrders; - getLimitOrderByHash: GetLimitOrderByHash; +export type GetOTCOrdersFunctions = { + getOTCOrders: GetOTCOrders; + getOTCOrderByHash: GetOTCOrderByHash; /** * Gets fillableBalance for tokens from user's active orders. * User needs to have enough balance & allowance to cover active orders before creating new orders. @@ -68,19 +58,18 @@ export type GetLimitOrdersFunctions = { getRequiredBalance: GetRequiredBalance; }; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructGetLimitOrders = ({ +export const constructGetOTCOrders = ({ apiURL = API_URL, chainId, fetcher, -}: ConstructFetchInput): GetLimitOrdersFunctions => { +}: ConstructFetchInput): GetOTCOrdersFunctions => { const getBaseFetchURLByEntityType = constructBaseFetchUrlGetter({ apiURL, chainId, }); - const getLimitOrders: GetLimitOrders = async (userParams, requestParams) => { - const baseFetchURL = getBaseFetchURLByEntityType(userParams.type); + const getOTCOrders: GetOTCOrders = async (userParams, requestParams) => { + const baseFetchURL = getBaseFetchURLByEntityType('P2P'); const userURL = 'maker' in userParams ? (`maker/${userParams.maker}` as const) @@ -96,7 +85,7 @@ export const constructGetLimitOrders = ({ const fetchURL = `${baseFetchURL}/${userURL}${search}` as const; - const response = await fetcher({ + const response = await fetcher({ url: fetchURL, method: 'GET', requestParams, @@ -129,14 +118,14 @@ export const constructGetLimitOrders = ({ return response; }; - const getLimitOrderByHash: GetLimitOrderByHash = async ( + const getOTCOrderByHash: GetOTCOrderByHash = async ( orderHash, requestParams ) => { const baseFetchURL = getBaseFetchURLByEntityType(); const fetchURL = `${baseFetchURL}/${orderHash}` as const; - const order = await fetcher({ + const order = await fetcher({ url: fetchURL, method: 'GET', requestParams, @@ -146,8 +135,8 @@ export const constructGetLimitOrders = ({ }; return { - getLimitOrders, - getLimitOrderByHash, + getOTCOrders, + getOTCOrderByHash, getRequiredBalance, }; }; diff --git a/src/methods/otcOrders/getOrdersContract.ts b/src/methods/otcOrders/getOrdersContract.ts new file mode 100644 index 000000000..b043a4b9c --- /dev/null +++ b/src/methods/otcOrders/getOrdersContract.ts @@ -0,0 +1,20 @@ +import type { ConstructFetchInput } from '../../types'; +import { constructGetSpender, GetSpender } from '../swap/spender'; + +export type GetOTCOrdersContractFunctions = { + getOTCOrdersContract: GetSpender; + getTokenTransferProxy: GetSpender; +}; + +export const constructGetOTCOrdersContract = ( + options: ConstructFetchInput +): GetOTCOrdersContractFunctions => { + // analogous to getSpender() but for OTC Orders Contract = AugustusRFQ + + const { + getSpender: getTokenTransferProxy, + getAugustusRFQ: getOTCOrdersContract, + } = constructGetSpender(options); + + return { getOTCOrdersContract, getTokenTransferProxy }; +}; diff --git a/src/methods/limitOrders/helpers/buildOrderData.ts b/src/methods/otcOrders/helpers/buildOrderData.ts similarity index 90% rename from src/methods/limitOrders/helpers/buildOrderData.ts rename to src/methods/otcOrders/helpers/buildOrderData.ts index 7e9adbb08..2c7bb324f 100644 --- a/src/methods/limitOrders/helpers/buildOrderData.ts +++ b/src/methods/otcOrders/helpers/buildOrderData.ts @@ -28,10 +28,10 @@ export interface BuildOrderDataInput { makerAmount: string; takerAmount: string; maker: Address; - // OrderData.taker must be Augustus (or other Executor) for p2p limitOrders to involve swap through Augustus + // OrderData.taker must be Augustus (or other Executor) for p2p OTCOrders to involve swap through Augustus /** @description actual user taker which will go into nonceAndMeta */ - taker?: Address; - /** @description contract executor (Augustus or similar) that is allowed to execute the order, gois in Order.taker */ + taker: Address; + /** @description contract executor (Augustus or similar) that is allowed to execute the order, goes in Order.taker */ contractTaker?: Address; AugustusAddress: Address; @@ -67,7 +67,7 @@ export function buildOrderData({ maker, AugustusAddress, // if taker is specified -- p2p order for that taker only to fill through Augustus (v5) or directly (v6)-- taker = Augustus | _taker, takerInNonce = _taker - // if taker is not specified -- limitOrder for anyone to fill through Augustus or not -- taker = Zero, takerInNonce = Zero + // if taker is not specified -- OTC Order for anyone to fill through Augustus or not -- taker = Zero, takerInNonce = Zero taker: takerInNonce = ZERO_ADDRESS, // if given, overrides the above choices made based on `taker` contractTaker, @@ -75,7 +75,7 @@ export function buildOrderData({ AppVersion, }: BuildOrderDataInput): SignableOrderData { // first 160 bits is taker address (for p2p orders), - // or 0 for limitOrders, so that anyone can be the taker of the Order + // or 0 for OTC Orders, so that anyone can be the taker of the Order const nonceAndMeta = ( BigInt(takerInNonce) + (BigInt(nonce) << BigInt(160)) diff --git a/src/methods/limitOrders/helpers/misc.ts b/src/methods/otcOrders/helpers/misc.ts similarity index 100% rename from src/methods/limitOrders/helpers/misc.ts rename to src/methods/otcOrders/helpers/misc.ts diff --git a/src/methods/limitOrders/helpers/types.ts b/src/methods/otcOrders/helpers/types.ts similarity index 70% rename from src/methods/limitOrders/helpers/types.ts rename to src/methods/otcOrders/helpers/types.ts index 486b9a95a..678e9b3b8 100644 --- a/src/methods/limitOrders/helpers/types.ts +++ b/src/methods/otcOrders/helpers/types.ts @@ -1,33 +1,32 @@ -import { OrderTransaction } from '../../common/orders/types'; import type { OrderData } from './buildOrderData'; -export type LimitOrderType = 'LIMIT' | 'P2P'; +export type OTCOrderType = 'P2P'; -export type LimitOrder = LimitOrderFromApi; +export type OTCOrder = OTCOrderFromApi; -export type LimitOrderToSend = OrderData & { +export type OTCOrderToPost = OrderData & { permitMakerAsset?: string; signature: string; }; -export type LimitOrdersApiResponse = { +export type OTCOrdersApiResponse = { limit: number; offset: number; total: number; hasMore: boolean; - orders: LimitOrderFromApi[]; + orders: OTCOrderFromApi[]; }; -export type LimitOrderApiResponse = { - order: LimitOrderFromApi; +export type OTCOrderApiResponse = { + order: OTCOrderFromApi; }; // display states such as EXPIRED and PARTIALLY_FILLLED derived on client side // returned by API but can be calculated too, EXPIRED == order.expiry < Date.now()/1000 // PARTIALLY_FILLED == order.fillableBalance < order.makerAmount && order.fillableBalance !== '0' -// SUSPENDED status was introduced for Limit orders to indicate that orders where makers lacked sufficient funds +// SUSPENDED status was introduced for OTC orders to indicate that orders where makers lacked sufficient funds // to fulfill them would no longer be tracked. This status is similar to CANCELLED, but it reduces any ambiguity that might // arise when debugging or when users view their CANCELLED orders. -export type LimitOrderState = +export type OTCOrderState = | 'DRAFT' | 'PENDING' | 'FULFILLED' @@ -35,11 +34,7 @@ export type LimitOrderState = | 'SUSPENDED' | 'EXPIRED'; -export type LimitOrderEvent = ''; - -export type LimitOrderTransaction = OrderTransaction; - -export type LimitOrderFromApi = { +export type OTCOrderFromApi = { chainId: number; nonceAndMeta: string; // uiint expiry: number; // timestamp @@ -55,12 +50,10 @@ export type LimitOrderFromApi = { orderHash: string; // hex string createdAt: number; // timestamp updatedAt: number; // timestamp - state: LimitOrderState; + state: OTCOrderState; /** @description transaction with the last event pertaining to the order: OrderFilled or OrderCancelled */ transactionHash: null | string; - // not yet returned - // transactions: LimitOrderTransaction[]; - type: LimitOrderType; + type: OTCOrderType; takerFromMeta: string; // the intended receiver, eg receiving address of p2p order where `taker` would be augustus fillableBalance: string; // amount that remains to be filled reservedBalance: string; // amount that is currently reserved in this order diff --git a/src/methods/otcOrders/index.ts b/src/methods/otcOrders/index.ts new file mode 100644 index 000000000..ce178bcb0 --- /dev/null +++ b/src/methods/otcOrders/index.ts @@ -0,0 +1,134 @@ +import type { + ConstructProviderFetchInput, + RequestParameters, +} from '../../types'; +import type { OTCOrderToPost, OTCOrderFromApi } from './helpers/types'; +import { + BuildOTCOrderFunctions, + BuildOTCOrderInput, + constructBuildOTCOrder, +} from './buildOrder'; +import { + CancelOTCOrderFunctions, + constructCancelOTCOrder, +} from './cancelOrder'; +import { constructGetOTCOrders, GetOTCOrdersFunctions } from './getOrders'; +import { constructPostOTCOrder, PostOTCOrderFunctions } from './postOrder'; +import { constructSignOTCOrder, SignOTCOrderFunctions } from './signOrder'; +import { + constructApproveTokenForOTCOrder, + ApproveTokenForOTCOrderFunctions, +} from './approveForOrder'; +import { + GetOTCOrdersContractFunctions, + constructGetOTCOrdersContract, +} from './getOrdersContract'; +import { + BuildOTCOrdersTxFunctions, + constructBuildOTCOrderTx, +} from './transaction'; +import type { Address } from '@paraswap/core'; +import { + FillOTCOrderFunctions, + constructFillOTCOrder, +} from './fillOrderDirectly'; + +type SubmitOTCOrder = ( + buildOTCOrderParams: BuildOTCOrderInput & { taker: Address }, + extra?: { permitMakerAsset?: string }, + requestParams?: RequestParameters +) => Promise; + +export type SubmitOTCOrderFuncs = { + submitOTCOrder: SubmitOTCOrder; +}; + +export const constructSubmitOTCOrder = ( + options: ConstructProviderFetchInput +): SubmitOTCOrderFuncs => { + const { buildOTCOrder } = constructBuildOTCOrder(options); + const { signOTCOrder } = constructSignOTCOrder(options); + const { postOTCOrder } = constructPostOTCOrder(options); + + const prepareOTCOrder = async ( + buildOTCOrderParams: BuildOTCOrderInput, + extra?: { permitMakerAsset?: string } + ): Promise => { + const orderData = await buildOTCOrder(buildOTCOrderParams); + const signature = await signOTCOrder(orderData); + + const orderWithSignature: OTCOrderToPost = { + ...orderData.data, + ...extra, + signature, + }; + + return orderWithSignature; + }; + + const submitOTCOrder: SubmitOTCOrder = async ( + buildOTCOrderParams, + extra = {}, + requestParams + ) => { + const orderWithSignature: OTCOrderToPost = await prepareOTCOrder( + buildOTCOrderParams, + extra + ); + + const newOrder = await postOTCOrder(orderWithSignature, requestParams); + + return newOrder; + }; + + return { submitOTCOrder }; +}; + +export type OTCOrderHandlers = SubmitOTCOrderFuncs & + BuildOTCOrderFunctions & + SignOTCOrderFunctions & + PostOTCOrderFunctions & + GetOTCOrdersFunctions & + GetOTCOrdersContractFunctions & + BuildOTCOrdersTxFunctions & + CancelOTCOrderFunctions & + ApproveTokenForOTCOrderFunctions & + FillOTCOrderFunctions; + +/** + * @description construct SDK with every OTCOrders-related method, fetching from API and contract calls + */ +export const constructAllOTCOrdersHandlers = ( + options: ConstructProviderFetchInput< + TxResponse, + 'signTypedDataCall' | 'transactCall' | 'staticCall' + > +): OTCOrderHandlers => { + const OTCOrdersGetters = constructGetOTCOrders(options); + const OTCOrdersContractGetter = constructGetOTCOrdersContract(options); + + const OTCOrdersSubmit = constructSubmitOTCOrder(options); + const OTCOrdersBuild = constructBuildOTCOrder(options); + const OTCOrdersSign = constructSignOTCOrder(options); + const OTCOrdersPost = constructPostOTCOrder(options); + + const OTCOrdersCancel = constructCancelOTCOrder(options); + const OTCOrdersApproveToken = constructApproveTokenForOTCOrder(options); + + const OTCOrdersFillOrderDirectly = constructFillOTCOrder(options); + + const OTCOrdersBuildTx = constructBuildOTCOrderTx(options); + + return { + ...OTCOrdersGetters, + ...OTCOrdersContractGetter, + ...OTCOrdersSubmit, + ...OTCOrdersBuild, + ...OTCOrdersSign, + ...OTCOrdersPost, + ...OTCOrdersCancel, + ...OTCOrdersApproveToken, + ...OTCOrdersFillOrderDirectly, + ...OTCOrdersBuildTx, + }; +}; diff --git a/src/methods/otcOrders/postOrder.ts b/src/methods/otcOrders/postOrder.ts new file mode 100644 index 000000000..18905768d --- /dev/null +++ b/src/methods/otcOrders/postOrder.ts @@ -0,0 +1,58 @@ +import { API_URL } from '../../constants'; +import type { ConstructFetchInput, RequestParameters } from '../../types'; +import { constructBaseFetchUrlGetter, PostOrderURLs } from './helpers/misc'; +import type { + OTCOrderApiResponse, + OTCOrderToPost, + OTCOrderFromApi, + OTCOrderType, +} from './helpers/types'; + +type PostOTCOrder = ( + OTCOrderWithSignatureAndPermit: OTCOrderToPost, + requestParams?: RequestParameters +) => Promise; + +export type PostOTCOrderFunctions = { + postOTCOrder: PostOTCOrder; +}; + +export const constructPostOTCOrder = ({ + apiURL = API_URL, + chainId, + fetcher, +}: ConstructFetchInput): PostOTCOrderFunctions => { + const getBaseFetchURLByOrderType = constructBaseFetchUrlGetter({ + apiURL, + chainId, + }); + + const postTypedOrder = async ( + OTCOrderWithSignatureAndPermit: OTCOrderToPost, + type: OTCOrderType, + requestParams?: RequestParameters + ): Promise => { + const fetchURL = getBaseFetchURLByOrderType(type); + + const { order: newOrder } = await fetcher< + OTCOrderApiResponse, + PostOrderURLs + >({ + url: fetchURL, + method: 'POST', + data: OTCOrderWithSignatureAndPermit, + requestParams, + }); + + return newOrder; + }; + + const postOTCOrder: PostOTCOrder = ( + OTCOrderWithSignatureAndPermit, + requestParams + ) => { + return postTypedOrder(OTCOrderWithSignatureAndPermit, 'P2P', requestParams); + }; + + return { postOTCOrder }; +}; diff --git a/src/methods/limitOrders/signOrder.ts b/src/methods/otcOrders/signOrder.ts similarity index 56% rename from src/methods/limitOrders/signOrder.ts rename to src/methods/otcOrders/signOrder.ts index c66e999be..c217bcf4b 100644 --- a/src/methods/limitOrders/signOrder.ts +++ b/src/methods/otcOrders/signOrder.ts @@ -2,23 +2,19 @@ import type { ConstructProviderFetchInput } from '../../types'; import type { SignableOrderData } from './buildOrder'; import { sanitizeOrderData } from './helpers/misc'; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type SignLimitOrderFunctions = { - signLimitOrder: (signableOrderData: SignableOrderData) => Promise; +export type SignOTCOrderFunctions = { + signOTCOrder: (signableOrderData: SignableOrderData) => Promise; }; // returns whatever `contractCaller` returns // to allow for better versatility -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructSignLimitOrder = ( +export const constructSignOTCOrder = ( options: Pick< ConstructProviderFetchInput, 'contractCaller' > -): SignLimitOrderFunctions => { - const signLimitOrder: SignLimitOrderFunctions['signLimitOrder'] = ( - typedData - ) => { +): SignOTCOrderFunctions => { + const signOTCOrder: SignOTCOrderFunctions['signOTCOrder'] = (typedData) => { // types allow to pass OrderData & extra_stuff, but tx will break like that const typedDataOnly: SignableOrderData = { ...typedData, @@ -27,5 +23,5 @@ export const constructSignLimitOrder = ( return options.contractCaller.signTypedDataCall(typedDataOnly); }; - return { signLimitOrder }; + return { signOTCOrder }; }; diff --git a/src/methods/limitOrders/transaction.ts b/src/methods/otcOrders/transaction.ts similarity index 78% rename from src/methods/limitOrders/transaction.ts rename to src/methods/otcOrders/transaction.ts index 99f9c759a..39d4ffdd7 100644 --- a/src/methods/limitOrders/transaction.ts +++ b/src/methods/otcOrders/transaction.ts @@ -8,9 +8,9 @@ import { DEFAULT_VERSION, } from '../../constants'; import { - BuildLimitOrderTxInput, + BuildOTCOrderTxInput, BuildOptions, - BuildSwapAndLimitOrderTxInput, + BuildSwapAndOTCOrderTxInput, TransactionParams, constructBuildTx, } from '../swap/transaction'; @@ -19,52 +19,50 @@ import type { OrderData } from './buildOrder'; import { isFilledArray } from '../../helpers/misc'; import type { RequestParameters } from '../../types'; -type MinBuildSwapAndLimitOrderTxInput = Omit< +type MinBuildSwapAndOTCOrderTxInput = Omit< // these are derived from `orders` - BuildSwapAndLimitOrderTxInput, + BuildSwapAndOTCOrderTxInput, 'srcToken' | 'srcAmount' | 'destToken' | 'destDecimals' >; -type BuildSwapAndLimitOrdersTx = ( - params: MinBuildSwapAndLimitOrderTxInput, +type BuildSwapAndOTCOrdersTx = ( + params: MinBuildSwapAndOTCOrderTxInput, options?: BuildOptions, requestParams?: RequestParameters ) => Promise; -type MinBuildLimitOrderTxInput = Omit< - BuildLimitOrderTxInput, +type MinBuildOTCOrderTxInput = Omit< + BuildOTCOrderTxInput, // these are derived from `orders` 'srcToken' | 'srcAmount' | 'destToken' | 'slippage' // `slippage` doesn't participate as we derive `srcAmount` already >; -type BuildLimitOrdersTx = ( - params: MinBuildLimitOrderTxInput, +type BuildOTCOrdersTx = ( + params: MinBuildOTCOrderTxInput, options?: BuildOptions, requestParams?: RequestParameters ) => Promise; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type BuildLimitOrdersTxFunctions = { - getLimitOrdersRate: GetLimitOrdersRate; - buildLimitOrderTx: BuildLimitOrdersTx; - buildSwapAndLimitOrderTx: BuildSwapAndLimitOrdersTx; +export type BuildOTCOrdersTxFunctions = { + getOTCOrdersRate: GetOTCOrdersRate; + buildOTCOrderTx: BuildOTCOrdersTx; + buildSwapAndOTCOrderTx: BuildSwapAndOTCOrdersTx; }; -type GetLimitOrdersRate = ( +type GetOTCOrdersRate = ( // `amount`, if given, must equal the total of the orders' `takerAmounts` options: Omit & { amount?: string }, orders: CheckableOrderData[], requestParams?: RequestParameters ) => Promise; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export const constructBuildLimitOrderTx = ({ +export const constructBuildOTCOrderTx = ({ apiURL = API_URL, version = DEFAULT_VERSION, chainId, fetcher, -}: ConstructFetchInput): BuildLimitOrdersTxFunctions => { +}: ConstructFetchInput): BuildOTCOrdersTxFunctions => { const { buildTx: buildSwapTx } = constructBuildTx({ apiURL, chainId, @@ -72,15 +70,15 @@ export const constructBuildLimitOrderTx = ({ version, }); - const { getRate: getSwapAndLimitOrderRate } = constructGetRate({ + const { getRate: getSwapAndOTCOrderRate } = constructGetRate({ apiURL, version, chainId, fetcher, }); - // returns priceRoute that would allow to swap from srcToken to destToken(=order.takerAsset) followed by filling limit orders - const getLimitOrdersRate: GetLimitOrdersRate = async ( + // returns priceRoute that would allow to swap from srcToken to destToken(=order.takerAsset) followed by filling OTC orders + const getOTCOrdersRate: GetOTCOrdersRate = async ( { srcToken, destToken, amount, options: _options = {}, ...rest }, orders, requestParams @@ -120,15 +118,12 @@ export const constructBuildLimitOrderTx = ({ }; // priceRoute - const optimalRate = await getSwapAndLimitOrderRate( - rateInput, - requestParams - ); + const optimalRate = await getSwapAndOTCOrderRate(rateInput, requestParams); return optimalRate; }; // derive srcToken, destToken and srcAmount from orders[] - const buildLimitOrderTx: BuildLimitOrdersTx = ( + const buildOTCOrderTx: BuildOTCOrdersTx = ( params, options, requestParams @@ -137,7 +132,7 @@ export const constructBuildLimitOrderTx = ({ params.orders ); - const fillParams: BuildLimitOrderTxInput = { + const fillParams: BuildOTCOrderTxInput = { ...params, // taker supplies takerAsset srcToken: takerAsset, @@ -150,14 +145,14 @@ export const constructBuildLimitOrderTx = ({ return buildSwapTx(fillParams, options, requestParams); }; - const buildSwapAndLimitOrderTx: BuildSwapAndLimitOrdersTx = ( + const buildSwapAndOTCOrderTx: BuildSwapAndOTCOrdersTx = ( params, options, requestParams ) => { const { makerAsset } = checkAndParseOrders(params.orders); - const fillParams: BuildSwapAndLimitOrderTxInput = { + const fillParams: BuildSwapAndOTCOrderTxInput = { ...params, // taker supplies srcToken srcToken: params.priceRoute.srcToken, @@ -175,9 +170,9 @@ export const constructBuildLimitOrderTx = ({ }; return { - getLimitOrdersRate, - buildLimitOrderTx, - buildSwapAndLimitOrderTx, + getOTCOrdersRate, + buildOTCOrderTx, + buildSwapAndOTCOrderTx, }; }; diff --git a/src/methods/quote/getQuote.ts b/src/methods/quote/getQuote.ts index 9299f6f80..4cac17fb0 100644 --- a/src/methods/quote/getQuote.ts +++ b/src/methods/quote/getQuote.ts @@ -1,6 +1,6 @@ import { API_URL, SwapSide } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; -import type { BridgePrice, DeltaPrice } from '../delta/getDeltaPrice'; +import type { DeltaPrice } from '../delta/types'; import type { ConstructFetchInput, EnumerateLiteral, @@ -58,12 +58,12 @@ export type QuoteWithDeltaPrice = { }; export type QuoteWithBridgePrice = { - delta: BridgePrice; + delta: DeltaPrice; deltaAddress: string; }; export type QuoteWithDeltaPriceAndBridgePrice = { - delta: DeltaPrice | BridgePrice; + delta: DeltaPrice; deltaAddress: string; }; @@ -123,7 +123,7 @@ export const constructGetQuote = ({ chainId, fetcher, }: ConstructFetchInput): GetQuoteFunctions => { - const pricesUrl = `${apiURL}/quote` as const; + const pricesUrl = `${apiURL}/v2/quote` as const; function getQuote( options: QuoteParams<'delta'> & { destChainId?: undefined }, diff --git a/src/methods/swap/transaction.ts b/src/methods/swap/transaction.ts index 74cfbce3e..12b02b3a0 100644 --- a/src/methods/swap/transaction.ts +++ b/src/methods/swap/transaction.ts @@ -11,8 +11,8 @@ import type { import { assert } from 'ts-essentials'; import { API_URL, SwapSide } from '../../constants'; import { constructSearchString } from '../../helpers/misc'; -import type { OrderData } from '../limitOrders/buildOrder'; -import { sanitizeOrderData as sanitizeLimitOrderData } from '../limitOrders/helpers/misc'; +import type { OrderData } from '../otcOrders/buildOrder'; +import { sanitizeOrderData as sanitizeOTCOrderData } from '../otcOrders/helpers/misc'; import { sanitizeOrderData as sanitizeNFTOrderData } from '../nftOrders/helpers/misc'; import { AssetTypeVariant } from '../nftOrders/helpers/types'; @@ -98,7 +98,7 @@ export type BuildSwapTxInput = BuildTxInputBase & { | TxInputAmountsPartBuyOrSell ); // this union doesn't allow to mix srcAmount & destAmount & slippage together -// building block for LimitOrders and NFT Orders swaps +// building block for OTC Orders and NFT Orders swaps // can only use priceRoute.side=BUY and related TxInputAmountsPart* type BuildTxInputBaseBUYForOrders< // to Omit extra keys @@ -110,8 +110,8 @@ type BuildTxInputBaseBUYForOrders< | Omit ); -// for LimitOrder Fill, without swap -export type BuildLimitOrderTxInput = BuildTxInputBaseBUYForOrders & { +// for OTC Order Fill, without swap +export type BuildOTCOrderTxInput = BuildTxInputBaseBUYForOrders & { orders: SwappableOrder[]; srcDecimals: number; destDecimals: number; @@ -126,15 +126,8 @@ export type BuildNFTOrderTxInput = srcDecimals: number; }; -export interface BuildSwapAndLimitOrderTxInput0 - // destAmount is sum(orders[].makerAmount) - extends Omit { - priceRoute: OptimalRate; // priceRoute.side=BUY - orders: SwappableOrder[]; - destDecimals: number; -} -// for Swap + LimitOrder, priceRoute must have side=BUY -export type BuildSwapAndLimitOrderTxInput = +// for Swap + OTCOrder, priceRoute must have side=BUY +export type BuildSwapAndOTCOrderTxInput = // destAmount is sum(orders[].makerAmount) BuildTxInputBaseBUYForOrders & { priceRoute: OptimalRate; // priceRoute.side=BUY & priceRoute.contractMethod=simpleBuy @@ -154,9 +147,9 @@ export type BuildSwapAndNFTOrderTxInput = export type BuildTxInput = | BuildSwapTxInput - | BuildLimitOrderTxInput + | BuildOTCOrderTxInput | BuildNFTOrderTxInput - | BuildSwapAndLimitOrderTxInput + | BuildSwapAndOTCOrderTxInput | BuildSwapAndNFTOrderTxInput; export type BuildOptionsBase = { @@ -236,7 +229,7 @@ export const constructBuildTx = ({ 'makerAssetId' in order ? sanitizeNFTOrderData(order) // assetType is provided here, because Order.*Asset may be address : // if Order received from API by hash - sanitizeLimitOrderData(order); + sanitizeOTCOrderData(order); const sanitizedOrder: SwappableOrder = { ...sanitizedOrderData, diff --git a/src/sdk/full.ts b/src/sdk/full.ts index e6d2dde54..5ad105ca8 100644 --- a/src/sdk/full.ts +++ b/src/sdk/full.ts @@ -1,13 +1,9 @@ import type { SDKConfig } from './partial'; import { constructSwapSDK, SwapSDKMethods } from '../methods/swap'; import { - constructAllLimitOrdersHandlers, - LimitOrderHandlers, -} from '../methods/limitOrders'; -import { - constructAllNFTOrdersHandlers, - NFTOrderHandlers, -} from '../methods/nftOrders'; + constructAllOTCOrdersHandlers, + OTCOrderHandlers, +} from '../methods/otcOrders'; import { constructAllDeltaOrdersHandlers, DeltaOrderHandlers, @@ -21,32 +17,26 @@ import { API_URL, DEFAULT_VERSION } from '../constants'; export type AllSDKMethods = { swap: SwapSDKMethods; - /** @deprecated Limit Orders are deprecated and will be removed in a future version. */ - limitOrders: LimitOrderHandlers; - /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ - nftOrders: NFTOrderHandlers; + otcOrders: OTCOrderHandlers; delta: DeltaOrderHandlers; quote: GetQuoteFunctions; } & Required; -/** @description construct SDK with every method, for swap and limitOrders */ +/** @description construct SDK with every method, for swap and otcOrders */ export const constructFullSDK = ( config: SDKConfig ): AllSDKMethods => { // include all available functions const swap: SwapSDKMethods = constructSwapSDK(config); - const limitOrders: LimitOrderHandlers = - constructAllLimitOrdersHandlers(config); - const nftOrders: NFTOrderHandlers = - constructAllNFTOrdersHandlers(config); + const otcOrders: OTCOrderHandlers = + constructAllOTCOrdersHandlers(config); const delta: DeltaOrderHandlers = constructAllDeltaOrdersHandlers(config); const quote = constructGetQuote(config); return { swap, - limitOrders, - nftOrders, + otcOrders, delta, quote, apiURL: config.apiURL ?? API_URL, diff --git a/src/sdk/partial.ts b/src/sdk/partial.ts index b0d4fc9bb..c2973ff34 100644 --- a/src/sdk/partial.ts +++ b/src/sdk/partial.ts @@ -6,11 +6,9 @@ import type { } from '../types'; import type { Merge, UnionToIntersection } from 'ts-essentials'; import type { ApproveTokenFunctions } from '../methods/swap/approve'; -import type { CancelLimitOrderFunctions } from '../methods/limitOrders/cancelOrder'; -import type { ApproveTokenForLimitOrderFunctions } from '../methods/limitOrders/approveForOrder'; -import type { CancelNFTOrderFunctions } from '../methods/nftOrders/cancelOrder'; -import type { ApproveTokenForNFTOrderFunctions } from '../methods/nftOrders/approveForOrder'; -import type { FillOrderDirectlyFunctions } from '../methods/limitOrders/fillOrderDirectly'; +import type { CancelOTCOrderFunctions } from '../methods/otcOrders/cancelOrder'; +import type { ApproveTokenForOTCOrderFunctions } from '../methods/otcOrders/approveForOrder'; +import type { FillOTCOrderFunctions } from '../methods/otcOrders/fillOrderDirectly'; import type { ApproveTokenForDeltaFunctions } from '../methods/delta/approveForDelta'; import type { PreSignDeltaOrderFunctions } from '../methods/delta/preSignDeltaOrder'; import type { PreSignExternalDeltaOrderFunctions } from '../methods/delta/preSignExternalDeltaOrder'; @@ -46,14 +44,12 @@ type InferWithTxResponse< ? MergeExtendableRecursively< IntersectionOfReturns, [ - // if there are ApproveTokenFunctions or CancelLimitOrderFunctions in the intersection - // which means constructApproveToken or constructCancelLimitOrder was passed in Funcs + // if there are ApproveTokenFunctions or CancelOTCOrderFunctions in the intersection + // which means constructApproveToken or constructCancelOTCOrder was passed in Funcs ApproveTokenFunctions, - CancelLimitOrderFunctions, - FillOrderDirectlyFunctions, - ApproveTokenForLimitOrderFunctions, - CancelNFTOrderFunctions, - ApproveTokenForNFTOrderFunctions, + CancelOTCOrderFunctions, + FillOTCOrderFunctions, + ApproveTokenForOTCOrderFunctions, ApproveTokenForDeltaFunctions, PreSignDeltaOrderFunctions, PreSignExternalDeltaOrderFunctions, diff --git a/src/sdk/simple.ts b/src/sdk/simple.ts index 8d16a1860..6cd9dd40f 100644 --- a/src/sdk/simple.ts +++ b/src/sdk/simple.ts @@ -44,54 +44,29 @@ import type Web3 from 'web3'; import type { SwapSDKMethods } from '../methods/swap'; import { - BuildLimitOrderFunctions, - constructBuildLimitOrder, -} from '../methods/limitOrders/buildOrder'; + BuildOTCOrderFunctions, + constructBuildOTCOrder, +} from '../methods/otcOrders/buildOrder'; import { - constructPostLimitOrder, - PostLimitOrderFunctions, -} from '../methods/limitOrders/postOrder'; + constructPostOTCOrder, + PostOTCOrderFunctions, +} from '../methods/otcOrders/postOrder'; import { - constructGetLimitOrders, - GetLimitOrdersFunctions, -} from '../methods/limitOrders/getOrders'; + constructGetOTCOrders, + GetOTCOrdersFunctions, +} from '../methods/otcOrders/getOrders'; import { - constructGetLimitOrdersContract, - GetLimitOrdersContractFunctions, -} from '../methods/limitOrders/getOrdersContract'; + constructGetOTCOrdersContract, + GetOTCOrdersContractFunctions, +} from '../methods/otcOrders/getOrdersContract'; import { - constructBuildLimitOrderTx, - BuildLimitOrdersTxFunctions, -} from '../methods/limitOrders/transaction'; + constructBuildOTCOrderTx, + BuildOTCOrdersTxFunctions, +} from '../methods/otcOrders/transaction'; import { - constructAllLimitOrdersHandlers, - LimitOrderHandlers, -} from '../methods/limitOrders'; - -import { - constructGetNFTOrdersContract, - GetNFTOrdersContractFunctions, -} from '../methods/nftOrders/getOrdersContract'; -import { - constructGetNFTOrders, - GetNFTOrdersFunctions, -} from '../methods/nftOrders/getOrders'; -import { - BuildNFTOrderFunctions, - constructBuildNFTOrder, -} from '../methods/nftOrders/buildOrder'; -import { - constructPostNFTOrder, - PostNFTOrderFunctions, -} from '../methods/nftOrders/postOrder'; -import { - constructBuildNFTOrderTx, - BuildNFTOrdersTxFunctions, -} from '../methods/nftOrders/transaction'; -import { - constructAllNFTOrdersHandlers, - NFTOrderHandlers, -} from '../methods/nftOrders'; + constructAllOTCOrdersHandlers, + OTCOrderHandlers, +} from '../methods/otcOrders'; import { constructSwapSDK } from '../methods/swap'; import type { AxiosRequirement } from '../helpers/fetchers/axios'; @@ -129,9 +104,9 @@ import { GetQuoteFunctions, } from '../methods/quote/getQuote'; import { - constructGetBridgeInfo, - GetBridgeInfoFunctions, -} from '../methods/delta/getBridgeInfo'; + constructGetBridgeRoutes, + GetBridgeRoutesFunctions, +} from '../methods/delta/getBridgeRoutes'; import { constructIsTokenSupportedInDelta, IsTokenSupportedInDeltaFunctions, @@ -145,35 +120,24 @@ export type SwapFetchMethods = GetBalancesFunctions & GetRateFunctions & GetSwapTxFunctions; -/** @deprecated Limit Orders are deprecated and will be removed in a future version. */ -export type LimitOrdersFetchMethods = GetLimitOrdersContractFunctions & - GetLimitOrdersFunctions & - BuildLimitOrderFunctions & - PostLimitOrderFunctions & - BuildLimitOrdersTxFunctions; - -/** @deprecated NFT Orders are deprecated and will be removed in a future version. */ -export type NFTOrdersFetchMethods = GetNFTOrdersContractFunctions & - GetNFTOrdersFunctions & - BuildNFTOrderFunctions & - PostNFTOrderFunctions & - BuildNFTOrdersTxFunctions; +export type OTCOrdersFetchMethods = GetOTCOrdersContractFunctions & + GetOTCOrdersFunctions & + BuildOTCOrderFunctions & + PostOTCOrderFunctions & + BuildOTCOrdersTxFunctions; export type DeltaFetchMethods = BuildDeltaOrderFunctions & GetDeltaOrdersFunctions & GetDeltaPriceFunctions & GetDeltaContractFunctions & GetPartnerFeeFunctions & - GetBridgeInfoFunctions & + GetBridgeRoutesFunctions & IsTokenSupportedInDeltaFunctions & PostDeltaOrderFunctions; export type SimpleFetchSDK = { swap: SwapFetchMethods; - /** @deprecated Limit Orders are deprecated and will be removed in a future version. */ - limitOrders: LimitOrdersFetchMethods; - /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ - nftOrders: NFTOrdersFetchMethods; + otcOrders: OTCOrdersFetchMethods; delta: DeltaFetchMethods; quote: QuoteFetchMethods; } & Required; @@ -182,10 +146,7 @@ export type QuoteFetchMethods = GetQuoteFunctions; export type SimpleSDK = { swap: SwapSDKMethods; - /** @deprecated Limit Orders are deprecated and will be removed in a future version. */ - limitOrders: LimitOrderHandlers; - /** @deprecated NFT Orders are deprecated and will be removed in a future version. */ - nftOrders: NFTOrderHandlers; + otcOrders: OTCOrderHandlers; delta: DeltaOrderHandlers; quote: QuoteFetchMethods; } & Required; @@ -268,22 +229,13 @@ export function constructSimpleSDK( constructSwapTx ); - const limitOrders = constructPartialSDK( - config, - constructBuildLimitOrder, - constructPostLimitOrder, - constructGetLimitOrders, - constructGetLimitOrdersContract, - constructBuildLimitOrderTx - ); - - const nftOrders = constructPartialSDK( + const otcOrders = constructPartialSDK( config, - constructBuildNFTOrder, - constructPostNFTOrder, - constructGetNFTOrders, - constructGetNFTOrdersContract, - constructBuildNFTOrderTx + constructBuildOTCOrder, + constructPostOTCOrder, + constructGetOTCOrders, + constructGetOTCOrdersContract, + constructBuildOTCOrderTx ); const delta = constructPartialSDK( @@ -294,7 +246,7 @@ export function constructSimpleSDK( constructGetDeltaPrice, constructGetDeltaContract, constructGetPartnerFee, - constructGetBridgeInfo, + constructGetBridgeRoutes, constructIsTokenSupportedInDelta ); @@ -302,8 +254,7 @@ export function constructSimpleSDK( return { swap, - limitOrders, - nftOrders, + otcOrders, delta, quote, apiURL: options.apiURL ?? API_URL, @@ -324,11 +275,8 @@ export function constructSimpleSDK( const swap: SwapSDKMethods = constructSwapSDK(config); - const limitOrders: LimitOrderHandlers = - constructAllLimitOrdersHandlers(config); - - const nftOrders: NFTOrderHandlers = - constructAllNFTOrdersHandlers(config); + const otcOrders: OTCOrderHandlers = + constructAllOTCOrdersHandlers(config); const delta: DeltaOrderHandlers = constructAllDeltaOrdersHandlers(config); @@ -337,8 +285,7 @@ export function constructSimpleSDK( return { swap, - limitOrders, - nftOrders, + otcOrders, delta, quote, apiURL: options.apiURL ?? API_URL, diff --git a/src/types.ts b/src/types.ts index 345f85d9f..c19201145 100644 --- a/src/types.ts +++ b/src/types.ts @@ -241,3 +241,12 @@ export interface JsonFragment { */ readonly gas?: string; } + +/** @description Standard pagination envelope returned by paginated API endpoints. */ +export type PaginatedResponse = { + data: T[]; + total: number; + page: number; + limit: number; + hasMore: boolean; +}; diff --git a/tests/__snapshots__/delta.test.ts.snap b/tests/__snapshots__/delta.test.ts.snap deleted file mode 100644 index f4cb106b0..000000000 --- a/tests/__snapshots__/delta.test.ts.snap +++ /dev/null @@ -1,517 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Delta:methods Build Delta Order 1`] = ` -{ - "data": { - "beneficiary": "0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9", - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, - }, - "deadline": NaN, - "destAmount": "3147447403157656698880", - "destToken": "0x6b175474e89094c44da98b954eedeac495271d0f", - "expectedAmount": "3163263721766488892666", - "kind": 0, - "metadata": "0x", - "nonce": "dynamic_number", - "owner": "0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9", - "partnerAndFee": "512", - "permit": "0x", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - }, - "domain": { - "chainId": 1, - "name": "Portikus", - "verifyingContract": "0x0000000000bbf5c5fd284e657f01bd000933c96d", - "version": "2.0.0", - }, - "types": { - "Bridge": [ - { - "name": "protocolSelector", - "type": "bytes4", - }, - { - "name": "destinationChainId", - "type": "uint256", - }, - { - "name": "outputToken", - "type": "address", - }, - { - "name": "scalingFactor", - "type": "int8", - }, - { - "name": "protocolData", - "type": "bytes", - }, - ], - "Order": [ - { - "name": "owner", - "type": "address", - }, - { - "name": "beneficiary", - "type": "address", - }, - { - "name": "srcToken", - "type": "address", - }, - { - "name": "destToken", - "type": "address", - }, - { - "name": "srcAmount", - "type": "uint256", - }, - { - "name": "destAmount", - "type": "uint256", - }, - { - "name": "expectedAmount", - "type": "uint256", - }, - { - "name": "deadline", - "type": "uint256", - }, - { - "name": "kind", - "type": "uint8", - }, - { - "name": "nonce", - "type": "uint256", - }, - { - "name": "partnerAndFee", - "type": "uint256", - }, - { - "name": "permit", - "type": "bytes", - }, - { - "name": "metadata", - "type": "bytes", - }, - { - "name": "bridge", - "type": "Bridge", - }, - ], - }, -} -`; - -exports[`Delta:methods Get Delta Order by Id and Hash 1`] = ` -{ - "bridgeMetadata": null, - "bridgeStatus": null, - "chainId": 1, - "createdAt": "2025-04-18T14:04:43.806Z", - "deltaVersion": "2.0", - "excludeAgents": null, - "expiresAt": "2025-04-18T15:03:33.000Z", - "id": "7ec0dc82-98ad-4501-9f46-03e31e51098f", - "includeAgents": null, - "onChainOrderType": "Order", - "order": { - "beneficiary": "0x0ddc793680ff4f5793849c8c6992be1695cbe72a", - "bridge": { - "destinationChainId": 0, - "maxRelayerFee": "0", - "multiCallHandler": "0x0000000000000000000000000000000000000000", - "outputToken": "0x0000000000000000000000000000000000000000", - }, - "deadline": 1744988613, - "destAmount": "15614735", - "destToken": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "expectedAmount": "15693202", - "expectedDestAmount": "15693202", - "nonce": "1744985033868", - "owner": "0x0ddc793680ff4f5793849c8c6992be1695cbe72a", - "partnerAndFee": "0", - "permit": "0x0000000000000000000000000000000000000000000000000000000000000011b7130d8420811c9f39ed0393c106255bae4619e2ad0d41ca8bbf81a91b257a89dd67bca7d8a48faba04f51dd84f4e587865e7f5c9c92858663bfb4eb809e4c26", - "srcAmount": "10000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - }, - "orderHash": "0xce14e79ba90ba85c52f3e7308d00dd8978827d8d3c2249252222cc324121d02a", - "partiallyFillable": false, - "partner": "paraswap.io-local", - "referrerAddress": null, - "status": "EXECUTED", - "transactions": [ - { - "agent": "laita", - "bidId": "787bdca0-bd2e-4cfb-ad6c-9a8a84d90a76", - "blobGasPrice": 0, - "blobGasUsed": 0, - "blockHash": "0x9b66830ee3ae02a604309099227303bc3e73a672e58cffd0685a8c3f7152ff51", - "blockNumber": 22296365, - "blockTimestamp": null, - "bridgeMetadata": null, - "bridgeOverride": null, - "bridgeProtocol": null, - "bridgeStatus": null, - "filledPercent": 10000, - "from": "0x2e5ef37ade8afb712b8be858fec7389fe32857e2", - "gasPrice": 471068591, - "gasUsed": 313190, - "hash": "0x1f955f47482a8deeb5763613448a7d737ca3b3583dc9ab0c8665329ad93a2f32", - "id": "483394ee-1f2d-47f4-bc3d-e050b6645495", - "index": 73, - "orderId": "7ec0dc82-98ad-4501-9f46-03e31e51098f", - "partnerFee": "0", - "protocolFee": "26193", - "receivedAmount": "15719395", - "receivedAmountUSD": 15.72, - "spentAmount": "10000000000000000", - "spentAmountUSD": 15.9, - "status": 1, - "to": "0x0000000000bbf5c5fd284e657f01bd000933c96d", - }, - ], - "type": "MARKET", - "updatedAt": "2025-04-18T14:05:13.519Z", - "user": "0x0ddc793680ff4f5793849c8c6992be1695cbe72a", -} -`; - -exports[`Delta:methods Get Delta Orders for user 1`] = ` -[ - { - "bridgeMetadata": null, - "bridgeStatus": null, - "chainId": 1, - "createdAt": "2024-10-10T16:18:04.727Z", - "deltaVersion": "1.0", - "excludeAgents": null, - "expiresAt": "2024-10-10T17:17:47.000Z", - "id": "8515cce6-c7c6-486b-9f1e-5702f204edd6", - "includeAgents": null, - "onChainOrderType": "Order", - "order": { - "beneficiary": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, - }, - "deadline": 1728580667, - "destAmount": "11302885800000000000", - "destToken": "0x6b175474e89094c44da98b954eedeac495271d0f", - "expectedAmount": "11302885800000000000", - "nonce": 1728577074265, - "owner": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - "permit": "0x00000000000000000000000076176c2971300217e9f48e3dd4e40591500b96ff00000000000000000000000036ff475499e928590659d5b8aa3a34330a583fd900000000000000000000000000000000000000000000000000000000019d278900000000000000000000000000000000000000000000000000000000670bf2ae000000000000000000000000000000000000000000000000000000000000001bf548be9f97f37f0b2ab285bba67c8fdab99c3a08b0fdc0a910267988485535945df93e27958867f1d479c7b7783e98ba586629407e44f8d5c5d4115a7298dca9", - "srcAmount": "27076489", - "srcToken": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - }, - "orderHash": "0x5cd9f334b7b72943588af160e3fa8a46c894f89a3ce38967079713bf38af8128", - "partiallyFillable": false, - "partner": "delta-paraswap.io-local", - "referrerAddress": null, - "status": "EXECUTED", - "transactions": [ - { - "agent": "laita", - "bidId": null, - "blobGasPrice": 0, - "blobGasUsed": 0, - "blockHash": "0x21425d0c3625d5e55061ba2fd8ce91621dbee52c7d2846b76dd897d3438a6893", - "blockNumber": 20936359, - "blockTimestamp": null, - "bridgeMetadata": null, - "bridgeOverride": null, - "bridgeProtocol": null, - "bridgeStatus": null, - "filledPercent": 10000, - "from": "0x2e5eF37Ade8afb712B8Be858fEc7389Fe32857e2", - "gasPrice": 23525770029, - "gasUsed": 597540, - "hash": "0x3e5040d187288848ca57e4423d60fd31922b6db7fe636580d96200b03a8a8d8f", - "id": "c729ff7b-ffc8-4c85-88d8-41f4f26668eb", - "index": 57, - "orderId": "8515cce6-c7c6-486b-9f1e-5702f204edd6", - "partnerFee": "0", - "protocolFee": "0", - "receivedAmount": "17225367867506356154", - "receivedAmountUSD": 17.22, - "spentAmount": "27076489", - "spentAmountUSD": 27.06, - "status": 1, - "to": "0x1D7405DF25FD2fe80390DA3A696dcFd5120cA9Ce", - }, - ], - "type": "MARKET", - "updatedAt": "2024-10-10T16:18:51.447Z", - "user": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - }, - { - "bridgeMetadata": null, - "bridgeStatus": null, - "chainId": 1, - "createdAt": "2024-10-09T16:52:18.826Z", - "deltaVersion": "1.0", - "excludeAgents": null, - "expiresAt": "2024-10-09T17:52:08.000Z", - "id": "7696f983-4f0d-4bb0-b591-61957abf74de", - "includeAgents": null, - "onChainOrderType": "Order", - "order": { - "beneficiary": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, - }, - "deadline": 1728496328, - "destAmount": "736681085000000000000", - "destToken": "0xcafe001067cdef266afb7eb5a286dcfd277f3de5", - "expectedAmount": "736681085000000000000", - "nonce": 1728492729603, - "owner": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - "permit": "0x", - "srcAmount": "21000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - }, - "orderHash": "0x07b46a39e260d90f1be2575b1fffb7c905eacd0f9e36ad2f3a45f14b921b8a60", - "partiallyFillable": false, - "partner": "delta-paraswap.io-local", - "referrerAddress": null, - "status": "EXECUTED", - "transactions": [ - { - "agent": "laita", - "bidId": null, - "blobGasPrice": 0, - "blobGasUsed": 0, - "blockHash": "0x58dbd72e843c1224e8113694b8b4a37e29657f0d52634c0f3f89835a3c7a7187", - "blockNumber": 20929352, - "blockTimestamp": null, - "bridgeMetadata": null, - "bridgeOverride": null, - "bridgeProtocol": null, - "bridgeStatus": null, - "filledPercent": 10000, - "from": "0x2e5eF37Ade8afb712B8Be858fEc7389Fe32857e2", - "gasPrice": 47757958240, - "gasUsed": 224182, - "hash": "0x6d5fa34f4723283dc32496acb8b8faf4bb9e713e3a9d43152ebef7d842c59700", - "id": "0531cfdf-0732-4757-8a46-3886487eeedd", - "index": 188, - "orderId": "7696f983-4f0d-4bb0-b591-61957abf74de", - "partnerFee": "0", - "protocolFee": "0", - "receivedAmount": "1635237633557152096036", - "receivedAmountUSD": 22.77, - "spentAmount": "21000000000000000", - "spentAmountUSD": 51.08, - "status": 1, - "to": "0x1D7405DF25FD2fe80390DA3A696dcFd5120cA9Ce", - }, - ], - "type": "MARKET", - "updatedAt": "2024-10-09T16:52:37.585Z", - "user": "0x76176c2971300217e9f48e3dd4e40591500b96ff", - }, -] -`; - -exports[`Delta:methods Get Delta Price 1`] = ` -{ - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, - }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0x6b175474e89094c44da98b954eedeac495271d0f", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "srcUSD": "dynamic_number", -} -`; - -exports[`Delta:methods Get Delta Price Crosschain Get Delta Price Crosschain/destToken=ETH 1`] = ` -{ - "availableBridges": [], - "bridge": { - "destinationChainId": 10, - "outputToken": "dynamic_hash", - "protocolData": "dynamic_string", - "protocolSelector": "dynamic_string", - "scalingFactor": NaN, - }, - "bridgeInfo": { - "bestReturn": true, - "destAmountAfterBridge": "dynamic_number", - "destUSDAfterBridge": "dynamic_number", - "estimatedTimeMs": NaN, - "fastest": true, - "fees": [], - "protocolName": "dynamic_string", - "recommended": true, - }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "srcUSD": "dynamic_number", -} -`; - -exports[`Delta:methods Get Delta Price Crosschain Get Delta Price Crosschain/destToken=WETH 1`] = ` -{ - "availableBridges": [], - "bridge": { - "destinationChainId": 10, - "outputToken": "0x4200000000000000000000000000000000000006", - "protocolData": "dynamic_string", - "protocolSelector": "dynamic_string", - "scalingFactor": NaN, - }, - "bridgeInfo": { - "bestReturn": true, - "destAmountAfterBridge": "dynamic_number", - "destUSDAfterBridge": "dynamic_number", - "estimatedTimeMs": NaN, - "fastest": true, - "fees": [], - "protocolName": "dynamic_string", - "recommended": true, - }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "srcUSD": "dynamic_number", -} -`; - -exports[`Delta:methods Get Delta Price Crosschain Get Delta Price Crosschain/destToken=random 1`] = ` -{ - "availableBridges": [], - "bridge": { - "destinationChainId": 10, - "outputToken": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", - "protocolData": "dynamic_string", - "protocolSelector": "dynamic_string", - "scalingFactor": NaN, - }, - "bridgeInfo": { - "bestReturn": true, - "destAmountAfterBridge": "dynamic_number", - "destUSDAfterBridge": "dynamic_number", - "estimatedTimeMs": NaN, - "fastest": true, - "fees": [], - "protocolName": "dynamic_string", - "recommended": true, - }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "dynamic_address", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "srcUSD": "dynamic_number", -} -`; - -exports[`Delta:methods Submit(=build+sign+post) Delta Order 1`] = ` -{ - "beneficiary": "0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9", - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, - }, - "deadline": NaN, - "destAmount": "3147447403157656698880", - "destToken": "0x6b175474e89094c44da98b954eedeac495271d0f", - "expectedAmount": "3163263721766488892666", - "kind": 0, - "metadata": "0x", - "nonce": "dynamic_number", - "owner": "0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9", - "partnerAndFee": "512", - "permit": "0x", - "srcAmount": "1000000000000000000", - "srcToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", -} -`; diff --git a/tests/__snapshots__/viem.test.ts.snap b/tests/__snapshots__/viem.test.ts.snap index f6f6608a8..93975056b 100644 --- a/tests/__snapshots__/viem.test.ts.snap +++ b/tests/__snapshots__/viem.test.ts.snap @@ -1,14 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SDK with viem: contract calling methods signOrder: LimitOrder to sign 1`] = ` +exports[`SDK with viem: contract calling methods signOrder: OTCOrder to sign 1`] = ` { "data": { "expiry": 1766188800, "maker": "0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9", "makerAmount": "1000000000000000000", "makerAsset": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "nonceAndMeta": "1461501637330902918203684832716283019655932542976", - "taker": "0x0000000000000000000000000000000000000000", + "nonceAndMeta": "2596758597966366553121409781677941038171886226858", + "taker": "0xc6daaec7e58c1689cb0117933f862d9d3df08daa", "takerAmount": "8000000000000000000", "takerAsset": "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", }, diff --git a/tests/delta.test.ts b/tests/delta.test.ts index bcd71e71b..3aad98980 100644 --- a/tests/delta.test.ts +++ b/tests/delta.test.ts @@ -1,1132 +1,1022 @@ import * as dotenv from 'dotenv'; -import Web3 from 'web3'; -import { ethers } from 'ethersV5'; -import { ethers as ethersV6 } from 'ethers'; import fetch from 'isomorphic-unfetch'; import { - constructEthersV5ContractCaller, - constructEthersV6ContractCaller, - constructFetchFetcher, constructPartialSDK, - constructWeb3ContractCaller, + constructFetchFetcher, constructGetDeltaContract, + constructGetPartnerFee, + constructAllDeltaOrdersHandlers, + constructBuildDeltaOrder, + constructBuildExternalDeltaOrder, + constructBuildTWAPDeltaOrder, + constructCancelDeltaOrder, + constructGetAgentsList, + constructGetBridgeRoutes, constructGetDeltaOrders, constructGetDeltaPrice, - constructBuildDeltaOrder, - constructApproveTokenForDelta, - constructSignDeltaOrder, - constructViemContractCaller, - constructGetPartnerFee, - SignableDeltaOrderData, - DeltaPrice, + constructIsTokenSupportedInDelta, constructPostDeltaOrder, + constructPostExternalDeltaOrder, + constructPostTWAPDeltaOrder, constructSubmitDeltaOrder, - PostDeltaOrderParams, + PaginatedResponse, FetcherFunction, - constructCancelDeltaOrder, - constructPreSignDeltaOrder, - GetDeltaContractFunctions, - constructGetBridgeInfo, - BridgeInfo, } from '../src'; -import BigNumber from 'bignumber.js'; +import type { ContractCallerFunctions, TxHash } from '../src/types'; +import type { + DeltaAuction, + DeltaPrice, + DeltaRoute, + BuiltDeltaOrder, + BridgeRoute, +} from '../src/methods/delta/types'; -import erc20abi from './abi/ERC20.json'; +dotenv.config(); -import { assert } from 'ts-essentials'; -import { HardhatProvider } from './helpers/hardhat'; -import { privateKeyToAccount } from 'viem/accounts'; -import { - Address, - createWalletClient, - custom, - Hash, - Hex, - publicActions, - verifyTypedData, -} from 'viem'; -import { hardhat } from 'viem/chains'; -import { ZERO_ADDRESS } from '../src/methods/common/orders/buildOrderData'; -import { - BridgePriceInfo, - DeltaAuctionOrder, -} from '../src/methods/delta/helpers/types'; +const PARASWAP_DELTA = '0x1111111111111111111111111111111111111111'; +const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; +const DAI = '0x6b175474e89094c44da98b954eedeac495271d0f'; +const USDC_ARB = '0xaf88d065e77c8cc2239327c5edb3a432268e5831'; +const OWNER = '0xac39b311dceb2a4b2f5d8461c1cdaf756f4f7ae9'; +const API_URL = 'https://api.test.invalid'; +const FAKE_SIGNATURE = '0x' + 'ab'.repeat(64); + +type FetchSpy = jest.Mock, Parameters>; + +function buildPriceFixture( + overrides: Partial = {} +): DeltaPrice { + const srcInput = { + token: { chainId: 1, address: WETH }, + amount: '1000000000000000000', + amountUSD: '3000', + }; + const destOutput = { + token: { chainId: 1, address: DAI }, + amount: '2950000000000000000000', + amountUSD: '2950', + }; -dotenv.config(); + const route: DeltaRoute = { + origin: { input: srcInput, output: destOutput }, + destination: { input: destOutput, output: destOutput }, + bridge: null, + fees: { + gas: { + token: { + chainId: 1, + address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + }, + amount: '500000', + amountUSD: '0.5', + }, + bridge: [], + }, + }; -jest.setTimeout(30 * 1000); + return { + id: 'price-id-1', + side: 'SELL', + inputToken: { chainId: 1, address: WETH }, + outputToken: { chainId: 1, address: DAI }, + route, + partner: { name: 'sdk-test', feePercent: 0 }, + spender: PARASWAP_DELTA, + alternatives: [], + ...overrides, + }; +} -const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; -const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - -const chainId = 1; -const srcToken = WETH; -const destToken = DAI; -const srcAmount = (1 * 1e18).toString(); //The source amount multiplied by its decimals - -const TEST_MNEMONIC = - 'radar blur cabbage chef fix engine embark joy scheme fiction master release'; -//0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9 -const wallet = ethers.Wallet.fromMnemonic(TEST_MNEMONIC); -const walletV6 = ethersV6.HDNodeWallet.fromPhrase(TEST_MNEMONIC); - -const web3provider = new Web3(HardhatProvider as any); - -const ethersProvider = new ethers.providers.Web3Provider( - HardhatProvider as any -); - -const ethersV6Provider = new ethersV6.BrowserProvider(HardhatProvider); -const signerV6 = walletV6.connect(ethersV6Provider); - -const fetchFetcher = constructFetchFetcher(fetch); - -const signer = wallet.connect(ethersProvider); -const senderAddress = signer.address; - -const viemWalletClient = createWalletClient({ - // either walletClient needs to have account set at creation - // or provider must own the account (for testing can `await viemTestClient.impersonateAccount({ address: senderAddress });`) - // to be able to sign transactions - account: privateKeyToAccount(wallet.privateKey as Hex), - chain: { ...hardhat, id: chainId }, - transport: custom(HardhatProvider), -}).extend(publicActions); - -const ethersV5ContractCaller = constructEthersV5ContractCaller( - { - ethersProviderOrSigner: signer, - EthersContract: ethers.Contract, - }, - senderAddress -); - -const ethersV6ContractCaller = constructEthersV6ContractCaller( - { - ethersV6ProviderOrSigner: signerV6, - EthersV6Contract: ethersV6.Contract, - }, - senderAddress -); - -const web3ContractCaller = constructWeb3ContractCaller( - web3provider, - senderAddress -); - -const viemContractCaller = constructViemContractCaller( - viemWalletClient, - senderAddress -); - -describe('Delta:methods', () => { - const deltaSDK = constructPartialSDK( - { +function buildCrosschainRoute(): DeltaRoute { + const srcInput = { + token: { chainId: 1, address: WETH }, + amount: '1000000000000000000', + amountUSD: '3000', + }; + const srcOutputIntermediate = { + token: { chainId: 1, - fetcher: fetchFetcher, - contractCaller: ethersV5ContractCaller, - apiURL: process.env.API_URL, + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', }, - constructGetDeltaContract, - constructGetDeltaOrders, - constructGetDeltaPrice, - constructBuildDeltaOrder, - constructApproveTokenForDelta, - constructGetPartnerFee, - constructGetBridgeInfo - ); - - describe('Bridge methods', () => { - function flattenAllBridgeInfoTokens(bridgeInfo: BridgeInfo): string[] { - return Object.values(bridgeInfo).flatMap((chainMap) => - Object.values(chainMap).flat() - ); - } - test('Get Bridge Info', async () => { - const bridgeInfo = await deltaSDK.getBridgeInfo(); - expect(Object.keys(bridgeInfo)).toEqual( - // allow for more chains to be added in the future - expect.arrayContaining(['1', '10', '56', '130', '137', '8453', '42161']) - ); + amount: '2980000000', + amountUSD: '2980', + }; + const destInput = { + token: { chainId: 42161, address: USDC_ARB }, + amount: '2978000000', + amountUSD: '2978', + }; + const destOutput = { + token: { chainId: 42161, address: USDC_ARB }, + amount: '2978000000', + amountUSD: '2978', + }; - const defaultNumOfTokens = flattenAllBridgeInfoTokens(bridgeInfo).length; + return { + origin: { input: srcInput, output: srcOutputIntermediate }, + destination: { input: destInput, output: destOutput }, + bridge: { + protocol: 'Across', + tags: ['recommended', 'fastest'], + estimatedTimeMs: 90_000, + contractParams: { + protocolSelector: '0xdeadbeef', + outputToken: USDC_ARB, + scalingFactor: -12, + protocolData: '0xabcd', + }, + }, + fees: { + gas: { + token: { chainId: 1, address: WETH }, + amount: '7000000000000000', + amountUSD: '21', + }, + bridge: [ + { + token: { chainId: 42161, address: USDC_ARB }, + amount: '200000', + amountUSD: '0.2', + }, + ], + }, + }; +} - const bridgeInfoDIsallowedBridgeAndSwap = await deltaSDK.getBridgeInfo({ - allowBridgeAndSwap: false, - }); +/** Minimal BuiltDeltaOrder fixture representing a server-built order. */ +function buildBuiltOrderFixture( + value: Record = {}, + orderHash = '0xdeadbeef1234' +): BuiltDeltaOrder { + return { + toSign: { + domain: { + name: 'Portikus', + version: '2.0.0', + chainId: 1, + verifyingContract: PARASWAP_DELTA, + }, + types: { + Order: [ + { name: 'owner', type: 'address' }, + { name: 'beneficiary', type: 'address' }, + { name: 'srcToken', type: 'address' }, + { name: 'destToken', type: 'address' }, + { name: 'srcAmount', type: 'uint256' }, + { name: 'destAmount', type: 'uint256' }, + { name: 'expectedAmount', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, + { name: 'kind', type: 'uint8' }, + { name: 'nonce', type: 'uint256' }, + { name: 'partnerAndFee', type: 'uint256' }, + { name: 'permit', type: 'bytes' }, + { name: 'metadata', type: 'bytes' }, + { name: 'bridge', type: 'Bridge' }, + ], + Bridge: [ + { name: 'protocolSelector', type: 'bytes4' }, + { name: 'destinationChainId', type: 'uint256' }, + { name: 'outputToken', type: 'address' }, + { name: 'scalingFactor', type: 'int8' }, + { name: 'protocolData', type: 'bytes' }, + ], + }, + value: { + owner: OWNER, + beneficiary: OWNER, + srcToken: WETH, + destToken: DAI, + srcAmount: '1000000000000000000', + destAmount: '2950000000000000000000', + expectedAmount: '2950000000000000000000', + deadline: 9999999999, + kind: 0, + nonce: '12345', + permit: '0x', + partnerAndFee: '0', + metadata: '0x', + bridge: { + protocolSelector: '0x00000000', + destinationChainId: 0, + outputToken: '0x0000000000000000000000000000000000000000', + scalingFactor: 0, + protocolData: '0x', + }, + ...value, + }, + }, + orderHash, + }; +} - expect(Object.keys(bridgeInfoDIsallowedBridgeAndSwap)).toEqual( - Object.keys(bridgeInfo) +function makeMockContractCaller(): ContractCallerFunctions { + return { + staticCall: jest.fn(async () => { + throw new Error( + 'staticCall should not be invoked in v2 fetch-only tests' ); - const disallowedNumOfTokens = flattenAllBridgeInfoTokens( - bridgeInfoDIsallowedBridgeAndSwap - ).length; + }), + transactCall: jest.fn(async () => '0xfeedface' as TxHash), + signTypedDataCall: jest.fn(async () => FAKE_SIGNATURE), + }; +} - // fewer tokens are available when bridge and swap (swap on destChain after bridge) is not allowed - expect(disallowedNumOfTokens).toBeLessThan(defaultNumOfTokens); +function makeFetcher(handler: (params: any) => any): FetchSpy { + return jest.fn(async (params) => handler(params)) as FetchSpy; +} + +describe('Delta: fetch methods', () => { + test('getDeltaPrice hits /v2/delta/prices and returns DeltaPrice', async () => { + const fixture = buildPriceFixture(); + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect(url.startsWith(`${API_URL}/v2/delta/prices?`)).toBe(true); + expect(url).toContain(`srcToken=${WETH}`); + expect(url).toContain(`destToken=${DAI}`); + expect(url).toContain('amount=1000000000000000000'); + expect(url).toContain('chainId=1'); + expect(url).toContain('side=SELL'); + return fixture; }); - test('Get Bridge Protocols', async () => { - const bridgeProtocols = await deltaSDK.getBridgeProtocols(); - const expectedToInclude = [ - { - displayName: 'Across', - icon: expect.any(String), - protocol: 'Across', - }, - { - displayName: 'Relay', - icon: expect.any(String), - protocol: 'Relay', - }, - ]; - expect(bridgeProtocols).toEqual( - // allow for more bridges to be added in the future - expect.arrayContaining(expectedToInclude) - ); + const { getDeltaPrice } = constructGetDeltaPrice({ + apiURL: API_URL, + chainId: 1, + fetcher, }); - }); - test('Get Delta Price', async () => { - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: srcToken, - destToken: destToken, - amount: srcAmount, - userAddress: senderAddress, + const price = await getDeltaPrice({ + srcToken: WETH, + destToken: DAI, + amount: '1000000000000000000', srcDecimals: 18, destDecimals: 18, }); - const staticDeltaPrice: typeof deltaPrice = { - ...deltaPrice, - partnerFee: NaN, // dynamic number - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', - hmac: 'dynamic_string', - }; + expect(price).toEqual(fixture); + expect(price.route.origin.input.amount).toBe('1000000000000000000'); + expect(price.route.bridge).toBeNull(); + expect(fetcher).toHaveBeenCalledTimes(1); + }); - expect(staticDeltaPrice).toMatchSnapshot(); + test('getDeltaPrice passes destChainId for cross-chain', async () => { + const fixture = buildPriceFixture({ + route: buildCrosschainRoute(), + outputToken: { chainId: 42161, address: USDC_ARB }, + }); + const fetcher = makeFetcher(({ url }) => { + expect(url).toContain('destChainId=42161'); + return fixture; + }); + + const { getDeltaPrice } = constructGetDeltaPrice({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); + + const price = await getDeltaPrice({ + srcToken: WETH, + destToken: USDC_ARB, + amount: '1000000000000000000', + srcDecimals: 18, + destDecimals: 6, + destChainId: 42161, + }); + + expect(price.route.bridge?.protocol).toBe('Across'); + expect(price.route.destination.input.token.chainId).toBe(42161); }); - describe('Get Delta Price Crosschain', () => { - const destChainId = 10; - const ETH = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; - const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; - const WETH_ON_OPTIMISM = '0x4200000000000000000000000000000000000006'; - // const DAI_TOKEN_ON_ETHEREUM = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; - const DAI_TOKEN_ON_OPTIMISM = '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1'; + test('getBridgeRoutes hits /v2/delta/prices/bridge-routes and unwraps `routes`', async () => { + const routes: BridgeRoute[] = [ + { srcChainId: 1, destChainId: 42161, tokens: [USDC_ARB] }, + { srcChainId: 1, destChainId: 10, tokens: [DAI] }, + ]; + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect(url).toBe(`${API_URL}/v2/delta/prices/bridge-routes`); + return { routes }; + }); - test('Get Delta Price Crosschain/destToken=random', async () => { - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: WETH, - destToken: DAI_TOKEN_ON_OPTIMISM, - amount: srcAmount, - userAddress: senderAddress, - srcDecimals: 18, - destDecimals: 18, - destChainId, - }); - - const staticDeltaPrice: typeof deltaPrice = { - ...deltaPrice, - partnerFee: NaN, // dynamic number - destToken: 'dynamic_address', // will no longer match DAI_TOKEN_ON_ETHEREUM if bridge is Relay - bridge: { - ...deltaPrice.bridge, - protocolData: 'dynamic_string', - protocolSelector: 'dynamic_string', - scalingFactor: NaN, // dynamic number - }, - bridgeInfo: { - ...deltaPrice.bridgeInfo, - bestReturn: true, - destAmountAfterBridge: 'dynamic_number', - destUSDAfterBridge: 'dynamic_number', - estimatedTimeMs: NaN, // dynamic number - fastest: true, - fees: [], // dynamic array - protocolName: 'dynamic_string' as BridgePriceInfo['protocolName'], - recommended: true, - }, - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', - hmac: 'dynamic_string', - availableBridges: [], // dynamic array of bridge variants - }; - - // will no longer be true if swap is through Relay - // expect(deltaPrice.destToken).toEqual(DAI_TOKEN_ON_ETHEREUM.toLowerCase()); - expect(staticDeltaPrice).toMatchSnapshot(); - expect(deltaPrice.bridge.destinationChainId).toEqual(destChainId); - expect(deltaPrice.bridge.outputToken).toEqual( - DAI_TOKEN_ON_OPTIMISM.toLowerCase() - ); + const { getBridgeRoutes } = constructGetBridgeRoutes({ + apiURL: API_URL, + chainId: 1, + fetcher, }); - test('Get Delta Price Crosschain/destToken=WETH', async () => { - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: WETH, - destToken: WETH_ON_OPTIMISM, - amount: srcAmount, - userAddress: senderAddress, - srcDecimals: 18, - destDecimals: 18, - destChainId, - }); - - const staticDeltaPrice: typeof deltaPrice = { - ...deltaPrice, - partnerFee: NaN, // dynamic number - bridge: { - ...deltaPrice.bridge, - protocolData: 'dynamic_string', - protocolSelector: 'dynamic_string', - scalingFactor: NaN, // dynamic number - }, - bridgeInfo: { - ...deltaPrice.bridgeInfo, - bestReturn: true, - destAmountAfterBridge: 'dynamic_number', - destUSDAfterBridge: 'dynamic_number', - estimatedTimeMs: NaN, // dynamic number - fastest: true, - fees: [], // dynamic array - protocolName: 'dynamic_string' as BridgePriceInfo['protocolName'], - recommended: true, - }, - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', - hmac: 'dynamic_string', - availableBridges: [], // dynamic array of bridge variants - }; - - expect(staticDeltaPrice).toMatchSnapshot(); - expect(deltaPrice.bridge.destinationChainId).toEqual(destChainId); - expect(deltaPrice.bridge.outputToken).toEqual( - WETH_ON_OPTIMISM.toLowerCase() - ); + expect(await getBridgeRoutes()).toEqual(routes); + }); + + test('getBridgeRoutes passes filter params', async () => { + const fetcher = makeFetcher(({ url }) => { + expect(url).toContain('allowBridgeAndSwap=false'); + expect(url).toContain('bridges=Across%2CRelay'); + return { routes: [] }; }); - test('Get Delta Price Crosschain/destToken=ETH', async () => { - const deltaPrice = await deltaSDK.getDeltaPrice({ - srcToken: WETH, - destToken: ETH, - amount: srcAmount, - userAddress: senderAddress, - srcDecimals: 18, - destDecimals: 18, - destChainId, - }); - - const staticDeltaPrice: typeof deltaPrice = { - ...deltaPrice, - partnerFee: NaN, // dynamic number - bridge: { - ...deltaPrice.bridge, - outputToken: 'dynamic_hash', // WETH or ETH depending on bridge used - protocolData: 'dynamic_string', - protocolSelector: 'dynamic_string', - scalingFactor: NaN, // dynamic number - }, - bridgeInfo: { - ...deltaPrice.bridgeInfo, - bestReturn: true, - destAmountAfterBridge: 'dynamic_number', - destUSDAfterBridge: 'dynamic_number', - estimatedTimeMs: NaN, // dynamic number - fastest: true, - fees: [], // dynamic array - protocolName: 'dynamic_string' as BridgePriceInfo['protocolName'], - recommended: true, - }, - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', - hmac: 'dynamic_string', - availableBridges: [], // dynamic array of bridge variants - }; - - expect(staticDeltaPrice).toMatchSnapshot(); - expect(deltaPrice.bridge.destinationChainId).toEqual(destChainId); - // bridge.outputToken = WETH|ETH for destToken=ETH|WETH on destChain depending on bridge used; - // wrap/unwrap logic is determined by bridge.multiCallHandler presence - expect([WETH_ON_OPTIMISM.toLowerCase(), ETH.toLowerCase()]).toContain( - deltaPrice.bridge.outputToken - ); + const { getBridgeRoutes } = constructGetBridgeRoutes({ + apiURL: API_URL, + chainId: 1, + fetcher, }); + + expect( + await getBridgeRoutes({ + allowBridgeAndSwap: false, + bridges: ['Across', 'Relay'], + }) + ).toEqual([]); }); - test('Get Delta Contract', async () => { - const deltaContract = await deltaSDK.getDeltaContract(); - expect(deltaContract).toMatchInlineSnapshot( - `"0x0000000000bbf5c5fd284e657f01bd000933c96d"` - ); + test('isTokenSupportedInDelta unwraps `supported`', async () => { + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect( + url.startsWith(`${API_URL}/v2/delta/prices/is-token-supported/?`) + ).toBe(true); + expect(url).toContain(`token=${WETH}`); + expect(url).toContain('chainId=1'); + return { supported: true }; + }); + + const { isTokenSupportedInDelta } = constructIsTokenSupportedInDelta({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); + + expect(await isTokenSupportedInDelta(WETH)).toBe(true); }); - test('Approve Token For Delta', async () => { - const deltaContract = await deltaSDK.getDeltaContract(); - assert(deltaContract, 'Delta contract not found'); + test('getDeltaOrders returns the pagination envelope', async () => { + const order = { id: 'auction-1' } as unknown as DeltaAuction; + const envelope: PaginatedResponse = { + data: [order], + total: 1, + page: 1, + limit: 100, + hasMore: false, + }; - const allowanceBefore = await getTokenAllowance({ - tokenAddress: DAI, - owner: senderAddress, - spender: deltaContract, + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect(url.startsWith(`${API_URL}/v2/delta/orders?`)).toBe(true); + expect(url).toContain(`userAddress=${OWNER}`); + expect(url).toContain('page=2'); + expect(url).toContain('limit=10'); + return envelope; + }); + + const { getDeltaOrders } = constructGetDeltaOrders({ + apiURL: API_URL, + chainId: 1, + fetcher, }); - expect(allowanceBefore.toString()).toEqual('0'); + const result = await getDeltaOrders({ + userAddress: OWNER, + page: 2, + limit: 10, + }); - const amount = '1000000000000000000'; // 1 DAI - const tx = await deltaSDK.approveTokenForDelta(amount, DAI); - expect(tx).toBeDefined(); - await tx.wait(); + expect(result).toEqual(envelope); + expect(result.hasMore).toBe(false); + expect(result.data).toHaveLength(1); + }); - const allowanceAfter = await getTokenAllowance({ - tokenAddress: DAI, - owner: senderAddress, - spender: deltaContract, + test('getDeltaOrders by id / by hash use the v2 path', async () => { + const order = { id: 'auction-1' } as unknown as DeltaAuction; + const fetcher = makeFetcher(({ url }) => { + if (url === `${API_URL}/v2/delta/orders/auction-1`) return order; + if (url === `${API_URL}/v2/delta/orders/hash/0xhash`) return order; + throw new Error(`unexpected URL ${url}`); }); - expect(allowanceAfter.toString()).toEqual(amount); + const { getDeltaOrderById, getDeltaOrderByHash } = + constructGetDeltaOrders({ apiURL: API_URL, chainId: 1, fetcher }); + + expect(await getDeltaOrderById('auction-1')).toBe(order); + expect(await getDeltaOrderByHash('0xhash')).toBe(order); }); - test('Get Delta Orders for user', async () => { - const userWithOrders = '0x76176C2971300217E9f48E3dD4e40591500b96Ff'; + test('getRequiredBalanceForDeltaOrders hits /v2/delta/orders/fillablebalance/:chainId/:userAddress', async () => { + const required = { + [WETH]: '500000000000000000', + [DAI]: '1500000000000000000000', + }; + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect(url).toBe( + `${API_URL}/v2/delta/orders/fillablebalance/1/${OWNER}` + ); + return required; + }); - const deltaOrders = await deltaSDK.getDeltaOrders({ - userAddress: userWithOrders, + const { getRequiredBalanceForDeltaOrders } = + constructGetDeltaOrders({ apiURL: API_URL, chainId: 1, fetcher }); + + expect( + await getRequiredBalanceForDeltaOrders({ userAddress: OWNER }) + ).toEqual(required); + }); + + test('getRequiredBalanceForDeltaOrders narrows the URL when tokenAddress is passed', async () => { + const fetcher = makeFetcher(({ url }) => { + expect(url).toBe( + `${API_URL}/v2/delta/orders/fillablebalance/1/${OWNER}/${WETH}` + ); + return { [WETH]: '500000000000000000' }; }); - // Orders that we know the user had in the past - const staticSliceOfPastOrders = deltaOrders.slice(-2); // first 2 orders historically - expect(staticSliceOfPastOrders).toMatchSnapshot(); + const { getRequiredBalanceForDeltaOrders } = + constructGetDeltaOrders({ apiURL: API_URL, chainId: 1, fetcher }); + + const balance = await getRequiredBalanceForDeltaOrders({ + userAddress: OWNER, + tokenAddress: WETH, + }); + expect(balance[WETH]).toBe('500000000000000000'); }); - test('Get Delta Order by Id and Hash', async () => { - const orderId = '7ec0dc82-98ad-4501-9f46-03e31e51098f'; - const deltaOrder = await deltaSDK.getDeltaOrderById(orderId); - expect(deltaOrder).toMatchSnapshot(); - expect(deltaOrder).toBeDefined(); - assert( - deltaOrder?.orderHash, - "Delta order not found or doesn't have orderHash" - ); + test('getAgentsList hits /v2/delta/agents/list/:chainId and returns agent names', async () => { + const agents = ['agent-a', 'agent-b']; + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('GET'); + expect(url).toBe(`${API_URL}/v2/delta/agents/list/42161`); + return agents; // server returns string[] directly + }); - const orderByHash = await deltaSDK.getDeltaOrderByHash( - deltaOrder.orderHash - ); - expect(orderByHash).toEqual(deltaOrder); + const { getAgentsList } = constructGetAgentsList({ + apiURL: API_URL, + chainId: 42161, + fetcher, + }); + + expect(await getAgentsList()).toEqual(agents); }); +}); - test('Get PartnerFee', async () => { - const partnerFee = await deltaSDK.getPartnerFee({ partner: 'paraswap.io' }); - expect(partnerFee).toMatchInlineSnapshot(` - { - "partnerAddress": "0xc85f5d432b7fa25287c7e0cb88139a1a4c37f565", - "partnerFee": 0.15, - "takeSurplus": false, - } - `); +describe('Delta: build (server-side via POST /v2/delta/orders/build)', () => { + test('buildDeltaOrder POSTs to /v2/delta/orders/build with correct body', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; + + const fetcher = makeFetcher(({ url, method, data }) => { + expect(method).toBe('POST'); + expect(url).toBe(`${API_URL}/v2/delta/orders/build`); + postedBody = data; + return builtFixture; + }); + + const { buildDeltaOrder } = constructBuildDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); + + const route = buildPriceFixture().route; + const result = await buildDeltaOrder({ + owner: OWNER, + route, + side: 'SELL', + partnerAddress: '0x0000000000000000000000000000000000000000', + }); + + expect(result).toEqual(builtFixture); + // build endpoint derives the chain from the route — no chainId in the body + expect(postedBody.chainId).toBeUndefined(); + expect(postedBody.side).toBe('SELL'); + expect(postedBody.owner).toBe(OWNER); + expect(postedBody.route).toBe(route); + expect(postedBody.slippage).toBeUndefined(); + expect(postedBody.orderType).toBe('Order'); }); - test('Build Delta Order', async () => { - const sampleDeltaPrice: DeltaPrice = { - destAmount: '3163263721766488892666', - destAmountBeforeFee: '3194635547945152526200', - receivedDestAmount: '3163263721766488892666', - destToken: '0x6b175474e89094c44da98b954eedeac495271d0f', - destUSD: '3166.4269854931', - receivedDestUSD: '3166.4269854931', - destUSDBeforeFee: '3197.8301834931', - gasCost: '347788', - gasCostBeforeFee: '124240', - gasCostUSD: '31.403198', - gasCostUSDBeforeFee: '11.218137', - partner: 'anon', - partnerFee: 0, - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - srcUSD: '3191.5500000000', - hmac: '1234aeb', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }; + test('buildDeltaOrder passes slippage to server for SELL', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; - const slippagePercent = 0.5; - const destAmountAfterSlippage = decreaseBySlippage( - sampleDeltaPrice.destAmount, - slippagePercent - ); + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); - const amount = '1000000000000000000'; // 1 DAI + const { buildDeltaOrder } = constructBuildDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - const signableOrderData = await deltaSDK.buildDeltaOrder({ - deltaPrice: sampleDeltaPrice, - owner: senderAddress, - // beneficiary: anotherAccount, // if need to send destToken to another account - // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: WETH, - destToken: DAI, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount - partnerAddress: ZERO_ADDRESS, + await buildDeltaOrder({ + owner: OWNER, + route: buildPriceFixture().route, + side: 'SELL', + slippage: 100, + partnerAddress: '0x0000000000000000000000000000000000000000', }); - const staticSignableOrderData: typeof signableOrderData = { - ...signableOrderData, - data: { - ...signableOrderData.data, - deadline: NaN, // dynamic number - nonce: 'dynamic_number', - }, - }; - // for ZERO partnerAddress capSurplus (true) shifted (<< 9) = 512 - expect(signableOrderData.data.partnerAndFee).toEqual((1 << 9).toString()); - expect(staticSignableOrderData).toMatchSnapshot(); + // slippage is forwarded to server; server applies it to destAmount + expect(postedBody.slippage).toBe(100); + expect(postedBody.side).toBe('SELL'); }); - test('Build Delta Order with slippage (SELL)', async () => { - const sampleDeltaPrice: DeltaPrice = { - destAmount: '3163263721766488892666', - destAmountBeforeFee: '3194635547945152526200', - receivedDestAmount: '3163263721766488892666', - destToken: '0x6b175474e89094c44da98b954eedeac495271d0f', - destUSD: '3166.4269854931', - receivedDestUSD: '3166.4269854931', - destUSDBeforeFee: '3197.8301834931', - gasCost: '347788', - gasCostBeforeFee: '124240', - gasCostUSD: '31.403198', - gasCostUSDBeforeFee: '11.218137', - partner: 'anon', - partnerFee: 0, - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - srcUSD: '3191.5500000000', - hmac: '1234aeb', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }; + test('buildDeltaOrder passes slippage to server for BUY', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; - const slippageBps = 50; // 50 bps = 0.5% - const BPS_BASE = BigInt(10_000); - const expectedDestAmount = ( - (BigInt(sampleDeltaPrice.destAmount) * (BPS_BASE - BigInt(slippageBps))) / - BPS_BASE - ).toString(10); + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); - const amount = '1000000000000000000'; + const { buildDeltaOrder } = constructBuildDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - const signableOrderData = await deltaSDK.buildDeltaOrder({ - deltaPrice: sampleDeltaPrice, - owner: senderAddress, - srcToken: WETH, - destToken: DAI, - srcAmount: amount, - slippage: slippageBps, - partnerAddress: ZERO_ADDRESS, + await buildDeltaOrder({ + owner: OWNER, + route: buildPriceFixture().route, + side: 'BUY', + slippage: 100, + partnerAddress: '0x0000000000000000000000000000000000000000', }); - expect(signableOrderData.data.srcAmount).toEqual(amount); - expect(signableOrderData.data.destAmount).toEqual(expectedDestAmount); + expect(postedBody.slippage).toBe(100); + expect(postedBody.side).toBe('BUY'); }); - test('Build Delta Order with slippage (BUY)', async () => { - const sampleDeltaPrice: DeltaPrice = { - destAmount: '3163263721766488892666', - destAmountBeforeFee: '3194635547945152526200', - receivedDestAmount: '3163263721766488892666', - destToken: '0x6b175474e89094c44da98b954eedeac495271d0f', - destUSD: '3166.4269854931', - receivedDestUSD: '3166.4269854931', - destUSDBeforeFee: '3197.8301834931', - gasCost: '347788', - gasCostBeforeFee: '124240', - gasCostUSD: '31.403198', - gasCostUSDBeforeFee: '11.218137', - partner: 'anon', - partnerFee: 0, - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - srcUSD: '3191.5500000000', - hmac: '1234aeb', + test('buildDeltaOrder passes cross-chain route as-is; server injects destinationChainId', async () => { + const ccRoute = buildCrosschainRoute(); + const builtFixture = buildBuiltOrderFixture({ + srcToken: WETH, + destToken: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', + protocolSelector: '0xdeadbeef', + destinationChainId: 42161, + outputToken: USDC_ARB, + scalingFactor: -12, + protocolData: '0xabcd', }, - }; + }); + let postedBody: any; - const slippageBps = 50; // 50 bps = 0.5% - const destAmount = '3163263721766488892666'; + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); - const BPS_BASE = BigInt(10_000); - const expectedSrcAmount = ( - (BigInt(sampleDeltaPrice.srcAmount) * (BPS_BASE + BigInt(slippageBps))) / - BPS_BASE - ).toString(10); + const { buildDeltaOrder } = constructBuildDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - const signableOrderData = await deltaSDK.buildDeltaOrder({ - deltaPrice: sampleDeltaPrice, - owner: senderAddress, - srcToken: WETH, - destToken: DAI, - destAmount, - slippage: slippageBps, - side: 'BUY', - partnerAddress: ZERO_ADDRESS, + const result = await buildDeltaOrder({ + owner: OWNER, + route: ccRoute, + side: 'SELL', + partnerAddress: '0x0000000000000000000000000000000000000000', }); - expect(signableOrderData.data.destAmount).toEqual(destAmount); - expect(signableOrderData.data.srcAmount).toEqual(expectedSrcAmount); + // route is forwarded as-is; bridge in route.contractParams has no destinationChainId + expect(postedBody.route).toBe(ccRoute); + // the server (fixture) fills in destinationChainId + expect(result.toSign.value.bridge).toMatchObject({ + protocolSelector: '0xdeadbeef', + destinationChainId: 42161, + }); }); - let signature = ''; + test('buildExternalDeltaOrder sends orderType ExternalOrder with handler/data', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; - test.each([ - ['ethersV5', ethersV5ContractCaller], - ['ethersV6', ethersV6ContractCaller], - ['web3', web3ContractCaller], - ['viem', viemContractCaller], - ])('sign Delta Order with %s', async (_libName, contractCaller) => { - const sdk = constructPartialSDK( - { - chainId: 1, - fetcher: fetchFetcher, - contractCaller, - apiURL: process.env.API_URL, - }, - constructSignDeltaOrder + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); + + const { buildExternalDeltaOrder } = constructBuildExternalDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); + + const route = buildPriceFixture().route; + await buildExternalDeltaOrder({ + owner: OWNER, + handler: '0x2222222222222222222222222222222222222222', + data: '0xdeadbeef', + route, + side: 'SELL', + partnerAddress: '0x0000000000000000000000000000000000000000', + }); + + expect(postedBody.orderType).toBe('ExternalOrder'); + expect(postedBody.handler).toBe( + '0x2222222222222222222222222222222222222222' ); + expect(postedBody.data).toBe('0xdeadbeef'); + expect(postedBody.route).toBe(route); + }); - const sampleOrder: SignableDeltaOrderData = { - data: { - beneficiary: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - deadline: 1731328853, - destAmount: '3147447403157656698880', - destToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - expectedAmount: '3163263721766488892666', - nonce: '1731325253703', - owner: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - partnerAndFee: '0', - permit: '0x', - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - kind: 0, - metadata: '0x', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }, - domain: { - chainId: 1, - name: 'Portikus', - verifyingContract: '0x0000000000bbf5c5fd284e657f01bd000933c96d', - version: '2.0.0', - }, - types: { - Order: [ - { - name: 'owner', - type: 'address', - }, - { - name: 'beneficiary', - type: 'address', - }, - { - name: 'srcToken', - type: 'address', - }, - { - name: 'destToken', - type: 'address', - }, - { - name: 'srcAmount', - type: 'uint256', - }, - { - name: 'destAmount', - type: 'uint256', - }, - { - name: 'expectedAmount', - type: 'uint256', - }, - { - name: 'deadline', - type: 'uint256', - }, - { - name: 'kind', - type: 'uint8', - }, - { - name: 'nonce', - type: 'uint256', - }, - { - name: 'partnerAndFee', - type: 'uint256', - }, - { - name: 'permit', - type: 'bytes', - }, - { - name: 'metadata', - type: 'bytes', - }, - { - name: 'bridge', - type: 'Bridge', - }, - ], - Bridge: [ - { - name: 'protocolSelector', - type: 'bytes4', - }, - { - name: 'destinationChainId', - type: 'uint256', - }, - { - name: 'outputToken', - type: 'address', - }, - { - name: 'scalingFactor', - type: 'int8', - }, - { - name: 'protocolData', - type: 'bytes', - }, - ], - }, - }; + test('buildTWAPDeltaOrder (sell) sends TWAPOrder body; slippage forwarded to server', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; + + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); + + const { buildTWAPDeltaOrder } = constructBuildTWAPDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - const deltaOrderSignature = await sdk.signDeltaOrder(sampleOrder); - if (!signature) signature = deltaOrderSignature; - // signatures match between libraries - expect(deltaOrderSignature).toEqual(signature); + const route = buildPriceFixture().route; + await buildTWAPDeltaOrder({ + owner: OWNER, + onChainOrderType: 'TWAPOrder', + route, + totalSrcAmount: '5000000000000000000', + interval: 300, + numSlices: 5, + slippage: 50, + partnerAddress: '0x0000000000000000000000000000000000000000', + }); + + expect(postedBody.orderType).toBe('TWAPOrder'); + expect(postedBody.interval).toBe(300); + expect(postedBody.numSlices).toBe(5); + expect(postedBody.totalSrcAmount).toBe('5000000000000000000'); + expect(postedBody.slippage).toBe(50); // server applies slippage to destAmountPerSlice + expect(postedBody.side).toBe('SELL'); }); - let cancelSignature = ''; + test('buildTWAPDeltaOrder (buy) forwards slippage and maxSrcAmount to server', async () => { + const builtFixture = buildBuiltOrderFixture(); + let postedBody: any; + + const fetcher = makeFetcher(({ url, data }) => { + if (url === `${API_URL}/v2/delta/orders/build`) { + postedBody = data; + return builtFixture; + } + throw new Error(`unexpected ${url}`); + }); - const sampleOrderId = '7ec0dc82-98ad-4501-9f46-03e31e51098f'; + const { buildTWAPDeltaOrder } = constructBuildTWAPDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - test.each([ - ['ethersV5', ethersV5ContractCaller], - ['ethersV6', ethersV6ContractCaller], - ['web3', web3ContractCaller], - ['viem', viemContractCaller], - ])( - 'sign Cancel Delta Order Request with %s', - async (_libName, contractCaller) => { - const sdk = constructPartialSDK( - { - chainId: 1, - fetcher: fetchFetcher, - contractCaller, - apiURL: process.env.API_URL, - }, - constructCancelDeltaOrder - ); + const route = buildPriceFixture().route; + await buildTWAPDeltaOrder({ + owner: OWNER, + onChainOrderType: 'TWAPBuyOrder', + route, + totalDestAmount: '5000000000000000000', + maxSrcAmount: '1000000000000000000', + interval: 300, + numSlices: 5, + slippage: 100, + partnerAddress: '0x0000000000000000000000000000000000000000', + }); - const deltaCancelSignature = await sdk.signCancelLimitDeltaOrderRequest({ - orderIds: [sampleOrderId], - }); + expect(postedBody.orderType).toBe('TWAPBuyOrder'); + expect(postedBody.side).toBe('BUY'); + expect(postedBody.maxSrcAmount).toBe('1000000000000000000'); + expect(postedBody.slippage).toBe(100); + }); +}); - const valid = await verifySignedCancelRequest({ - orderId: sampleOrderId, - signature: deltaCancelSignature, - address: senderAddress, - chainId: sdk.chainId, - }); +describe('Delta: submit (build → sign → post)', () => { + test('submitDeltaOrder posts to /v2/delta/orders with signed order', async () => { + const builtFixture = buildBuiltOrderFixture(); + let posted: any; + let postUrl = ''; - expect(valid).toBe(true); + const fetcher = makeFetcher(({ url, method, data }) => { + if (method === 'POST' && url === `${API_URL}/v2/delta/orders/build`) { + return builtFixture; + } + if (method === 'POST' && url.startsWith(`${API_URL}/v2/delta/orders`)) { + postUrl = url; + posted = data; + return { + id: 'auction-99', + order: data.order, + onChainOrderType: 'Order', + } as unknown as DeltaAuction<'Order'>; + } + throw new Error(`unexpected request ${method} ${url}`); + }); - if (!cancelSignature) cancelSignature = deltaCancelSignature; - // signatures match between libraries - expect(deltaCancelSignature).toEqual(cancelSignature); - } - ); + const { submitDeltaOrder } = constructSubmitDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + contractCaller: makeMockContractCaller(), + }); - const dummyFetcher: FetcherFunction = (params) => { - // intercept POST requests - if (params.method === 'POST') { - return params as any; - } + const response = await submitDeltaOrder({ + owner: OWNER, + route: buildPriceFixture().route, + side: 'SELL', + partnerAddress: '0x0000000000000000000000000000000000000000', + }); - return fetchFetcher(params); - }; + expect(postUrl.startsWith(`${API_URL}/v2/delta/orders`)).toBe(true); + expect(posted.signature).toBe(FAKE_SIGNATURE); + expect(posted.chainId).toBe(1); + // order comes from builtFixture.toSign.value + expect(posted.order.owner).toBe(OWNER); + expect(posted.order.srcToken).toBe(WETH); + expect(posted.order.destToken).toBe(DAI); + expect(response.id).toBe('auction-99'); + }); - const mockFetch = jest.fn(dummyFetcher); + test('postDeltaOrder forwards degenMode as a query param', async () => { + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('POST'); + expect(url).toContain('degenMode=true'); + return { id: 'x' } as unknown as DeltaAuction<'Order'>; + }); - const dummySDK = constructPartialSDK( - { + const { postDeltaOrder } = constructPostDeltaOrder({ + apiURL: API_URL, chainId: 1, - fetcher: mockFetch as FetcherFunction, - contractCaller: ethersV5ContractCaller, - apiURL: process.env.API_URL, - }, - constructPostDeltaOrder, - constructSubmitDeltaOrder - ); - - test('Post Delta Order', async () => { - const sampleOrderData: SignableDeltaOrderData['data'] = { - beneficiary: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - deadline: NaN, // dynamic number - destAmount: '3147447403157656698880', - destToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - expectedAmount: '3163263721766488892666', - nonce: 'dynamic_number', - owner: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - partnerAndFee: '0', - permit: '0x', - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - kind: 0, - metadata: '0x', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }; + fetcher, + }); - const sampleSignature = '0x1234....'; + expect( + await postDeltaOrder({ + signature: FAKE_SIGNATURE, + order: {} as any, + degenMode: true, + }) + ).toEqual({ id: 'x' }); + }); - const input = { - order: sampleOrderData, - signature: sampleSignature, - }; + test('postExternalDeltaOrder sends to /v2/delta/orders', async () => { + const fetcher = makeFetcher(({ url, method }) => { + expect(method).toBe('POST'); + expect(url).toBe(`${API_URL}/v2/delta/orders`); + return { id: 'ext-1' } as unknown as DeltaAuction<'ExternalOrder'>; + }); - await dummySDK.postDeltaOrder(input); + const { postExternalDeltaOrder } = constructPostExternalDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + }); - expect(mockFetch).toHaveBeenLastCalledWith({ - data: { ...input, chainId: dummySDK.chainId }, - method: 'POST', - url: `${dummySDK.apiURL}/delta/orders/`, + expect( + await postExternalDeltaOrder({ + signature: FAKE_SIGNATURE, + order: {} as any, + }) + ).toEqual({ id: 'ext-1' }); + }); + + test('postTWAPDeltaOrder sends to /v2/delta/orders with onChainOrderType', async () => { + const fetcher = makeFetcher(({ url, method, data }) => { + expect(method).toBe('POST'); + expect(url.startsWith(`${API_URL}/v2/delta/orders`)).toBe(true); + expect(data.onChainOrderType).toBe('TWAPOrder'); + return { id: 'twap-1' } as unknown as DeltaAuction<'TWAPOrder'>; + }); + + const { postTWAPDeltaOrder } = constructPostTWAPDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, }); + + expect( + await postTWAPDeltaOrder({ + signature: FAKE_SIGNATURE, + order: {} as any, + onChainOrderType: 'TWAPOrder', + }) + ).toEqual({ id: 'twap-1' }); }); +}); - test('Submit(=build+sign+post) Delta Order', async () => { - const sampleDeltaPrice: DeltaPrice = { - destAmount: '3163263721766488892666', - destAmountBeforeFee: '3194635547945152526200', - receivedDestAmount: '3163263721766488892666', - destToken: '0x6b175474e89094c44da98b954eedeac495271d0f', - destUSD: '3166.4269854931', - receivedDestUSD: '3166.4269854931', - destUSDBeforeFee: '3197.8301834931', - gasCost: '347788', - gasCostBeforeFee: '124240', - gasCostUSD: '31.403198', - gasCostUSDBeforeFee: '11.218137', - partner: 'anon', - partnerFee: 0, - srcAmount: '1000000000000000000', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - srcUSD: '3191.5500000000', - hmac: '1234aeb', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }; +describe('Delta: cancel', () => { + test('cancelDeltaOrders signs then posts to /v2/delta/orders/cancel', async () => { + let postedTo = ''; + let postedBody: any; + + const fetcher = makeFetcher(({ url, method, data }) => { + const adapter = url.includes('/adapters/contracts') + ? { + AugustusSwapper: '0x', + TokenTransferProxy: '0x', + AugustusRFQ: '0x', + Executors: {}, + ParaswapDelta: '0x1111111111111111111111111111111111111111', + } + : undefined; + if (adapter) return adapter; + if (method === 'POST') { + postedTo = url; + postedBody = data; + return { success: true }; + } + throw new Error('unexpected'); + }); - const slippagePercent = 0.5; - const destAmountAfterSlippage = decreaseBySlippage( - sampleDeltaPrice.destAmount, - slippagePercent - ); + const { cancelDeltaOrders } = constructCancelDeltaOrder({ + apiURL: API_URL, + chainId: 1, + fetcher, + contractCaller: makeMockContractCaller(), + }); - const amount = '1000000000000000000'; // 1 DAI + const result = await cancelDeltaOrders({ + orderIds: ['a', 'b'], + }); - const input = { - deltaPrice: sampleDeltaPrice, - owner: senderAddress, - // beneficiary: anotherAccount, // if need to send destToken to another account - // permit: "0x1234...", // if signed a Permit1 or Permit2 TransferFrom for DeltaContract - srcToken: WETH, - destToken: DAI, - srcAmount: amount, - destAmount: destAmountAfterSlippage, // minimum acceptable destAmount - partnerAddress: ZERO_ADDRESS, - }; + expect(result).toEqual({ success: true }); + expect(postedTo).toBe(`${API_URL}/v2/delta/orders/cancel`); + expect(postedBody.orderIds).toEqual(['a', 'b']); + expect(postedBody.signature).toBe(FAKE_SIGNATURE); + }); +}); - await dummySDK.submitDeltaOrder(input); +describe('Delta: live API contract', () => { + jest.setTimeout(30_000); - const callArgs = mockFetch.mock.lastCall?.[0]; - assert(callArgs, 'No fetch call was made'); - assert('data' in callArgs, 'No data was sent in the fetch call'); - const { order, signature } = callArgs.data as PostDeltaOrderParams; + const LIVE_API = process.env.API_URL; + const fetchFetcher = constructFetchFetcher(fetch); - expect(signature).toBeDefined(); + test('GET /v2/delta/prices (same-chain) matches DeltaPrice shape', async () => { + const { getDeltaPrice } = constructGetDeltaPrice({ + apiURL: LIVE_API, + chainId: 1, + fetcher: fetchFetcher, + }); - const staticSignedOrderData: SignableDeltaOrderData['data'] = { - ...order, - deadline: NaN, // dynamic number - nonce: 'dynamic_number', - }; + const price = await getDeltaPrice({ + srcToken: WETH, + destToken: DAI, + amount: '1000000000000000000', + srcDecimals: 18, + destDecimals: 18, + side: 'SELL', + }); - // for ZERO partnerAddress capSurplus (true) shifted (<< 9) = 512 - expect(order.partnerAndFee).toEqual((1 << 9).toString()); - expect(staticSignedOrderData).toMatchSnapshot(); + expect(price.side).toBe('SELL'); + expect(price.inputToken.chainId).toBe(1); + expect(price.outputToken.chainId).toBe(1); + expect(typeof price.id).toBe('string'); + expect(typeof price.spender).toBe('string'); + expect(price.route.origin.input.token.address.toLowerCase()).toBe(WETH); + expect(typeof price.route.origin.input.amount).toBe('string'); + expect(typeof price.route.origin.input.amountUSD).toBe('string'); + // same-chain: bridge is null + expect(price.route.bridge).toBeNull(); + // fees.gas is a single DeltaTokenAmount, fees.bridge is an array + expect(typeof price.route.fees.gas.amount).toBe('string'); + expect(Array.isArray(price.route.fees.bridge)).toBe(true); }); - describe('PreSign Delta Order', () => { - const sdk = constructPartialSDK( - { - chainId: 1, - fetcher: fetchFetcher, - contractCaller: viemContractCaller, - apiURL: process.env.API_URL, - }, - constructPreSignDeltaOrder, - constructGetDeltaContract - ); + test('GET /v2/delta/prices (cross-chain) returns DeltaRoute with bridge.contractParams (no destinationChainId)', async () => { + const { getDeltaPrice } = constructGetDeltaPrice({ + apiURL: LIVE_API, + chainId: 1, + fetcher: fetchFetcher, + }); - const sampleOrder: DeltaAuctionOrder = { - owner: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - beneficiary: '0xaC39b311DCEb2A4b2f5d8461c1cdaF756F4F7Ae9', - srcToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - destToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - srcAmount: '1000000000000000000', - destAmount: '3147447403157656698880', - expectedAmount: '3163263721766488892666', - kind: 0, - metadata: '0x', - deadline: 1731328853, - nonce: '1731325253703', - permit: '0x', - partnerAndFee: '0', - bridge: { - protocolSelector: '0x00000000', - destinationChainId: 0, - outputToken: ZERO_ADDRESS, - scalingFactor: 0, - protocolData: '0x', - }, - }; + const price = await getDeltaPrice({ + srcToken: WETH, + destToken: USDC_ARB, + amount: '1000000000000000000', + srcDecimals: 18, + destDecimals: 6, + destChainId: 42161, + side: 'SELL', + }); - test('hash Delta Order', async () => { - const orderHash = await sdk.hashDeltaOrder(sampleOrder); - expect(orderHash).toMatchInlineSnapshot( - `"0x4e68492d838e64c329ecdba51d32cb088088445ca62b1d5c4edf5a2ab80b586d"` + expect(price.outputToken.chainId).toBe(42161); + expect(price.route.destination.input.token.chainId).toBe(42161); + expect(price.route.bridge).not.toBeNull(); + if (price.route.bridge) { + expect(typeof price.route.bridge.protocol).toBe('string'); + expect(Array.isArray(price.route.bridge.tags)).toBe(true); + expect(typeof price.route.bridge.contractParams.protocolSelector).toBe( + 'string' + ); + expect(typeof price.route.bridge.contractParams.outputToken).toBe( + 'string' + ); + // destinationChainId is NOT present on the wire — the SDK injects it at build time + expect('destinationChainId' in price.route.bridge.contractParams).toBe( + false ); + } + }); + + test('GET /v2/delta/prices/bridge-routes returns flat array', async () => { + const { getBridgeRoutes } = constructGetBridgeRoutes({ + apiURL: LIVE_API, + chainId: 1, + fetcher: fetchFetcher, }); - test('PreSign Delta Order', async () => { - const sampleOrderHash = - '0x4e68492d838e64c329ecdba51d32cb088088445ca62b1d5c4edf5a2ab80b586d'; - const txHash = await sdk.setDeltaOrderPreSignature(sampleOrderHash); - await viemWalletClient.waitForTransactionReceipt({ hash: txHash }); + const routes = await getBridgeRoutes(); + expect(Array.isArray(routes)).toBe(true); + expect(routes.length).toBeGreaterThan(0); + const first = routes[0]!; + expect(typeof first.srcChainId).toBe('number'); + expect(typeof first.destChainId).toBe('number'); + expect(Array.isArray(first.tokens)).toBe(true); + }); - const isPreSigned = await checkIfOrderHashPreSigned({ - orderHash: sampleOrderHash, - owner: senderAddress, - sdk, - }); - expect(isPreSigned).toBe(true); + test('GET /v2/delta/prices/bridge-protocols returns protocols', async () => { + const { getBridgeProtocols } = constructGetBridgeRoutes({ + apiURL: LIVE_API, + chainId: 1, + fetcher: fetchFetcher, }); + + const protocols = await getBridgeProtocols(); + expect(protocols.length).toBeGreaterThan(0); + expect(protocols.some((p) => p.protocol === 'Across')).toBe(true); }); }); -function getTokenAllowance({ - tokenAddress, - owner, - spender, -}: { - tokenAddress: string; - owner: string; - spender: string; -}): Promise { - const contract = new ethers.Contract(tokenAddress, erc20abi, signer); - return contract.allowance(owner, spender); -} - -function decreaseBySlippage(amount: string, slippagePercent: number): string { - const amountAfterSlippage = BigInt( - +(+amount * (1 - slippagePercent / 100)).toFixed(0) - ).toString(10); - - return amountAfterSlippage; -} +describe('Delta: SDK wiring', () => { + test('constructAllDeltaOrdersHandlers exposes all v2 methods', () => { + const sdk = constructAllDeltaOrdersHandlers({ + apiURL: API_URL, + chainId: 1, + fetcher: makeFetcher(() => ({})), + contractCaller: makeMockContractCaller(), + }); -type VerifySignedCancelRequestInput = { - orderId: string; - signature: string; - address: string; - chainId: number; -}; - -async function verifySignedCancelRequest({ - orderId, - signature, - address, -}: VerifySignedCancelRequestInput): Promise { - const ParaswapDelta = await constructGetDeltaContract({ - chainId, - fetcher: fetchFetcher, - }).getDeltaContract(); - - assert(ParaswapDelta, 'ParaswapDelta is not defined'); - - const valid = await verifyTypedData({ - address: address as Address, - domain: { - name: 'Portikus', - version: '2.0.0', - chainId, - verifyingContract: ParaswapDelta as Address, - }, - types: { - OrderCancellations: [{ name: 'orderIds', type: 'string[]' }], - }, - primaryType: 'OrderCancellations', - message: { - orderIds: [orderId], - }, - signature: signature as Hex, + expect(typeof sdk.getDeltaPrice).toBe('function'); + expect(typeof sdk.getDeltaOrders).toBe('function'); + expect(typeof sdk.getRequiredBalanceForDeltaOrders).toBe('function'); + expect(typeof sdk.getBridgeRoutes).toBe('function'); + expect(typeof sdk.buildDeltaOrder).toBe('function'); + expect(typeof sdk.postDeltaOrder).toBe('function'); + expect(typeof sdk.submitDeltaOrder).toBe('function'); + expect(typeof sdk.submitExternalDeltaOrder).toBe('function'); + expect(typeof sdk.submitTWAPDeltaOrder).toBe('function'); + expect(typeof sdk.cancelDeltaOrders).toBe('function'); + expect(typeof sdk.isTokenSupportedInDelta).toBe('function'); + expect(typeof sdk.getAgentsList).toBe('function'); + // reused v1 utilities + expect(typeof sdk.getDeltaContract).toBe('function'); + expect(typeof sdk.getPartnerFee).toBe('function'); + expect(typeof sdk.approveTokenForDelta).toBe('function'); + // v2 sign function (replaces v1 sign in deltaV2 namespace) + expect(typeof sdk.signDeltaOrder).toBe('function'); }); - return valid; -} + test('constructPartialSDK accepts v2 constructors individually', () => { + const fetcher = makeFetcher(() => ({})); + const sdk = constructPartialSDK( + { apiURL: API_URL, chainId: 1, fetcher }, + constructBuildDeltaOrder, + constructPostDeltaOrder, + constructGetDeltaOrders, + constructGetDeltaPrice, + constructGetDeltaContract, + constructGetPartnerFee, + constructGetBridgeRoutes, + constructIsTokenSupportedInDelta + ); -const PreSignatureModuleAbi = [ - { - inputs: [ - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'bytes32', - name: 'orderHash', - type: 'bytes32', - }, - ], - name: 'isPreSigned', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'orderHash', - type: 'bytes32', - }, - { - internalType: 'bool', - name: 'preSigned', - type: 'bool', - }, - ], - name: 'setPreSignature', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -] as const; - -type CheckIfOrderHashPreSignedInput = { - orderHash: string; - owner: string; - sdk: GetDeltaContractFunctions; -}; - -async function checkIfOrderHashPreSigned({ - orderHash, - owner, - sdk, -}: CheckIfOrderHashPreSignedInput): Promise { - const ParaswapDelta = await sdk.getDeltaContract(); - - assert(ParaswapDelta, 'ParaswapDelta is not available'); - - const isPreSigned = await viemWalletClient.readContract({ - address: ParaswapDelta as Address, - abi: PreSignatureModuleAbi, - functionName: 'isPreSigned', - args: [owner as Address, orderHash as Hash], + expect(typeof sdk.getDeltaPrice).toBe('function'); + expect(typeof sdk.getBridgeRoutes).toBe('function'); + expect(typeof sdk.getDeltaOrders).toBe('function'); + expect(typeof sdk.getRequiredBalanceForDeltaOrders).toBe('function'); + expect(typeof sdk.buildDeltaOrder).toBe('function'); + expect(typeof sdk.postDeltaOrder).toBe('function'); + expect(typeof sdk.isTokenSupportedInDelta).toBe('function'); }); - return isPreSigned; -} +}); diff --git a/tests/quote.test.ts b/tests/quote.test.ts index 5e9157796..7f8e5506b 100644 --- a/tests/quote.test.ts +++ b/tests/quote.test.ts @@ -49,51 +49,34 @@ describe('Quote:methods', () => { const staticDeltaPrice: typeof quote.delta = { ...quote.delta, - partnerFee: NaN, // dynamic number, can change slightly depending on API config - hmac: 'dynamic_string', - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', + id: 'dynamic_string', + // route + alternatives carry the dynamic amounts/USD/gas fields in v2; + // stabilized wholesale so the inline snapshot below regenerates cleanly. + route: 'dynamic_route' as unknown as typeof quote.delta.route, + alternatives: + 'dynamic_alternatives' as unknown as typeof quote.delta.alternatives, + partner: { name: quote.delta.partner.name, feePercent: NaN }, }; expect(staticDeltaPrice).toMatchInlineSnapshot(` { - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, + "alternatives": "dynamic_alternatives", + "id": "dynamic_string", + "inputToken": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "chainId": 1, }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "100000000000", - "srcToken": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "srcUSD": "dynamic_number", + "outputToken": { + "address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "chainId": 1, + }, + "partner": { + "feePercent": NaN, + "name": "anon", + }, + "route": "dynamic_route", + "side": "SELL", + "spender": "0x0000000000bbf5c5fd284e657f01bd000933c96d", } `); }); @@ -147,56 +130,34 @@ describe('Quote:methods', () => { const staticDeltaPrice: typeof quote.delta = { ...quote.delta, - partnerFee: NaN, // dynamic number - hmac: 'dynamic_string', - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', - srcAmount: 'dynamic_number', - srcAmountBeforeFee: 'dynamic_number', - srcUSDBeforeFee: 'dynamic_number', + id: 'dynamic_string', + // route + alternatives carry the dynamic amounts/USD/gas fields in v2; + // stabilized wholesale so the inline snapshot below regenerates cleanly. + route: 'dynamic_route' as unknown as typeof quote.delta.route, + alternatives: + 'dynamic_alternatives' as unknown as typeof quote.delta.alternatives, + partner: { name: quote.delta.partner.name, feePercent: NaN }, }; - // only SELL side has receivedDestAmountBeforeFee and receivedDestUSDBeforeFee - expect('receivedDestAmountBeforeFee' in quote.delta).toBeFalsy(); - expect('receivedDestUSDBeforeFee' in quote.delta).toBeFalsy(); - expect(staticDeltaPrice).toMatchInlineSnapshot(` { - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, + "alternatives": "dynamic_alternatives", + "id": "dynamic_string", + "inputToken": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "chainId": 1, + }, + "outputToken": { + "address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "chainId": 1, }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "srcAmount": "dynamic_number", - "srcAmountBeforeFee": "dynamic_number", - "srcToken": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "srcUSD": "dynamic_number", - "srcUSDBeforeFee": "dynamic_number", + "partner": { + "feePercent": NaN, + "name": "anon", + }, + "route": "dynamic_route", + "side": "BUY", + "spender": "0x0000000000bbf5c5fd284e657f01bd000933c96d", } `); }); @@ -258,51 +219,34 @@ describe('Quote:methods', () => { const staticDeltaPrice: typeof quote.delta = { ...quote.delta, - partnerFee: NaN, // dynamic number, can change slightly depending on API config - hmac: 'dynamic_string', - destAmount: 'dynamic_number', - destAmountBeforeFee: 'dynamic_number', - srcUSD: 'dynamic_number', - destUSD: 'dynamic_number', - destUSDBeforeFee: 'dynamic_number', - receivedDestAmount: 'dynamic_number', - receivedDestUSD: 'dynamic_number', - receivedDestAmountBeforeFee: 'dynamic_number', - receivedDestUSDBeforeFee: 'dynamic_number', - gasCost: 'dynamic_number', - gasCostBeforeFee: 'dynamic_number', - gasCostUSD: 'dynamic_number', - gasCostUSDBeforeFee: 'dynamic_number', + id: 'dynamic_string', + // route + alternatives carry the dynamic amounts/USD/gas fields in v2; + // stabilized wholesale so the inline snapshot below regenerates cleanly. + route: 'dynamic_route' as unknown as typeof quote.delta.route, + alternatives: + 'dynamic_alternatives' as unknown as typeof quote.delta.alternatives, + partner: { name: quote.delta.partner.name, feePercent: NaN }, }; expect(staticDeltaPrice).toMatchInlineSnapshot(` { - "bridge": { - "destinationChainId": 0, - "outputToken": "0x0000000000000000000000000000000000000000", - "protocolData": "0x", - "protocolSelector": "0x00000000", - "scalingFactor": 0, + "alternatives": "dynamic_alternatives", + "id": "dynamic_string", + "inputToken": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "chainId": 1, + }, + "outputToken": { + "address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "chainId": 1, + }, + "partner": { + "feePercent": NaN, + "name": "anon", }, - "destAmount": "dynamic_number", - "destAmountBeforeFee": "dynamic_number", - "destToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", - "destUSD": "dynamic_number", - "destUSDBeforeFee": "dynamic_number", - "gasCost": "dynamic_number", - "gasCostBeforeFee": "dynamic_number", - "gasCostUSD": "dynamic_number", - "gasCostUSDBeforeFee": "dynamic_number", - "hmac": "dynamic_string", - "partner": "anon", - "partnerFee": NaN, - "receivedDestAmount": "dynamic_number", - "receivedDestAmountBeforeFee": "dynamic_number", - "receivedDestUSD": "dynamic_number", - "receivedDestUSDBeforeFee": "dynamic_number", - "srcAmount": "100000000000", - "srcToken": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "srcUSD": "dynamic_number", + "route": "dynamic_route", + "side": "SELL", + "spender": "0x0000000000bbf5c5fd284e657f01bd000933c96d", } `); }); diff --git a/tests/viem.test.ts b/tests/viem.test.ts index 6f22982e5..c47dd09cb 100644 --- a/tests/viem.test.ts +++ b/tests/viem.test.ts @@ -33,6 +33,7 @@ const ethersProvider = new ethers.providers.Web3Provider( const signer = wallet.connect(ethersProvider); const senderAddress = signer.address as Hex; +const takerAddress: Hex = '0xc6daaec7e58c1689cb0117933f862d9d3df08daa'; const viemTestClient = createTestClient({ chain: { ...hardhat, id: chainId }, // may need to override chainId @@ -71,6 +72,7 @@ describe('SDK with viem: contract calling methods', () => { makerAmount: (1e18).toString(10), takerAmount: (8e18).toString(10), maker: senderAddress, + taker: takerAddress, }; let spender: Hex; @@ -186,22 +188,22 @@ describe('SDK with viem: contract calling methods', () => { }, 120000); test('signOrder', async () => { - const signableOrderData = await SDKwithEthers.limitOrders.buildLimitOrder( + const signableOrderData = await SDKwithEthers.otcOrders.buildOTCOrder( orderInput ); - expect(signableOrderData).toMatchSnapshot('LimitOrder to sign'); + expect(signableOrderData).toMatchSnapshot('OTCOrder to sign'); - const ethersSignature = await SDKwithEthers.limitOrders.signLimitOrder( + const ethersSignature = await SDKwithEthers.otcOrders.signOTCOrder( signableOrderData ); - const viemSignature = await SDKwithViem.limitOrders.signLimitOrder( + const viemSignature = await SDKwithViem.otcOrders.signOTCOrder( signableOrderData ); expect(viemSignature).toMatchInlineSnapshot( - `"0x18b022691daab1d8a3486aab5a006f2e98932b1c2fe4f04726c766e7a4e6d4935cbbf6d03ef945f23bef5cf4e250086f14581b1b8097f6c3ffd62653c8b2454b1b"` + `"0xa7db0debfa744bab5aec8c99365cacf2858ac32b72e717cf3bad38cd7a53aa51338f406ad8cd42e81cce0714bbdde2e25424654c384a5264afcdff0e347c187a1b"` ); expect(ethersSignature).toEqual(viemSignature); });