Integration surface
This repository is a Next.js application, not a published SplitLayer SDK or a separately hosted public API. Its internal endpoints support the included interface. Their responses follow the configured upstream provider and may change as the app evolves.
For an independent integration, start from the official LI.FI quote and transfer-status APIs. Keep provider credentials on your server. The browser wallet is responsible for all signatures.
The application endpoints
Quote amount is a human decimal string with at most six places; the server converts it to USDC base units. Slippage is an integer from 10 to 100 basis points. Source and destination must be different enabled networks. The recipient is the connected address.
The server binds reviewed quote terms and transaction data with an HMAC signature. Allowed LI.FI transaction targets and transfer calldata are validated before execution. This protects the application boundary; it is not an audit or a guarantee of bridge solvency.
const response = await fetch('/api/quote', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fromChainId: 8453,
toChainId: 42161,
amount: '10.00',
address: connectedWalletAddress,
slippageBps: 50,
}),
});
if (!response.ok) throw new Error('Quote unavailable');
const reviewedQuote = await response.json();| Endpoint | Input | Purpose |
|---|---|---|
| POST /api/quote | fromChainId, toChainId, amount, address, slippageBps | Validated native-USDC quote with a signed 60-second expiry |
| POST /api/quote/validate | verificationToken, optional includeFunds | Verify signature and expiry; optionally read balance, allowance, and native gas balance |
| GET /api/receipt | hash, chainId | Source-chain receipt status or pending |
| GET /api/balances | address | Registered-chain USDC balances; null when a network read fails |
| GET /api/status | hash, fromChainId, toChainId, optional tool | Normalized route status, substatus, and receiving details |
| GET /api/assets | address, tokenAddress, chainId=4663 | Read-only imported ERC-20 metadata and wallet balance |
| GET /api/rwa | None | Official Robinhood Chain asset metadata and available reference prices |
Requesting an upstream quote
This example shows the upstream API and assumes a valid connected EVM address. Production code should use allowlisted token addresses rather than symbols. It must validate the chains, assets, recipient, amount, slippage, and transaction target returned by the provider.
const params = new URLSearchParams({
fromChain: '8453',
toChain: '42161',
fromToken: 'USDC',
toToken: 'USDC',
fromAmount: '10000000', // 10 USDC, 6 decimals
fromAddress: connectedWalletAddress,
toAddress: connectedWalletAddress,
slippage: '0.005',
integrator: 'splitlayer',
});
const response = await fetch(
`https://li.quest/v1/quote?${params}`,
{ cache: 'no-store' },
);
if (!response.ok) throw new Error('Quote unavailable');
const quote = await response.json();
// Validate and show the quote before requesting a signature.Keep amounts exact
Read decimals from the verified token registry. Parse human input into integer base units, using string-based decimal parsing and bigint. Do not multiply a JavaScript floating-point number by 10 raised to the token decimals for transaction amounts.
Separate display formatting from validation. Reject negative values, exponent notation, too many decimal places, zero-sized transfers, and amounts greater than the actual source balance. A USD portfolio estimate must never be treated as a token spending allowance.
Execution boundary
- Invalidate the quote whenever the account, chains, token, amount, or slippage changes.
- Require a reviewed quote and the expected connected chain before execution.
- Validate that the quote recipient and source address equal the intended wallet addresses.
- Read the current ERC-20 allowance and request only the allowance the route requires.
- Wait for an approval receipt before submitting the bridge transaction.
- Record the submitted transaction hash immediately; an RPC timeout is not proof that it was never sent.
- Derive transfer records from wallet-submitted transaction hashes and provider status; never infer successful settlement from a local UI transition.
Track status without guessing
The internal status endpoint proxies the configured provider. Apply bounded polling with backoff, retain the transaction hash, and inspect the receiving transaction. A transport error should remain unknown or pending until there is evidence of a terminal result.
const params = new URLSearchParams({
hash: sourceTransactionHash,
fromChainId: '8453',
toChainId: '42161',
});
const response = await fetch(`/api/status?${params}`);
const result = await response.json();
// Interpret both fields; DONE alone is insufficient.
const settled = result.status === 'DONE'
&& result.substatus === 'COMPLETED';
const needsReview = ['PARTIAL', 'REFUNDED'].includes(
result.substatus,
);Running and deploying
See the repository README for environment variables, validation commands, and Railway deployment details. The application currently has no persistent server database. If shared persistent data is introduced, use PostgreSQL and run database migrations at application start rather than during Railway's build phase.
npm install
npm run dev
# Production build
npm run build
npm start