Here is a comprehensive guide, broken down by the key architectural decisions and implementation steps.
Core Concept

The fundamental idea is to intercept a portion of the fee a user pays for a cross-chain swap (via a bridging aggregator like Socket, Li.Fi, etc.) and divert it to a designated treasury address instead of letting the aggregator's protocol keep 100% of it.
There are two primary architectural patterns to achieve this:
Direct Integration (Using the Aggregator's Built-in Fee Mechanism)
Meta-Transaction / Relay-Based Model (Implementing Your Own Fee Take)
1. Direct Integration (Using Aggregator's Fee Mechanism)
Most major bridging aggregators have a built-in concept of "affiliate fees" or "integrator fees." This is the simplest and most efficient way to achieve your goal. You act as an "integrator," and the aggregator's contract is programmed to send a portion of the fee to your specified address.
How it Works:
Your dApp/frontend integrates with the aggregator's API/SDK.
When requesting a quote for a bridge/swap, you include your integrator ID and treasury address.
The aggregator's API returns a quote that includes your fee.
When the user executes the transaction, the aggregator's smart contract automatically splits the fee, sending your share to your treasury.
Implementation Steps (Generic):
Step 1: Register with the Aggregator
Go to the aggregator's developer portal (e.g., Socket Dashboard, Li.Fi Developer Portal).
Create an account and register your project to get an Integrator ID (or a similar identifier).
Step 2: Integrate the SDK/API in Your Frontend
Use the aggregator's SDK (e.g.,
@socket.tech/socket-sdk,@lifi/sdk) in your application.When generating a transaction, pass your
integratorIdandfeeTreasuryaddress in the quote request parameters.
Example using a hypothetical Socket-like SDK:
import { Socket } from '@socket.tech/socket-sdk';const socket = new Socket({ apiKey: 'YOUR_API_KEY' });// Request a quote for a cross-chain swapconst
quote = await socket.getQuote({
fromChainId: 1, // Ethereum
toChainId: 137, // Polygon
fromToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native ETH
toToken: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619', // WETH on Polygon
fromAmount: '1000000000000000000', // 1 ETH
userAddress: '0xUserAddress...',
// --- Key Parameters for Fees ---
integratorId: 'your_project_name', // Your registered Integrator ID
feeTreasury: '0xYourTreasuryAddress...', // The address to receive fees
// The fee is typically a percentage of the fromAmount, configurable in the dashboard.});// The returned quote will have the final 'txn' object which
includes the computed fee.const transaction = quote.txn;// Send this transaction to the user's wallet for signing.Step 3: The Smart Contract Handles the Rest
The user signs and submits the transaction. The
toaddress of this transaction is the aggregator's verified contract (e.g.,SocketGateway).Inside its
executefunction, the aggregator's contract logic calculates the total fee, deducts your share, and sends it to yourfeeTreasuryaddress on the source chain as part of the same atomic transaction.
Pros & Cons of Direct Integration:
Pros:
Simple: No need to deploy or maintain your own smart contracts.
Secure: Leverages the aggregator's audited and battle-tested fee logic.
Automatic: Fee routing happens atomically with the user's bridge transaction.
Cons:
Less Flexible: You are bound by the aggregator's fee model (e.g., max fee percentage).
Vendor Lock-in: You must repeat this process for each aggregator you use.
2. Meta-Transaction / Relay-Based Model
If you need more control, want to use multiple aggregators under a single fee model, or if the aggregator doesn't have a built-in affiliate system, you can build this yourself.
How it Works:
Your dApp acts as a "relayer." You get a quote from any bridging aggregator.
You wrap this original transaction data into your own "Fee Router" smart contract.
The user signs a meta-transaction, or more simply, approves your contract to spend their tokens.
Your contract takes a fee in the source token and then calls the aggregator's contract with the remaining amount.
Implementation Steps:
Step 1: Deploy a "Fee Router" Smart Contract
This contract will hold the logic for deducting fees and making the external call to the bridging aggregator.
// SPDX-License-Identifier: MITpragma solidity ^0.8.19;import "@openzeppelin/contracts/token/ERC20/IERC20.sol";import "
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";import "@openzeppelin/contracts/access/Ownable.sol";contract BridgingFeeRouter is Ownable {
using SafeERC20 for IERC20;
address public immutable treasury;
uint256 public feeBasisPoints; // e.g., 10 = 0.1%, 50 = 0.5%
event FeeCollected(address indexed token, uint256 amount);
constructor(address _treasury, uint256 _feeBasisPoints) {
treasury = _treasury;
feeBasisPoints = _feeBasisPoints;
}
/**
* @dev The main function to route a bridge via an aggregator while taking a fee.
* @param target The address of the aggregator's contract (e.g., SocketGateway).
* @param approvalToken The token the user is spending (address(0) for native gas token).
* @param approvalAmount The total amount the user wants to bridge.
* @param aggregatorCallData The encoded function call for the aggregator's contract.
*/
function bridgeWithFee(
address target,
address approvalToken,
uint256 approvalAmount,
bytes calldata aggregatorCallData ) external payable {
uint256 fee = (approvalAmount * feeBasisPoints) / 10000;
uint256 amountAfterFee = approvalAmount - fee;
if (approvalToken == address(0)) {
// Native ETH/MTIC case
require(msg.value == approvalAmount, "Incorrect value sent");
// Take fee for treasury
(bool success, ) = treasury.call{value: fee}("");
require(success, "Fee transfer failed");
// Call the aggregator with the remaining value
(success, ) = target.call{value: amountAfterFee}(aggregatorCallData);
require(success, "Aggregator call failed");
} else {
// ERC20 token case
// Transfer tokens from user to this contract
IERC20(approvalToken).safeTransferFrom(msg.sender, address(this), approvalAmount);
// Take fee for treasury
IERC20(approvalToken).safeTransfer(treasury, fee);
// Approve the aggregator to spend the tokens
IERC20(approvalToken).safeApprove(target, amountAfterFee);
// Call the aggregator's function
(bool success, ) = target.call(aggregatorCallData);
require(success, "Aggregator call failed");
}
emit FeeCollected(approvalToken, fee);
}
// Admin function to update fee, if necessary
function setFeeBasisPoints(uint256 _newFeeBasisPoints) external onlyOwner {
feeBasisPoints = _newFeeBasisPoints;
}}Step 2: Integrate Your Contract into the Flow
Get a quote from an aggregator (Socket, Li.Fi, etc.) as you normally would.
Instead of having the user send the transaction directly to the aggregator, you encode a call to your
BridgingFeeRouter.bridgeWithFeefunction.The
targetis the aggregator's contract address, and theaggregatorCallDatais thedatafrom the original quote.
Step 3: User Interaction
The user interacts with your dApp.
Your dApp creates the meta-transaction calling your
FeeRouter.The user signs this transaction, which transfers the tokens to your contract, which then takes the fee and executes the bridge.
Pros & Cons of the Meta-Transaction Model:
Pros:
Maximum Control: You set the fee structure and logic.
Aggregator Agnostic: Works with any aggregator or even direct bridges.
Unified Treasury: All fees from all sources go through one contract.
Cons:
Complex: Requires developing, deploying, and maintaining a secure smart contract.
Security Risk: A bug in your contract could lead to loss of user funds. AUDITING IS MANDATORY.
Worse UX: Requires an extra
approvestep for ERC20 tokens and is generally more complex for the user.
Summary & Recommendation
| Feature | Direct Integration (Affiliate Fees) | Meta-Transaction Model |
|---|---|---|
| Development Effort | Low (SDK Integration) | High (Smart Contract Dev) |
| Security | High (Uses audited code) | Your Responsibility (Needs audit) |
| Flexibility | Low (Set by aggregator) | High (You have full control) |
| UX | Excellent (Single transaction) | Good (May require extra approval) |
Recommendation:
Start with the Direct Integration method. It is by far the safest, fastest, and most reliable way to start collecting fees. Register with the major aggregators you use and integrate their affiliate fee parameters.
Only consider building your own Meta-Transaction Model if you have a specific business need that the aggregators' built-in systems cannot fulfill and you have the significant expertise and resources required to do it securely.
