@lifi/composer-sdk
Version:
Public Composer SDK for building and submitting flows
206 lines (193 loc) • 8.76 kB
text/typescript
/**
* Example harness — builds a request and sends it to a live compose backend.
*
* Usage:
* COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>
*
* Pass LIFI_API_KEY to authenticate:
* LIFI_API_KEY=your-key COMPOSER_BASE_URL=https://composer.li.quest yarn example <name>
*
* Available examples:
* aave-repay — repay an Aave v3 WETH debt by supplying WETH
* aave-repay-atoken — repay an Aave v3 USDC debt by burning proxy aTokens
* aave-claim — claim AAVE rewards and forward to a recipient
* approve-deposit — approve vault allowance then deposit USDC
* consolidate — consolidate ERC-20 balances to USDC
* consolidate-eth — consolidate ERC-20 balances to native ETH
* deposit-proxy — deposit tokens already on the proxy into Aave
* dust-sweep — split USDC 80/20 and sweep leftover dust
* swap — swap WETH to USDC via LI.FI
* swap-fee — swap WETH to USDC with a 50 bps integrator fee
* split-zap — split USDC 60/40 and zap into Aave + Morpho vaults
* split-arithmetic — split USDC 70/30 with arithmetic assertions
* zap — zap USDC into Aave lending position
* swap-zap — swap WETH to USDC then zap into Aave
* swap-check — swap WETH to USDC with balance check
* swap-recipient — swap WETH + DAI to USDC and send to recipient
* swap-validate — swap WETH to USDC with output validation bounds
* swap-allow-revert — swap WETH to USDC with allow-revert policy
* raw-call — query a contract with raw calldata + arithmetic
* read-state — read on-chain state via peek, staticCall, balanceOf
* redeem — redeem ERC-4626 vault shares via core.call
* claim — claim rewards from a contract (resource-free call)
* wrap-eth — wrap native ETH into WETH via ValueCall
* transfer — transfer full token balance to a recipient
* partial-transfer — transfer a specific amount, keeping the remainder
* untyped-ref — mix untypedOp with typed handles via raw.ref
*/
import type { ComposeCompileRequest } from '@lifi/compose-spec';
import { createComposeSdk } from '../sdk.js';
import { buildAaveClaimRewards } from './aaveClaimRewards.js';
import { buildAaveRepay } from './aaveRepay.js';
import { buildAaveRepayWithATokens } from './aaveRepayWithATokens.js';
import { buildApproveAndDeposit } from './approveAndDeposit.js';
import {
buildClaimRewards,
buildRedeemFromVault,
buildWrapEth,
} from './callContract.js';
import { API_KEY, BASE_URL, OWNER, PROXY, RECIPIENT } from './config.js';
import { buildConsolidateToEth } from './consolidateToEth.js';
import { buildConsolidateStablesToUsdc } from './consolidateToUsdc.js';
import { buildDepositFromProxy } from './depositFromProxy.js';
import { buildDustSweepExample } from './dustSweep.js';
import { buildLifiSwapExample } from './lifiSwap.js';
import { buildLifiZapExample } from './lifiZap.js';
import { buildRawCallWithArithmetic } from './rawCallWithArithmetic.js';
import { buildReadContractState } from './readContractState.js';
import { buildSplitAndZapExample } from './splitAndZap.js';
import { buildSplitWithArithmetic } from './splitWithArithmetic.js';
import { buildSwapAndZapExample } from './swapAndZap.js';
import { buildSwapToRecipient } from './swapToRecipient.js';
import { buildSwapWithAllowRevertExample } from './swapWithAllowRevert.js';
import { buildSwapWithBalanceCheck } from './swapWithBalanceCheck.js';
import { buildSwapWithFeeExample } from './swapWithFee.js';
import { buildSwapWithOutputValidation } from './swapWithOutputValidation.js';
import { buildPartialTransfer, buildTransferTokens } from './transferTokens.js';
import { buildUntypedOpWithTypedRef } from './untypedOpWithTypedRef.js';
const EXAMPLES: Record<string, () => ComposeCompileRequest> = {
'aave-repay': () =>
buildAaveRepay({ owner: OWNER, amount: '500000000000000000' }).request,
'aave-repay-atoken': () =>
buildAaveRepayWithATokens({
owner: OWNER,
proxyAddress: PROXY,
expectedATokenBalance: '1000000000',
}).request,
'aave-claim': () =>
buildAaveClaimRewards({ owner: OWNER, recipient: RECIPIENT }).request,
'approve-deposit': () =>
buildApproveAndDeposit({ owner: OWNER, amount: '1000000000' }).request,
consolidate: () =>
buildConsolidateStablesToUsdc({
owner: OWNER,
usdtAmount: '1000000000',
daiAmount: '1000000000000000000000',
fraxAmount: '1000000000000000000000',
lusdAmount: '1000000000000000000000',
}).request,
'consolidate-eth': () =>
buildConsolidateToEth({
owner: OWNER,
wethAmount: '1000000000000000000',
usdcAmount: '1000000000',
usdtAmount: '1000000000',
daiAmount: '1000000000000000000000',
}).request,
'deposit-proxy': () =>
buildDepositFromProxy({
owner: OWNER,
proxyAddress: PROXY,
expectedAmount: '1000000000',
}).request,
'dust-sweep': () => buildDustSweepExample().request,
swap: () => buildLifiSwapExample().request,
'swap-fee': () => buildSwapWithFeeExample().request,
'split-zap': () => buildSplitAndZapExample().request,
'split-arithmetic': () =>
buildSplitWithArithmetic({ owner: OWNER, amount: '1000000000' }).request,
zap: () => buildLifiZapExample().request,
'swap-zap': () => buildSwapAndZapExample().request,
'swap-check': () =>
buildSwapWithBalanceCheck({ owner: OWNER, amount: '1000000000000000000' })
.request,
'swap-recipient': () =>
buildSwapToRecipient({
owner: OWNER,
recipient: RECIPIENT,
wethAmount: '1000000000000000000',
daiAmount: '500000000000000000000',
}).request,
'swap-validate': () =>
buildSwapWithOutputValidation({
owner: OWNER,
amount: '1000000000000000000',
expectedOut: '3000000000',
}).request,
'swap-allow-revert': () => buildSwapWithAllowRevertExample().request,
'raw-call': () => buildRawCallWithArithmetic({ owner: OWNER }).request,
'read-state': () => buildReadContractState({ owner: OWNER }).request,
redeem: () =>
buildRedeemFromVault({ owner: OWNER, amount: '1000000000000000000' })
.request,
claim: () => buildClaimRewards({ owner: OWNER }).request,
'wrap-eth': () =>
buildWrapEth({ owner: OWNER, amount: '1000000000000000000' }).request,
transfer: () =>
buildTransferTokens({
owner: OWNER,
recipient: RECIPIENT,
amount: '1000000000',
}).request,
'partial-transfer': () =>
buildPartialTransfer({
owner: OWNER,
recipient: RECIPIENT,
amount: '1000000000',
}).request,
'untyped-ref': () => buildUntypedOpWithTypedRef({ owner: OWNER }).request,
};
const run = async () => {
const args = process.argv.slice(2);
const useStaged = args.includes('--staged');
const name = args.find((arg) => arg !== '--staged');
// Staged examples live under examples/staged/ and reference not-yet-prod
// definitions, so they are deliberately excluded from this production file's
// type-check. With --staged, pull their registry in via a NON-LITERAL dynamic
// import (kept `any` to tsc, so the staged files are not dragged into the
// production program). Requires the SDK to have been regenerated with
// `yarn generate --staged` first, so the staged ops/materialisers exist at
// runtime; run `yarn generate` afterwards to restore the production surface.
let examples: Record<string, () => ComposeCompileRequest> = EXAMPLES;
if (useStaged) {
const stagedModule = (await import(
`${import.meta.dirname}/staged/registry.js`
)) as { STAGED_EXAMPLES: Record<string, () => ComposeCompileRequest> };
examples = { ...EXAMPLES, ...stagedModule.STAGED_EXAMPLES };
}
const builder = name ? examples[name] : undefined;
if (!builder) {
const valid = Object.keys(examples).join(', ');
console.error(
`Error: ${
name ? `unknown example "${name}"` : 'no example specified'
}\n` +
`Valid examples: ${valid}\n` +
`Usage: COMPOSER_BASE_URL=https://composer.li.quest yarn example [--staged] <name>`,
);
process.exit(1);
}
console.log(`Running example: ${name}`);
const request = builder();
const sdk = createComposeSdk({ baseUrl: BASE_URL, apiKey: API_KEY });
console.log('--- Request ---');
console.log(JSON.stringify(request, null, 2));
console.log(`\n--- Compiling against ${BASE_URL} ---`);
const result = await sdk.client.compile(request);
console.log('\n--- Result ---');
console.log(JSON.stringify(result, null, 2));
};
run().catch((err: unknown) => {
console.error(err);
process.exit(1);
});