Skip to main content

Developer Guide

This guide demonstrates how to integrate only swaps libraries into your apps, enabling secure, conditional cross-chain settlement powered by the dcipher network. It shows how to get started and integrate settlement logic inside smart contract functions and client-side applications.

The dcipher network provides two implementation options for integrating its cross-chain settlement primitives into your decentralized applications:

  1. onlyswaps-js - JavaScript/TypeScript library designed to simplify client-side interaction with the only swaps protocol. It allows frontend and backend applications to prepare, initiate, and manage cross-chain token swaps.
    • πŸ”„ Cross-chain token swaps across EVM-compatible networks
    • πŸ’° Dynamic fee estimation via the OnlySwaps fee API
    • 🌐 Multi-chain support - BASE, Avalanche (mainnet and testnets)
  2. onlyswaps-solidity - Solidity library for integrating cross-chain token swaps logic directly into your smart contracts with upgradeability and BLS signature verification.

Choose the Implementation that Best Fits Your Use Case

  • Choose the JavaScript Library if you need to:

    • Integrate with your client applications to allow users to initiate token swaps through a UI.
    • Integrate conditional swap features into your client-side dApp interface.
  • Choose the Solidity Library if you need to:

    • Implement the full cross-chain token swap logic directly in your smart contract.
    • Build on-chain protocols that require cross-chain transfers in the smart contract.

Build with onlyswaps-js​

This guide will help you integrate cross-chain token swaps into your dApp using the onlyswaps-js and dcipher network.

In this guide, we will use Base Sepolia and Avalanche Fuji testnets as examples to swap RUSD tokens. RUSD is the testing token we created for development purposes, and you can request test RUSD from the RUSD faucet.

Once you move your appliation to mainnet, only swaps also supports swapping USDT between Base, Avalanche, and more to come. You can find the support token information here. All you need to do is use the USDT_ADDRESS for different networks defined in the onlyswaps-js constants file.

Installation​

Install the package using npm:

npm install onlyswaps-js

Or using yarn:

yarn add onlyswaps-js

Quickstart​

1.Setting Up Clients​

First, set up your viem clients and only swaps router.

import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia, avalancheFuji } from 'viem/chains';
import { RouterClient, ViemChainBackend, BASE_SEPOLIA } from 'onlyswaps-js';

// Initialize your wallet account
const account = privateKeyToAccount(process.env.PRIVATE_KEY!);

// Create public client for reading blockchain state
const publicClient = createPublicClient({
chain: baseSepolia,
transport: http(process.env.RPC_URL) // Optional: use your own RPC
});

// Create wallet client for sending transactions
const walletClient = createWalletClient({
chain: baseSepolia,
transport: http(process.env.RPC_URL),
account
});

// Create the OnlySwaps backend
const backend = new ViemChainBackend(
account.address,
publicClient,
walletClient
);

// Create the router client
const router = new RouterClient(
{ routerAddress: BASE_SEPOLIA.ROUTER_ADDRESS},
backend
);

only swaps provides an API to fetch recommended fees based on current network conditions:

import { 
fetchRecommendedFees,
BASE_SEPOLIA,
AVAX_FUJI
} from 'onlyswaps-js';
import { baseSepolia, avalancheFuji } from 'viem/chains';

async function getOptimalFees() {
const feeRequest = {
sourceToken: BASE_SEPOLIA.RUSD_ADDRESS,
destinationToken: AVAX_FUJI.RUSD_ADDRESS,
sourceChainId: BigInt(baseSepolia.id),
destinationChainId: BigInt(avalancheFuji.id),
amount: 1000000000000000000n // 1 RUSD
};

const fees = await fetchRecommendedFees(feeRequest);

console.log('Recommended fees:', {
solverFee: fees.fees.solver,
networkFee: fees.fees.network,
totalFee: fees.fees.total,
amountToTransfer: fees.transferAmount,
amountToApprove: fees.approvalAmount
});

return fees;
}

The fee response includes:

  • fees.solver: Fee paid to the solver who fulfills your swap
  • fees.network: Fee charged by the dcipher network
  • fees.total: Total fee (solver + network)
  • transferAmount: Amount to send to achieve your desired output
  • approvalAmount: Amount to approve for the ERC20 contract

3.Executing a Cross-Chain Swap​

To execute a cross-chain swap, you need to provide:

  • Source token address: RUSD in Base Sepolia
  • Destination token address: RUSD in Aavalance Fuji testnet
  • Amount to swap
  • Solver fee: You can get from last step
  • Destination chain ID: Avalance Fuji chain Id
  • Recipient address
import { AVAX_FUJI, BASE_SEPOLIA } from 'onlyswaps-js';
import { avalancheFuji } from 'viem/chains';

async function executeSwap() {
try {
const swapRequest = {
recipient: '0x...',
srcToken: BASE_SEPOLIA.RUSD_ADDRESS,
destToken: AVAX_FUJI.RUSD_ADDRESS,
amount: 1000000000000000000n, // 1 RUSD (18 decimals)
fee: 10000000000000000n, // 0.01 RUSD solver fee
destChainId: BigInt(avalancheFuji.id) // Avalanche Fuji
};

// The swap method handles:
// 1. Token approval
// 2. Swap execution
// 3. Returns request ID for tracking
const { requestId } = await router.swap(swapRequest);

console.log('Swap request submitted:', requestId);
return requestId;
} catch (error) {
console.error('Swap failed:', error);
throw error;
}
}

4.Tracking Swap Status​

After submitting a swap, you can track its status:

Fetch Request Parameters

async function checkSwapStatus(requestId: string) {
const params = await router.fetchRequestParams(requestId);

console.log('Swap parameters:', {
sender: params.sender,
recipient: params.recipient,
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
amountIn: params.amountIn,
amountOut: params.amountOut,
srcChainId: params.srcChainId,
dstChainId: params.dstChainId,
verificationFee: params.verificationFee,
solverFee: params.solverFee,
executed: params.executed, // true when verified by dcipher
requestedAt: params.requestedAt
});

return params;
}

Fetch Fulfillment Receipt

async function checkFulfillment(requestId: string) {
const receipt = await router.fetchFulfilmentReceipt(requestId);

console.log('Fulfillment status:', {
requestId: receipt.requestId,
fulfilled: receipt.fulfilled, // true when solver completes transfer
solver: receipt.solver,
recipient: receipt.recipient,
amountOut: receipt.amountOut,
fulfilledAt: receipt.fulfilledAt
});

return receipt;
}

Key Difference:

  • executed (from fetchRequestParams): true when the swap is verified by the dcipher network
  • fulfilled (from fetchFulfilmentReceipt): true when the solver completes the transfer (may not be verified yet)

Build with onlyswaps-solidity​

onlyswaps-solidity enables your smart contracts to seamlessly swap tokens across different blockchains. Simply integrate the Router contract into your Solidity code, and your users can swap tokens from Ethereum to Polygon, Arbitrum to Base, or any supported chain pairβ€”all without centralized bridges or wrapped tokens.

The Router contract is the central entry point for swap requests and contract upgrades. It manages cross-chain token swap requests, swap execution, and upgrade scheduling.

Prerequisites​

Smart Contract Requirements​

To integrate only swaps into your smart contract, you need:

  1. Router Interface: Import the IRouter interface
  2. Token Approval: Approve the Router to spend tokens
  3. Supported ERC20 tokens: Tokens must be supported by only swaps

Deployment Information​

You'll need to know:

  • the router contract address on your source chain
  • the destination chain ID
  • the token addresses on both source and destination chains
  • the current fee structure (verification fee BPS)

Quickstart​

1. Import the Router Interface​

First, we need to install the onlyswaps-solidity library.

forge install randa-mu/onlyswaps-solidity 

Once the library is intalled, we can import IRouter to access the interfaces for token swaps.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IRouter} from "onlyswaps-solidity/src/interfaces/IRouter.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

2. Create Your Contract​

contract MySwapContract {
IRouter public immutable router;

constructor(address _router) {
router = IRouter(_router);
}

// Your swap functions here
}

3: Understand the Fee Structure​

The Router charges two types of fees:

  1. Solver Fee: A user-defined fee paid to the solver for providing liquidity

    • Must be greater than 0
    • Paid in addition to the verification fee
  2. Verification Fee: A percentage-based fee (in basis points) taken from the swap amount

    • Configurable by the protocol maintainers for now (max 50%)
    • Used for protocol operations

Example Calculation:

uint256 swapAmount = 100 ether; // Amount to swap
uint256 solverFee = 1 ether; // Fee for solver

// Get verification fee (e.g., 5% = 500 BPS)
(uint256 verificationFee, uint256 amountOut) = router.getVerificationFeeAmount(swapAmount);
// verificationFee = 5 ether
// amountOut = 95 ether (amount recipient receives)

// Total tokens needed from user
uint256 totalRequired = swapAmount + solverFee; // 101 ether

4. Basic cross-chain token swap​

    
/**
* @notice Initiates a cross-chain token swap
*/
function swapTokens(
address tokenIn,
address tokenOut,
uint256 amount,
uint256 solverFee,
uint256 dstChainId,
address recipient
) external returns (bytes32 requestId) {
require(amount > 0, "Amount must be greater than 0");
require(solverFee > 0, "Solver fee must be greater than 0");
require(recipient != address(0), "Invalid recipient");

// Initiate cross-chain swap
requestId = router.requestCrossChainSwap(
tokenIn, // RUSD in source chain
tokenOut, // RUSD in destination chain
amount,
solverFee,
dstChainId,
recipient
);

emit SwapInitiated(requestId, msg.sender, amount);

// other logic here
}

This guide covers the essential aspects of integrating with the only swaps Router contract. Key takeaways:

  1. Always validate inputs and router configuration before initiating swaps
  2. Handle fees correctly - both verification and solver fees
  3. Track swap requests for your users
  4. Implement proper error handling and security measures
  5. Monitor swap status and provide cancellation mechanisms