@lifi/composer-sdk
Version:
Public Composer SDK for building and submitting flows
129 lines (124 loc) • 4.67 kB
text/typescript
import type {
ComposeRun,
InputSpec,
MaterialiserInput,
Precondition,
SimulationPolicy,
SweepTo,
} from '@lifi/compose-spec';
import type { Address, InputSchema, InputSpecOf } from '../types.js';
/**
* Runtime inputs for compiling a flow. Passed to `builder.compile()` or `sdk.request()`.
*
* @typeParam T - The flow's input schema, used to type-check `inputs` and `assumptions`.
*/
export interface ComposeRunInput<T extends InputSchema = InputSchema> {
/**
* Concrete values for each declared flow input. Resource inputs accept a
* materialiser or a literal integer amount; scalar inputs accept the matching type.
*/
readonly inputs: { readonly [K in keyof T]: InputSpecOf<T[K]> };
/** Optional preconditions that must hold before the flow executes (e.g. minimum balances). */
readonly preconditions?: readonly Precondition[];
/** The `0x`-prefixed address of the transaction signer. */
readonly signer: Address;
/**
* Optional assumed token amounts for resource inputs, keyed by input name.
* When a materialiser resolves amounts at execution time rather than upfront,
* assumptions let the compiler plan routes using estimated values. The keys
* must match the input names declared in the flow schema.
*/
readonly assumptions?: { readonly [K in keyof T]?: bigint };
/** Optional integrator referrer identifier. */
readonly referrer?: string;
/**
* Optional integrator fee in basis points (1bp = 0.01%, max `9000` = 90%).
* A non-zero value requires the request to be authenticated with an
* integration-scoped API key — the integration is derived from the key, not
* this field. Defaults to `0` (no fee) when omitted.
*/
readonly integratorFeeBps?: number;
/** Maximum acceptable price impact in basis points (e.g. `300` = 3%). */
readonly maxPriceImpactBps?: number;
/**
* Destination for sweeping all proxy-held terminal resources after execution.
* Pass a literal `0x`-prefixed address or `{ $ref: "context.sender" }` to
* send remaining tokens to the signer.
*/
readonly sweepTo?: SweepTo;
/**
* Controls behavior when simulation detects a revert.
* `'strict'` (default) returns an error; `'allow-revert'` returns a partial
* result with the transaction and revert diagnostics.
*/
readonly simulationPolicy?: SimulationPolicy;
/**
* When `true`, the server checks on-chain ERC-20 allowances and omits
* approvals that are already sufficient. Defaults to `false`.
*/
readonly checkOnChainAllowances?: boolean;
}
/**
* Creates an untyped materialiser input spec. This is a low-level escape hatch
* for materialiser kinds not yet covered by the generated helpers.
*
* Prefer the typed helpers in the `materialisers` namespace (e.g.
* `materialisers.balanceOf()`, `materialisers.directDeposit()`) which provide
* compile-time config validation.
*
* @param kind - The materialiser type (e.g. `"balanceOf"`, `"directDeposit"`).
* @param config - Optional materialiser-specific configuration.
* @returns A {@link MaterialiserInput} for use in {@link ComposeRunInput.inputs}.
*
* @example
* ```ts
* const run = {
* inputs: { token: materialiser('customKind', { myParam: '0x...' }) },
* signer: '0x...',
* };
* ```
*/
export const materialiser = (
kind: string,
config: Record<string, unknown> = {},
): MaterialiserInput => ({
kind,
...config,
});
/**
* Assembles a {@link ComposeRun} object from individual parameters.
* Used internally by the SDK; prefer {@link ComposeRunInput} for external use.
*
* @internal
*/
export const buildRun = (run: {
inputs: Record<string, InputSpec>;
preconditions?: readonly Precondition[];
signer: string;
assumptions?: Record<string, bigint>;
referrer?: string;
integratorFeeBps?: number;
maxPriceImpactBps?: number;
sweepTo?: SweepTo;
simulationPolicy?: SimulationPolicy;
checkOnChainAllowances?: boolean;
}): ComposeRun => ({
inputs: run.inputs,
...(run.preconditions?.length && { preconditions: run.preconditions }),
signer: run.signer,
...(run.assumptions && { assumptions: run.assumptions }),
...(run.referrer !== undefined && { referrer: run.referrer }),
...(run.integratorFeeBps !== undefined && {
integratorFeeBps: run.integratorFeeBps,
}),
...(run.maxPriceImpactBps !== undefined && {
maxPriceImpactBps: run.maxPriceImpactBps,
}),
...(run.sweepTo !== undefined && { sweepTo: run.sweepTo }),
...(run.simulationPolicy !== undefined && {
simulationPolicy: run.simulationPolicy,
}),
...(run.checkOnChainAllowances !== undefined && {
checkOnChainAllowances: run.checkOnChainAllowances,
}),
});