Documentation Index
Fetch the complete documentation index at: https://bridge.near.tools/llms.txt
Use this file to discover all available pages before exploring further.
This is the most common cause of transfer failures. Read this before building any production integration.
The Problem
Different chains use different decimal precisions for the same token:
| Token | Ethereum | NEAR | Solana |
|---|
| USDC | 6 decimals | 24 decimals | 6 decimals |
| WETH | 18 decimals | 24 decimals | 8 decimals |
When bridging tokens, amounts must be converted between these precisions. Small amounts can round to zero during conversion — and a zero-amount transfer fails.
Example: The Dust Problem
Suppose you try to bridge 0.0000001 USDC from NEAR (24 decimals) to Ethereum (6 decimals):
// On NEAR: 0.0000001 USDC = 100000000000000000 (24 decimals)
// Converted to Ethereum: rounds down to 0 (6 decimals)
// Result: transfer fails
This is called “dust” — amounts so small they disappear during conversion.
How the SDK Protects You
validateTransfer() catches this automatically:
const validated = await bridge.validateTransfer({
token: "near:a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.factory.bridge.near", // USDC
amount: 100000000000000000n, // Too small!
sender: "near:alice.near",
recipient: "eth:0x...",
fee: 0n,
nativeFee: 0n,
})
// Throws ValidationError with code "AMOUNT_TOO_SMALL"
The validation checks that your amount (minus fees) survives the round-trip conversion.
Finding Minimum Amounts
Use these helpers to determine safe transfer amounts:
import { getMinimumTransferableAmount, validateTransferAmount } from "@omni-bridge/core"
// Get the minimum amount that survives conversion
const min = getMinimumTransferableAmount(6, 24) // 1n
// Validate a specific amount
try {
validateTransferAmount(
amount, // Amount in source decimals
fee, // Fee in source decimals
6, // Source decimals
24 // Destination decimals
)
} catch {
console.log("Amount too small")
}
Building UI Validation
Show users the minimum before they submit:
import { getMinimumTransferableAmount } from "@omni-bridge/core"
import { formatUnits } from "viem"
const sourceDecimals = 6 // USDC on Ethereum
const destDecimals = 24 // USDC on NEAR
const minAmount = getMinimumTransferableAmount(sourceDecimals, destDecimals)
const minDisplay = formatUnits(minAmount, sourceDecimals)
console.log(`Minimum transfer: ${minDisplay} USDC`)
Handling Errors
import { ValidationError, getMinimumTransferableAmount } from "@omni-bridge/core"
import { formatUnits } from "viem"
try {
await bridge.validateTransfer(params)
} catch (error) {
if (error instanceof ValidationError && error.code === "AMOUNT_TOO_SMALL") {
const min = getMinimumTransferableAmount(sourceDecimals, destDecimals)
showError(`Minimum amount is ${formatUnits(min, sourceDecimals)}`)
}
}
The ValidatedTransfer Contains Normalized Amounts
After validation succeeds, the result includes the normalized amount:
const validated = await bridge.validateTransfer(params)
console.log(validated.normalizedAmount) // Amount safe for cross-chain
console.log(validated.normalizedFee) // Fee safe for cross-chain
Builders use these normalized values internally.
Fees Matter Too
Remember: amount - fee must survive normalization, not just amount. If you’re paying fees from the transfer:
// This might fail even if amount is large enough
await bridge.validateTransfer({
amount: 1_000_000n, // 1 USDC
fee: 999_999n, // Almost all of it
// Net amount: 1 unit — might round to zero!
})
Key Takeaways
- Always use
validateTransfer() — Never skip validation
- Check minimums in your UI — Show users the minimum before they submit
- Handle
AMOUNT_TOO_SMALL errors — Give users a helpful message
- Remember fees reduce the amount — The net amount must survive, not just the gross