@lifi/compose-spec
Version:
Public wire-format types and schemas for Compose flows
80 lines (67 loc) • 2 kB
text/typescript
export type Availability = "now" | "future";
export interface OutputAmount {
readonly expected: bigint;
readonly min?: bigint;
}
export type Resource =
| { readonly kind: "native"; readonly chainId: number }
| {
readonly kind: "erc20";
readonly token: string;
readonly chainId: number;
};
export type SimulatedAmounts = {
readonly amountOut: bigint;
readonly amountOutMin: bigint;
};
export type ProducedResource = Resource & {
readonly availability: Availability;
readonly simulated?: SimulatedAmounts;
readonly owner: string;
};
export const erc20Resource = (token: string, chainId: number): Resource => ({
kind: "erc20",
token,
chainId,
});
export const nativeResource = (chainId: number): Resource => ({
kind: "native",
chainId,
});
export const isERC20Resource = (
r: Resource,
): r is Extract<Resource, { kind: "erc20" }> => r.kind === "erc20";
export const isNativeResource = (
r: Resource,
): r is Extract<Resource, { kind: "native" }> => r.kind === "native";
export const resourcesEqual = (a: Resource, b: Resource): boolean => {
if (isNativeResource(a) && isNativeResource(b)) {
return a.chainId === b.chainId;
}
if (isERC20Resource(a) && isERC20Resource(b)) {
return (
a.chainId === b.chainId && a.token.toLowerCase() === b.token.toLowerCase()
);
}
return false;
};
export const foldResource = <R>(
r: Resource,
cases: {
readonly native: (chainId: number) => R;
readonly erc20: (token: string, chainId: number) => R;
},
): R =>
r.kind === "native"
? cases.native(r.chainId)
: cases.erc20(r.token, r.chainId);
export const resourceKey = (r: Resource): string =>
foldResource(r, {
native: (chainId) => `native:${chainId}`,
erc20: (token, chainId) => `erc20:${token.toLowerCase()}:${chainId}`,
});
export const erc20Token = (r: Resource): string => {
if (r.kind !== "erc20")
throw new Error(`Expected erc20 resource, got ${r.kind}`);
return r.token;
};