Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions examples/node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# LI.FI SDK Node.js Examples

This directory contains example scripts demonstrating various features of the `@lifi/sdk` package.

## Prerequisites

1. Copy `.env-template` to `.env` and add your private key:
```bash
cp .env-template .env
```

2. Install dependencies:
```bash
pnpm install
```

3. Ensure your wallet has small amounts of tokens on the respective chains.

## Examples Overview

| Script | Description | Chains | Approx. Cost |
|--------|-------------|--------|--------------|
| `swap.ts` | Same-chain token swap | Optimism | ~$0.10 |
| `bridge.ts` | Cross-chain token bridge | Optimism → Arbitrum | ~$0.10 |
| `multihop.ts` | Multi-hop bridge with intermediate chain | Arbitrum → Polygon → Optimism | ~$0.10 |
| `toAmount.ts` | Bridge with exact output amount | Arbitrum → Optimism | ~$0.10 |
| `klimaRetireExactCarbon.ts` | Carbon offset via Klima DAO | Optimism → Polygon | ~$0.10 |
| `polynomialDeposit.ts` | DeFi deposit to Polynomial | Arbitrum → Optimism | ~$0.40 |
| `yearnDeposit.ts` | DeFi deposit to Yearn vault | Arbitrum → Polygon | ~$0.40 |

---

## Script Details

### `swap.ts` - Same-Chain Token Swap

**What it tests:** Basic token swap on a single chain using `getRoutes` and `executeRoute`.

**Flow:**
1. Creates an SDK client with EthereumProvider
2. Requests a route for USDC → USDT swap on Optimism
3. Executes the route with automatic transaction handling

**Key SDK features:**
- `createClient()` - Initialize SDK
- `getRoutes()` - Get swap/bridge routes
- `executeRoute()` - Execute a route with full lifecycle management

**Run:** `pnpm example:swap`

---

### `bridge.ts` - Cross-Chain Token Bridge

**What it tests:** Bridging tokens between two different chains with chain switching.

**Flow:**
1. Creates SDK client with `switchChain` callback for multi-chain support
2. Requests a route for USDC bridge from Optimism to Arbitrum
3. Executes the bridge with automatic chain switching if needed

**Key SDK features:**
- `EthereumProvider({ switchChain })` - Handle chain switching during execution
- Cross-chain route execution

**Run:** `pnpm example:bridge`

---

### `multihop.ts` - Multi-Hop Bridge

**What it tests:** Complex bridging scenario using contract calls to chain multiple bridges.

**Flow:**
1. Gets a quote for the second bridge leg (Polygon → Optimism)
2. Creates a contract calls quote that bridges to Polygon AND executes the second bridge
3. Manually sends the transaction and polls for status

**Key SDK features:**
- `getQuote()` - Get a single-step quote
- `getContractCallsQuote()` - Get quote with destination contract calls
- `getStatus()` - Poll transaction status
- Manual transaction execution (without `executeRoute`)

**Run:** `pnpm example:multihop`

---

### `toAmount.ts` - Exact Output Amount

**What it tests:** Bridging with a specific target output amount (reverse quote).

**Flow:**
1. Requests a quote where `toAmount` is specified instead of `fromAmount`
2. SDK calculates required input amount
3. Executes the transaction manually

**Key SDK features:**
- `getContractCallsQuote({ toAmount })` - Reverse quote calculation
- Token allowance checking and setting

**Run:** `pnpm example:toAmount`

---

### `klimaRetireExactCarbon.ts` - Carbon Offset Integration

**What it tests:** Cross-chain contract call to Klima DAO for carbon retirement.

**Flow:**
1. Reads Klima contract to calculate required token amount
2. Encodes the `retireExactCarbonDefault` function call
3. Creates a contract calls quote that bridges tokens AND retires carbon
4. Executes and monitors the transaction

**Key SDK features:**
- `getContractCallsQuote({ contractCalls })` - Execute arbitrary contract calls on destination
- Integration with external DeFi protocols

**Run:** `pnpm example:klima`

---

### `polynomialDeposit.ts` - DeFi Protocol Deposit

**What it tests:** Cross-chain deposit into Polynomial Earn vault.

**Flow:**
1. Encodes `initiateDeposit` function call for Polynomial contract
2. Creates quote to bridge sETH to Optimism and deposit in one transaction
3. Executes and monitors

**Key SDK features:**
- Cross-chain DeFi integrations
- Contract call encoding with destination protocol

**Run:** `pnpm example:polynomial`

---

### `yearnDeposit.ts` - Yearn Vault Deposit

**What it tests:** Cross-chain deposit into Yearn Finance vault.

**Flow:**
1. Encodes `deposit` function call for Yearn vault
2. Creates quote to bridge WETH to Polygon and deposit
3. Handles both same-chain and cross-chain scenarios

**Key SDK features:**
- Yearn protocol integration
- Conditional status polling (skipped for same-chain)

**Run:** `pnpm example:yearn`

---

## Utility Files

### `utils/checkTokenAllowance.ts`
Helper to check and set ERC20 token allowances before transactions.

### `utils/transformTxRequestToSendTxParams.ts`
Transforms SDK transaction request format to viem's `sendTransaction` parameters.

### `helpers/promptConfirm.ts`
Interactive confirmation prompt before executing transactions.

### `helpers/reportStepsExecutionToTerminal.ts`
Callback to log execution progress to the terminal.

---

## Safety Notes

⚠️ **These examples execute REAL transactions on mainnet chains.**

- All amounts are intentionally small (~$0.10-0.40)
- Each script prompts for confirmation before executing
- Use a dedicated test wallet with minimal funds
- Review the route details before confirming
43 changes: 21 additions & 22 deletions examples/node/examples/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { findDefaultToken } from '@lifi/data-types'
import {
ChainId,
CoinKey,
createConfig,
EVM,
createClient,
executeRoute,
getRoutes,
} from '@lifi/sdk'
import { EthereumProvider } from '@lifi/sdk-provider-ethereum'
import type { Address, Chain } from 'viem'
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
Expand All @@ -25,38 +25,37 @@ async function run() {
// but you can also use a Mnemonic account - see https://viem.sh/docs/accounts/mnemonic
const account = privateKeyToAccount(privateKey)

const client = createWalletClient({
const walletClient = createWalletClient({
account,
chain: optimism as Chain,
transport: http(),
})

const switchChains = [mainnet, arbitrum, optimism, polygon] as Chain[]

createConfig({
const client = createClient({
integrator: 'lifi-sdk-example',
providers: [
EVM({
getWalletClient: () => Promise.resolve(client),
switchChain: (chainId) =>
Promise.resolve(
createWalletClient({
account,
chain: switchChains.find(
(chain) => chain.id === chainId
) as Chain,
transport: http(),
})
),
}),
],
})

client.setProviders([
EthereumProvider({
getWalletClient: () => Promise.resolve(walletClient),
switchChain: (chainId) =>
Promise.resolve(
createWalletClient({
account,
chain: switchChains.find((chain) => chain.id === chainId) as Chain,
transport: http(),
})
),
}),
])

const routeRequest = {
toAddress: account.address,
fromAddress: account.address,
fromChainId: ChainId.OPT, // Optimism
fromAmount: '1000000', // 1 USDC
fromAmount: '100000', // 0.1 USDC
fromTokenAddress: findDefaultToken(CoinKey.USDC, ChainId.OPT).address, // USDC on Optimism
toChainId: ChainId.ARB, // Arbitrum
toTokenAddress: findDefaultToken(CoinKey.USDC, ChainId.ARB).address,
Expand All @@ -67,7 +66,7 @@ async function run() {

console.info('>> Requesting route', routeRequest)

const routeResponse = await getRoutes(routeRequest)
const routeResponse = await getRoutes(client, routeRequest)
const route = routeResponse.routes[0]

console.info('>> Got Route', routeResponse)
Expand All @@ -82,7 +81,7 @@ async function run() {
const executionOptions = {
updateRouteHook: reportStepsExecutionToTerminal,
}
await executeRoute(route, executionOptions)
await executeRoute(client, route, executionOptions)

console.info('>> Done')
}
Expand Down
55 changes: 31 additions & 24 deletions examples/node/examples/klimaRetireExactCarbon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import type { ContractCallsQuoteRequest, StatusResponse } from '@lifi/sdk'
import {
ChainId,
CoinKey,
createConfig,
EVM,
createClient,
getContractCallsQuote,
getStatus,
} from '@lifi/sdk'
import { EthereumProvider } from '@lifi/sdk-provider-ethereum'
import type { Address, Chain } from 'viem'
import {
createPublicClient,
Expand Down Expand Up @@ -36,33 +36,34 @@ const run = async () => {
// but you can also use a Mnemonic account - see https://viem.sh/docs/accounts/mnemonic
const account = privateKeyToAccount(privateKey)

const client = createWalletClient({
const walletClient = createWalletClient({
account,
chain: optimism as Chain,
transport: http(),
}).extend(publicActions)

const switchChains = [mainnet, arbitrum, optimism, polygon] as Chain[]

createConfig({
const client = createClient({
integrator: 'lifi-sdk-example',
providers: [
EVM({
getWalletClient: () => Promise.resolve(client),
switchChain: (chainId) =>
Promise.resolve(
createWalletClient({
account,
chain: switchChains.find(
(chain) => chain.id === chainId
) as Chain,
transport: http(),
})
),
}),
],
})

client.setProviders([
EthereumProvider({
getWalletClient: () => Promise.resolve(walletClient),
switchChain: (chainId) =>
Promise.resolve(
createWalletClient({
account,
chain: switchChains.find(
(chain) => chain.id === chainId
) as Chain,
transport: http(),
})
),
}),
])

// config for klima contract run - https://docs.klimadao.finance/developers/contracts/retirement/v2-diamond/generalized-retirement
const config = {
fromChain: ChainId.OPT,
Expand Down Expand Up @@ -151,6 +152,7 @@ const run = async () => {
)

const contactCallsQuoteResponse = await getContractCallsQuote(
client,
contractCallsQuoteRequest
)
console.info('>> Quote received', contactCallsQuoteResponse)
Expand All @@ -159,22 +161,27 @@ const run = async () => {
return
}

await checkTokenAllowance(contactCallsQuoteResponse, account, client)
await checkTokenAllowance(
client,
contactCallsQuoteResponse,
account,
walletClient
)

console.info(
'>> Execute transaction',
contactCallsQuoteResponse.transactionRequest
)

const hash = await client.sendTransaction(
const hash = await walletClient.sendTransaction(
transformTxRequestToSendTxParams(
client.account,
walletClient.account,
contactCallsQuoteResponse.transactionRequest
)
)
console.info('>> Transaction sent', hash)

const receipt = await client.waitForTransactionReceipt({
const receipt = await walletClient.waitForTransactionReceipt({
hash,
})
console.info('>> Transaction receipt', receipt)
Expand All @@ -188,7 +195,7 @@ const run = async () => {
}, 5000)
})

result = await getStatus({
result = await getStatus(client, {
txHash: receipt.transactionHash,
bridge: contactCallsQuoteResponse.tool,
fromChain: contactCallsQuoteResponse.action.fromChainId,
Expand Down
Loading