diff --git a/package.json b/package.json index 60592ad1..0892c22c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/types", - "version": "17.83.0", + "version": "17.84.0-alpha.0", "description": "Types for the LI.FI stack", "keywords": [ "sdk", diff --git a/src/api.ts b/src/api.ts index 28c433ec..6307b6aa 100644 --- a/src/api.ts +++ b/src/api.ts @@ -160,10 +160,54 @@ export interface RouteOptionsBase { executionType?: ExecutionType } +/** + * A single entry in the `distributionFees` request parameter. + * + * `distributionFees` lets a verified integrator carve additional on-chain + * recipients out of their integrator-fee pool, in parallel with the + * optional `intermediary` carve. Each entry produces an extra fee transfer + * to `receiver` proportional to `percentage` of the source amount, executed + * via the LI.FI FeeForwarder contract. Partner-provided receivers are + * sanction-screened at quote time (warn-log on failure, see backend logs). + * + * Constraints (enforced server-side, subject to change without a types + * major bump — read the current values from the API error responses if + * you need them programmatically): + * - `percentage` is a decimal proportion ( `0.001` = 0.1% ), exclusive of 0 + * and bounded by a per-request cap. The aggregate fee (integrator `fee` + * plus all `distributionFees[].percentage`) is also capped by the + * backend; exceeding either limit yields a `ValidationError`. + * - At most ~10 entries per request. + * - `receiver` must be a non-zero EVM address (`0x` followed by 40 hex + * characters). Non-EVM receivers are not yet supported. + * + * Only meaningful when `integrator` is set and has an active fee agreement. + */ +export interface DistributionFee { + /** Fraction of the swap input taken as a distribution fee (e.g. `0.001` = 0.1%). */ + percentage: number + /** On-chain EVM recipient address; must be a non-zero `0x`-prefixed hex address. */ + receiver: string +} + export interface RouteOptions extends RouteOptionsBase { /** Should contain the identifier of the integrator. Usually, it's dApp/company name. */ integrator?: string + /** Optional intermediary identifier for multi-party fee splitting. + * Requires a registered integrator with a `fee` and a configured intermediary share on the backend. */ + intermediary?: string + + /** + * Partner-provided fee distribution recipients. Each entry adds an + * independent on-chain transfer to `receiver` in proportion to + * `percentage` of the swap input, in parallel with the integrator and + * (optional) intermediary carves. Requires a verified `integrator` with + * an active fee agreement. + * @see {@link DistributionFee} for per-entry constraints. + */ + distributionFees?: DistributionFee[] + /** Integrators can set a wallet address as a referrer to track them */ referrer?: string @@ -368,6 +412,11 @@ export interface QuoteRequest extends ToolConfiguration, TimingStrings { order?: Order slippage?: number | string integrator?: string + /** Optional intermediary identifier for multi-party fee splitting. + * Requires a registered integrator with a `fee` and a configured intermediary share on the backend. */ + intermediary?: string + /** @see {@link RouteOptions.distributionFees} and {@link DistributionFee} */ + distributionFees?: DistributionFee[] referrer?: string fee?: number | string @@ -406,8 +455,10 @@ export interface QuoteRequest extends ToolConfiguration, TimingStrings { insurance?: boolean } -export interface QuoteToAmountRequest - extends Omit { +export interface QuoteToAmountRequest extends Omit< + QuoteRequest, + 'fromAmount' | 'fromAmountForGas' | 'insurance' +> { toAmount: string } @@ -850,8 +901,7 @@ export type TransferSummary = { totalReceivedAmount: number } -export interface TransferSummariesResponse - extends PaginatedResponse {} +export interface TransferSummariesResponse extends PaginatedResponse {} export interface GetStepRequest { stepId: string diff --git a/src/step.ts b/src/step.ts index 7fa05e31..1c6fe792 100644 --- a/src/step.ts +++ b/src/step.ts @@ -6,6 +6,78 @@ import type { } from './api.js' import type { Token } from './tokens/index.js' +/** + * How a fee was calculated / the role of the recipient in the split. + * + * - `FIXED` — a fixed LI.FI cut applied alongside the integrator's own fee. + * - `SHARED` — a single shared pool divided between LI.FI and the integrator. + * - `DYNAMIC` — fee resolved at quote time from configured rules (e.g. dynamic + * stablecoin pricing). + * - `INTERMEDIARY` — a third-party recipient that carves a configured share + * from the integrator pool (e.g. a widget or aggregator). + * - `DISTRIBUTION` — a partner-specified extra recipient added in parallel to + * the integrator/intermediary split via the `distributionFees` request param. + * + * The union is expected to grow over time. When pattern-matching with a + * `switch`, always include a `default` branch so adding a new value remains + * a non-breaking minor for consumers. + */ +export type FeeSplitType = + | 'FIXED' + | 'SHARED' + | 'DYNAMIC' + | 'INTERMEDIARY' + | 'DISTRIBUTION' + +export interface FeeRecipient { + /** Recipient identifier. Polymorphic — interpret in conjunction with `type`: + * - `'lifi'` for the LI.FI platform recipient, + * - the integrator id (e.g. `'jumper'`) for the integrator recipient, + * - the intermediary id (e.g. `'mesh'`) when `type === 'INTERMEDIARY'`, + * - the recipient wallet address when `type === 'DISTRIBUTION'`. + * + * Do not display this value directly in user-facing UI without + * `type`-aware formatting — for `DISTRIBUTION` rows the value is a + * raw hex address. */ + name: string + + /** Absolute fee amount, a big number in source token base units (string-encoded). */ + fee: string + + /** Fee calculation type. Absent when not statically determinable (e.g. + * an integrator entry whose `feeType` could not be resolved from the + * matching planned fee cost). Consumers should null-check before reading. */ + type?: FeeSplitType + + /** Recipient wallet address on the source chain. */ + walletAddress?: string +} + +export interface FeeSplit { + /** LI.FI's slice of THIS `FeeCost.amount`. */ + lifiFee: string + + /** The integrator's slice of THIS `FeeCost.amount` — the integrator's + * portion only, NOT including any intermediary or distribution amounts. */ + integratorFee: string + + /** The intermediary's slice of THIS `FeeCost.amount` when an intermediary + * participates in the split. Absent otherwise. */ + intermediaryFee?: string + + /** Per-recipient breakdown of THIS `FeeCost.amount`. Source of truth for + * new consumers — the aggregate fields above are disjoint slices kept + * for backward compatibility with 2-recipient consumers. + * + * Note: partner-specified distribution recipients are emitted as + * separate `FeeCost` entries (one per receiver, `name: "Fee Forward"`) + * at quote/route estimation time. At status-response time the same + * recipients may appear merged on the integrator's `FeeCost` for + * compactness. Iterate `estimate.feeCosts[]` to discover all + * recipients across both shapes. */ + recipients?: FeeRecipient[] +} + export interface FeeCost { name: string description: string @@ -14,6 +86,8 @@ export interface FeeCost { amount: string amountUSD: string included: boolean + + feeSplit?: FeeSplit } export interface GasCost { @@ -101,6 +175,9 @@ export interface StepBase { tool: StepTool toolDetails: StepToolDetails integrator?: string + /** Intermediary identifier set when the route was generated with a multi-party fee split. + * Threaded through to /stepTransaction so the same split can be reproduced at tx-generation time. */ + intermediary?: string referrer?: string action: Action estimate?: Estimate