@lifi/compose-spec
Version:
Public wire-format types and schemas for Compose flows
90 lines (75 loc) • 2.36 kB
text/typescript
import { EVM_NATIVE_SENTINEL } from './chainCapabilities.js';
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);
// Canonical address representation of a resource for consumers whose wire
// contract uses the EVM-native sentinel rather than the Resource union.
export const resourceToken = (r: Resource): string =>
foldResource(r, {
native: () => EVM_NATIVE_SENTINEL,
erc20: (token) => token,
});
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;
};