Overview
Fund mode implements input-driven deposit flows where users select the amount they want to send. The widget automatically routes funds from any supported chain/token to the destination.
Trade Type: EXACT_INPUT - User specifies input amount, variable output amount after fees.
Configuration
Required Props
| Prop | Type | Description |
|---|
apiKey | string | Your project access key provided by Trails |
mode | "fund" | Sets the widget to fund mode |
Optional Props
| Prop | Type | Description |
|---|
toAmount | string | Pre-set deposit amount (user can still modify) |
toAddress | string | Destination address or contract |
toChainId | number | Destination chain ID |
toToken | string | Destination token symbol or address |
toCalldata | string | Calldata to execute on destination |
slippageTolerance | string | number | Slippage tolerance (default: 0.5%) |
swapProvider | RouteProvider | Swap provider: "AUTO", "LIFI", "RELAY", "SUSHI", "ZEROX", "CCTP" |
bridgeProvider | RouteProvider | Bridge provider: "AUTO", "LIFI", "RELAY", "CCTP" |
Implementation
Basic Chain Funding
Simple deposit to a chain:
import { TrailsWidget } from '0xtrails/widget'
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0x97c4A952b46bEcaD0663f76357d3776ba11566E1"
toChainId={8453} // Base
toToken="USDC"
onCheckoutComplete={({ sessionId }) => {
console.log('Deposit completed:', sessionId)
}}
>
<button>Deposit to Base</button>
</TrailsWidget>
Deposit with Fiat Onramp
Fiat onramp functionality is enabled by default in fund mode, allowing users to purchase crypto with credit/debit cards, bank transfers, and other payment methods.
fundOnramp and buyCryptoOnramp props have been removed. Onramp funding is now enabled by default, so you can drop those props from your widget configuration.
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0x97c4A952b46bEcaD0663f76357d3776ba11566E1"
toChainId={8453} // Base
toToken="USDC"
onCheckoutComplete={({ sessionId }) => {
console.log('Deposit completed:', sessionId)
}}
>
<button>Deposit to Base</button>
</TrailsWidget>
Fixed Amount Deposit
Pre-populate a specific amount:
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0x..."
toAmount="100" // Pre-filled, user can change
toChainId={8453}
toToken="USDC"
>
<button>Deposit 100 USDC</button>
</TrailsWidget>
Protocol Deposit with Static Calldata
Deposit into a DeFi protocol with predefined parameters:
import { TrailsWidget } from '0xtrails/widget'
import { encodeFunctionData } from 'viem'
const aaveDepositCalldata = encodeFunctionData({
abi: [{
name: 'depositETH',
type: 'function',
stateMutability: 'payable',
inputs: [
{ name: 'pool', type: 'address' },
{ name: 'onBehalfOf', type: 'address' },
{ name: 'referralCode', type: 'uint16' },
],
outputs: [],
}],
functionName: 'depositETH',
args: [
'0xA238Dd80C259a72e81d7e4664a9801593F98d1c5', // Aave pool
'0x97c4A952b46bEcaD0663f76357d3776ba11566E1', // User address
0, // No referral code
],
})
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24" // Aave Pool on Base
toAmount="100"
toChainId={8453}
toToken="USDC"
toCalldata={aaveDepositCalldata}
/>
Dynamic Amount Protocol Deposit
Use placeholder amount for user-selected deposit amounts in calldata:
import { TrailsWidget, TRAILS_ROUTER_PLACEHOLDER_AMOUNT } from '0xtrails'
import { encodeFunctionData } from 'viem'
// Encode vault deposit with placeholder that gets replaced at execution
const vaultDepositCalldata = encodeFunctionData({
abi: [{
name: 'deposit',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'amount', type: 'uint256' },
{ name: 'receiver', type: 'address' },
],
outputs: [{ name: 'shares', type: 'uint256' }],
}],
functionName: 'deposit',
args: [
TRAILS_ROUTER_PLACEHOLDER_AMOUNT, // Replaced with actual bridged amount
'0x97c4A952b46bEcaD0663f76357d3776ba11566E1', // Receiver
],
})
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0x80c34BD3A3569E126e7055831036aa7b212cB159" // Yearn Vault
toChainId={747474} // Katana
toToken="USDC"
toCalldata={vaultDepositCalldata}
>
<button>Deposit to Yearn Vault</button>
</TrailsWidget>
Dynamic Calldata Pattern
When the deposit amount is part of the calldata and user-selected, use TRAILS_ROUTER_PLACEHOLDER_AMOUNT:
Why it’s needed: In fund mode, the final output amount after swaps/bridging isn’t known until execution. The placeholder gets replaced with the actual output amount.
When to use:
- ERC-4626 vault deposits with dynamic amounts
- Staking contracts that require amount parameter
- Any function where amount is a parameter and user-selectable
When not needed:
- Simple transfers to addresses
- Static calldata where amount isn’t a parameter
- Functions that read balance directly (e.g.,
depositAll())
Event Handlers
<TrailsWidget
apiKey="YOUR_API_KEY"
mode="fund"
toAddress="0x..."
toChainId={8453}
toToken="USDC"
onCheckoutStart={({ sessionId }) => {
console.log('Deposit started:', sessionId)
}}
onCheckoutComplete={({ sessionId }) => {
console.log('Deposit completed:', sessionId)
// Update TVL, refresh balances, etc.
}}
onCheckoutError={({ sessionId, error }) => {
console.error('Deposit failed:', error)
// Handle error appropriately
}}
/>
Use Cases
- Chain Onboarding: Help users get started on new chains
- Protocol Deposits: Deposit into lending protocols (Aave, Compound, Morpho)
- Vault Deposits: Fund yield aggregators and vaults
- Perp Exchange Funding: Deposit into perpetual exchanges
- Liquidity Provision: Add liquidity to AMMs and pools
- Staking: Fund staking contracts
See Also