Quick Start
Key differences
Here’s what’s different when integrating Tron Bungee API compared to standard EVM chains: Transaction Flow- User sends funds to a Deposit contract with the quote ID
- Bungee indexes the transaction and delivers the funds on the destination chain
- Both
userAddressandreceiverAddressrequired for quotes - The only asset supported from/to Tron is Tron USDT
- There is no Fee collection at the moment
Integration Steps
The “Auto routing onchain” guide from Bungee Docs outlines how to integrate the deposit flow as it is a quite similar process.- Select Chains: Users choose the source and destination chains, which determine the tokens available for bridging.
- Fetch Routes: After selecting the tokens, retrieve the deposit route if available using the
/quoteendpoint. - Submitting a deposit via the Deposit contract: Obtain the transaction data from the
/quoteendpoint. Use this data to execute the deposit transaction on the source chain. - Track Transaction Status: Monitor the transaction’s progress by polling the
/statusendpoint until the bridging process is complete.
For Tron quotes, please ensure both
userAddress and receiverAddress are defined.Also, note that this is a separate route from autoRoute since it is under depositRoute.Examples
Queries
Quote from Polygon USDC to Tron USDT
Quote from Polygon USDC to Tron USDT
Copy
https://public-backend.bungee.exchange/api/v1/bungee/quote?userAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&receiverAddress=TMe1CS54poswoTTrPAtqsKhry4RM7nvSF4&originChainId=137&destinationChainId=728126428&inputToken=0x3c499c542cef5e3811e1192ce70d8cc03d5c3359&outputToken=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&inputAmount=5000000
Quote from Tron USDT to Base USDC
Quote from Tron USDT to Base USDC
Copy
https://public-backend.bungee.exchange/api/v1/bungee/quote?userAddress=TMe1CS54poswoTTrPAtqsKhry4RM7nvSF4&receiverAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&originChainId=728126428&destinationChainId=8453&inputToken=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&outputToken=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&inputAmount=9681288
Scripts
Quote and swap from Tron USDT to Polygon USDC (tronweb)
Quote and swap from Tron USDT to Polygon USDC (tronweb)
Copy
import { privateKeyToAccount } from "viem/accounts";
import { TronWeb } from "tronweb";
// Check if PRIVATE_KEY is set, set in console, i.e.: export PRIVATE_KEY=<PRIVATE_KEY_HEX_64>
if (!process.env.PRIVATE_KEY) {
console.error("Error: PRIVATE_KEY environment variable is not set");
console.error(
"Example: PRIVATE_KEY=<PRIVATE_KEY_HEX_64>"
);
process.exit(1);
}
// Check if TRON_PRIVATE_KEY is set
if (!process.env.TRON_PRIVATE_KEY) {
console.error("Error: TRON_PRIVATE_KEY environment variable is not set");
console.error(
"Example: TRON_PRIVATE_KEY=<PRIVATE_KEY_HEX_64>"
);
process.exit(1);
}
// Create account from private key
const account = privateKeyToAccount(`${process.env.PRIVATE_KEY}`);
// Derive TRON address from TRON private key
const tronPrivateKey = process.env.TRON_PRIVATE_KEY.replace(/^0x/, "");
const tronWeb = new TronWeb({
fullHost: "https://api.trongrid.io",
privateKey: tronPrivateKey,
});
const tronAddress = tronWeb.address.fromPrivateKey(tronPrivateKey);
// API and token parameters
const BUNGEE_API_BASE_URL = "https://public-backend.bungee.exchange";
// USDT contract address on Tron
const USDT_CONTRACT = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
// Function to get USDT balance
async function getUSDTBalance() {
try {
const contract = await tronWeb.contract().at(USDT_CONTRACT);
const balance = await contract.balanceOf(tronAddress).call();
return balance.toString();
} catch (error) {
console.error("Failed to get USDT balance:", error);
throw error;
}
}
// Function to get a quote
async function getQuote(params) {
try {
const url = `${BUNGEE_API_BASE_URL}/api/v1/bungee/quote`;
const queryParams = new URLSearchParams(params);
const fullUrl = `${url}?${queryParams}`;
const response = await fetch(fullUrl);
console.log(fullUrl);
const data = await response.json();
const serverReqId = response.headers.get("server-req-id");
// Check for errors
if (!data.success) {
throw new Error(
`Quote error: ${data.statusCode}: ${data.message}. server-req-id: ${serverReqId}`
);
}
// Check if autoRoute exists
if (!data.result.depositRoute) {
throw new Error(`No depositRoute available. server-req-id: ${serverReqId}`);
}
const quoteId = data.result.depositRoute.quoteId;
console.log("- Quote ID:", quoteId);
// Extract data based on the response structure
const txData = data.result.depositRoute.txData;
return {
quoteId,
txData,
fullResponse: data,
};
} catch (error) {
console.error("Failed to get quote:", error);
throw error;
}
}
// Function to submit the transaction to the Deposit contract
async function submitNativeTransaction(txData) {
try {
console.log("- Submitting transaction to Deposit contract...");
console.log(" To:", txData.to);
console.log(" Value:", txData.value);
console.log(" Data:", txData.data);
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
tronWeb.address.fromHex(txData.to),
"", // Empty functionSelector when using 'input'
{
input: txData.data.replace(/^0x/, ""), // Full data including function selector + params + quoteId
callValue: parseInt(txData.value) || 0,
feeLimit: 100000000,
},
[], // Empty parameters since we're using 'input'
tronAddress
);
// Sign and send
const signed = await tronWeb.trx.sign(transaction.transaction);
const result = await tronWeb.trx.sendRawTransaction(signed);
if (!result.result) {
throw new Error(`Transaction failed: ${JSON.stringify(result)}`);
}
const hash = result.txid;
console.log("- Transaction sent:", hash);
// Wait for confirmation
let receipt;
while (!receipt) {
await new Promise((resolve) => setTimeout(resolve, 3000));
try {
const txInfo = await tronWeb.trx.getTransactionInfo(hash);
if (txInfo?.blockNumber) {
receipt = { blockNumber: txInfo.blockNumber, status: txInfo.receipt ? "success" : "failed", transactionHash: hash };
}
} catch { }
}
console.log("- Transaction confirmed in block:", receipt.blockNumber);
return { hash, receipt };
} catch (error) {
console.error("Failed to submit transaction:", error);
throw error;
}
}
// Function to check the status of a request
async function checkStatus(requestHash) {
try {
const response = await fetch(
`${BUNGEE_API_BASE_URL}/api/v1/bungee/status?requestHash=${requestHash}`
);
const data = await response.json();
if (!data.success) {
throw new Error(
`Status error: ${data.error?.message || "Unknown error"}`
);
}
return data.result[0];
} catch (error) {
console.error("Failed to check status:", error);
throw error;
}
}
// Main function to handle the flow
async function main() {
try {
console.log("Starting Bungee Tron to EVM Token Test (Deposit Route)...");
// Get USDT balance
console.log("\n1. Getting USDT balance...");
const usdtBalance = await getUSDTBalance();
console.log("- USDT Balance:", usdtBalance);
// Quote parameters for ERC20 token test
const quoteParamsERC20 = {
userAddress: tronAddress,
receiverAddress: account.address,
originChainId: 728126428, // Tron
destinationChainId: 137, // Polygon
inputToken: USDT_CONTRACT, // USDT on Tron
outputToken: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", // USDC on Polygon
inputAmount: usdtBalance, // Use actual USDT balance
};
// Get the quote and extract data
console.log("\n2. Getting quote...");
const quoteResponse = await getQuote(quoteParamsERC20);
//console.log(JSON.stringify(quoteResponse.fullResponse, null, 2));
if (quoteResponse.txData) {
// Submit the transaction
console.log("\n3. Submitting transaction...");
const { hash, receipt } = await submitNativeTransaction(quoteResponse.txData);
console.log(
"\n4. Transaction submitted:",
"\n- Hash:",
hash,
"\n- Status:",
receipt.status
);
// Wait for 5 seconds before checking status
console.log("\n5. Waiting for 5 seconds...");
let status;
do {
await new Promise((resolve) => setTimeout(resolve, 5000));
console.log("\n6. Checking status...");
try {
status = await checkStatus(quoteResponse.quoteId);
console.log("- Status details:", status.bungeeStatusCode);
} catch (error) {
console.error(
"Failed to check status:",
error?.message || "Unknown error"
);
}
} while (status?.bungeeStatusCode !== 3 && status?.bungeeStatusCode !== 4);
console.log(
"\n7. Transaction complete:",
"\n- Hash:",
status.destinationData?.txHash || "Transaction hash not available"
);
} else {
console.log("No transaction data available in the quote response");
}
} catch (error) {
console.error("Error in processing:", error?.shortMessage || error.message);
throw error;
}
}
// Execute the main function
main();
Quote and swap from Polygon USDC to Tron USDT (Viem)
Quote and swap from Polygon USDC to Tron USDT (Viem)
Copy
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http, createWalletClient } from "viem";
import { polygon } from "viem/chains";
import { TronWeb } from "tronweb";
// Check if PRIVATE_KEY is set, set in console, i.e.: export PRIVATE_KEY=<PRIVATE_KEY_HEX_64>
if (!process.env.PRIVATE_KEY) {
console.error("Error: PRIVATE_KEY environment variable is not set");
console.error(
"Example: PRIVATE_KEY=<PRIVATE_KEY_HEX_64>"
);
process.exit(1);
}
// Create account from private key
// Normalize private key to ensure it has 0x prefix (required by viem)
const rawPrivateKey = process.env.PRIVATE_KEY;
const normalizedPrivateKey = rawPrivateKey.startsWith('0x')
? rawPrivateKey
: `0x${rawPrivateKey}`;
const account = privateKeyToAccount(normalizedPrivateKey);
// Create Viem clients
const publicClient = createPublicClient({
chain: polygon,
transport: http(),
});
const walletClient = createWalletClient({
account,
chain: polygon,
transport: http(),
});
// Check if TRON_PRIVATE_KEY is set
if (!process.env.TRON_PRIVATE_KEY) {
console.error("Error: TRON_PRIVATE_KEY environment variable is not set");
console.error(
"Example: TRON_PRIVATE_KEY=<PRIVATE_KEY_HEX_64>"
);
process.exit(1);
}
// Derive TRON address from TRON private key
const tronPrivateKey = process.env.TRON_PRIVATE_KEY.replace(/^0x/, "");
const tronWeb = new TronWeb({
fullHost: "https://api.trongrid.io",
privateKey: tronPrivateKey,
});
const tronAddress = tronWeb.address.fromPrivateKey(tronPrivateKey);
// API and token parameters
const BUNGEE_API_BASE_URL = "https://public-backend.bungee.exchange";
// Quote parameters for ERC20 token test (USDC from Optimism to Arbitrum)
const quoteParamsERC20 = {
userAddress: account.address,
receiverAddress: tronAddress,
originChainId: 137, // Polygon
destinationChainId: 728126428, // Tron
inputToken: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", // USDC on Polygon
outputToken: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // USDT
inputAmount: "10000000", // 10 USDC (6 decimals)
};
// Function to get a quote
async function getQuote(params) {
try {
const url = `${BUNGEE_API_BASE_URL}/api/v1/bungee/quote`;
const queryParams = new URLSearchParams(params);
const fullUrl = `${url}?${queryParams}`;
const response = await fetch(fullUrl);
console.log(fullUrl);
const data = await response.json();
const serverReqId = response.headers.get("server-req-id");
// Check for errors
if (!data.success) {
throw new Error(
`Quote error: ${data.statusCode}: ${data.message}. server-req-id: ${serverReqId}`
);
}
// Check if autoRoute exists
if (!data.result.depositRoute) {
throw new Error(`No depositRoute available. server-req-id: ${serverReqId}`);
}
const quoteId = data.result.depositRoute.quoteId;
console.log("- Quote ID:", quoteId);
// Extract data based on the response structure
const txData = data.result.depositRoute.txData;
return {
quoteId,
txData,
fullResponse: data,
};
} catch (error) {
console.error("Failed to get quote:", error);
throw error;
}
}
// Function to submit the transaction to the inbox contract
async function submitNativeTransaction(txData) {
try {
console.log("- Submitting transaction to inbox contract...");
console.log(" To:", txData.to);
console.log(" Value:", txData.value);
console.log(" Data:", txData.data);
// Send the transaction
const hash = await walletClient.sendTransaction({
to: txData.to,
value: BigInt(txData.value),
data: txData.data,
});
console.log("- Transaction sent:", hash);
// Wait for transaction to be mined
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log("- Transaction confirmed in block:", receipt.blockNumber);
return {
hash,
receipt,
};
} catch (error) {
console.error("Failed to submit transaction:", error);
throw error;
}
}
// Function to check the status of a request
async function checkStatus(requestHash) {
try {
const response = await fetch(
`${BUNGEE_API_BASE_URL}/api/v1/bungee/status?requestHash=${requestHash}`
);
const data = await response.json();
if (!data.success) {
throw new Error(
`Status error: ${data.error?.message || "Unknown error"}`
);
}
return data.result[0];
} catch (error) {
console.error("Failed to check status:", error);
throw error;
}
}
// Main function to handle the flow
async function main() {
try {
console.log("Starting Bungee EVM to Tron Test (Deposit Route)...");
// Get the quote and extract data
console.log("\n1. Getting quote...");
const quoteResponse = await getQuote(quoteParamsERC20);
//console.log(JSON.stringify(quoteResponse.fullResponse, null, 2));
if (quoteResponse.txData) {
// Submit the transaction
console.log("\n2. Submitting transaction...");
const { hash, receipt } = await submitNativeTransaction(quoteResponse.txData);
console.log(
"\n3. Transaction submitted:",
"\n- Hash:",
hash,
"\n- Status:",
receipt.status
);
// Wait for 5 seconds before checking status
console.log("\n4. Waiting for 5 seconds...");
let status;
do {
await new Promise((resolve) => setTimeout(resolve, 5000));
console.log("\n5. Checking status...");
try {
status = await checkStatus(quoteResponse.quoteId);
console.log("- Status details:", status.bungeeStatusCode);
} catch (error) {
console.error(
"Failed to check status:",
error?.message || "Unknown error"
);
}
} while (status?.bungeeStatusCode !== 3 && status?.bungeeStatusCode !== 4);
console.log(
"\n6. Transaction complete:",
"\n- Hash:",
status.destinationData?.txHash || "Transaction hash not available"
);
} else {
console.log("No transaction data available in the quote response");
}
} catch (error) {
console.error("Error in processing:", error?.shortMessage || error.message);
throw error;
}
}
// Execute the main function
main();