Bridging Assets via Calldata Execution
After getting a quote, you'll next have to send a transaction to Swing's Cross-Chain API.
This step involves using our wallet connector (xDefi) to send a transaction to the Bitcoin network or, to invoke a smart contract function on any EVM network which is necessary for approvals and swap transactions.
The steps for sending a transaction are as followed:
- First, we will make a request to
https://swap.prod.swing.xyz/v0/transfer/send - Using the
txData/callDatareturned from the/sendrequest, sign the transaction with using a user's wallet
Making a Request
Navigating to our src/services/requests.ts, you'll find our request implemenation for the /send endpoint:
export const sendTransactionRequest = async (
payload: SendTransactionPayload,
): Promise<SendTransactionApiResponse> => {
try {
const response = await axios.post<SendTransactionApiResponse>(
`${baseUrl}/transfer/send`,
{ ...payload, projectId },
{
headers: {
'Content-Type': 'application/json',
},
},
);
return response.data;
} catch (error) {
console.error('Error sending transaction:', error);
throw error;
}
};The SendTransactionPayload body payload contains the source chain, destination chain, tokenAmount, and the desired route.
URL: https://swap.prod.swing.xyz/v0/transfer/send
Parameters:
| Key | Example | Description |
|---|---|---|
fromChain | bitcoin | The blockchain where the transaction originates. |
fromTokenAddress | btc | Source Token Address |
fromUserAddress | bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x | Sender's wallet address |
tokenSymbol | BTC | Source Token slug |
toTokenAddress | 0x0000000000000000000000000000000000000000 | Destination Token Address. |
toChain | ethereum | Destination Source slug |
toTokenAmount | 4376081 | Amount of the destination token being received. |
toTokenSymbol | ETH | Destination Chain slug |
toUserAddress | 0x018c15DA1239B84b08283799B89045CD476BBbBb | Receiver's wallet address |
tokenAmount | 1000000000000000000 | Amount of the source token being sent (in wei for ETH). |
type | swap | Type of transaction. |
projectId | replug | Your project's ID |
route | See Getting BTC Routes page | Selected Route from /quote endpoint |
Since executing a swap/bridge will change the state of a user's wallet, the next step of this transaction must be done via a Smart Contract Transaction on Ethereum or a send transaction on Bitcoin and not via Swing's Cross-Chain API. The response received from the sendTransactionRequest endpoint provides us with the necessary txData/callData needed to be passed on to a user's wallet to sign the transaction.
The txData from the sendTransactionRequest will look something like this:
{
....
"tx": {
"from": "bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x",
"to": "0x",
"value": "0x",
"data": "70736274ff0100d80200000002b05b268c9f39123623c19077fd8be9ea3eb4be2cc9bf2b9679a03eaef853e4de0200000000ffffffff5f1d0367c097ea1af3dfae2eeba4c66887b4b4fea3a4853e7fdb73d3dab59d280000000000ffffffff0330750000000000001600145c8e21c7446ac47b8537eeee77116d1bb33d82350000000000000000356a333d3a653a3078653165303939326265393930326539323436306163306666363235646363316334383566636636623a3a743a30f617000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed430000000000001011f3910000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed4300001011f499d000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed43000000000",
"meta": {
"from": "bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x",
"recipient": "bc1qtj8zr36ydtz8hpfhamh8wytdrwenmq34e0l6zc",
"amount": {
"amount": "30000",
"decimals": 8
},
"memo": "=:e:0xe1e0992be9902e92460ac0ff625dcc1c485fcf6b::t:0",
"slippage": 1146
}
}
....
}Connecting to xDefi wallet
To connect to xDefi, we'll be using the xdefiWallet() and useConnect() hooks from Thirdweb's SDK. To interact with any EVM chain, we need a wallet signer which we also included in Thirdweb's SDK:
// src/components/Swaps.tsx
import { xdefiWallet, useConnect, useSigner } from '@thirdweb-dev/react';
const xDefiConfig = xdefiWallet(); //Wallet provider config.
const connect = useConnect(); //For connecting to a user's supported wallet.
const signer = useSigner(); //For interacting with EVM chainsNext, in our connect wallet function, we will connect to our wallet using the xDefiConfig:
// src/components/Swaps.tsx
async function connectWallet(chainId?: number) {
try {
// Connect to xDefi
await connect(xDefiConfig, { chainId });
} catch (error) {
console.error('Connect Wallet Error:', error);
}
}Bridging Assets from BTC to EVM
To perform a bridge from a Non-EVM chain like Bitcoin, you'll need to sign the transaction using a wallet provider that supports Bitcoin.
To brige our Bitcoin assets to any EVM chain, we have to set our source chain to bitcoin and our destination chain to any EVM chain like ethereum
Source Chain Config
const transferParams: TransferParams = {
...
fromChain: 'bitcoin',
fromUserAddress: 'bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x',
fromTokenAddress: 'btc',
tokenSymbol: 'BTC',
fromChainDecimal: 8,
...
};Destination Chain Config
const transferParams: TransferParams = {
...
toTokenAddress: '0x0000000000000000000000000000000000000000',
toTokenSymbol: 'ETH',
toChain: 'ethereum',
toUserAddress: '0xE1e0992Be9902E92460AC0Ff625Dcc1c485FCF6b',
toChainDecimal: 8,
...
};putting our transfer config together and making a sendTransactionRequest:
const transferParams: TransferParams = {
tokenAmount: '1000000',
fromChain: 'bitcoin',
fromUserAddress: 'bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x',
fromTokenAddress: 'btc',
fromChainDecimal: 8,
tokenSymbol: 'BTC',
toTokenAddress: '0x0000000000000000000000000000000000000000',
toTokenSymbol: 'ETH',
toChain: 'ethereum',
toUserAddress: '0xE1e0992Be9902E92460AC0Ff625Dcc1c485FCF6b', // enter your ethereum wallet here
toChainDecimal: 18,
};
const transfer = await sendTransactionRequest({
fromChain: transferParams.fromChain,
fromTokenAddress: transferParams.fromTokenAddress,
fromUserAddress: transferParams.fromUserAddress,
tokenSymbol: transferParams.tokenSymbol,
toTokenAddress: transferParams.toTokenAddress!,
toChain: transferParams.toChain,
toTokenAmount: transferRoute.quote.amount,
toTokenSymbol: transferParams.toTokenSymbol!,
toUserAddress: transferParams.toUserAddress!,
tokenAmount: convertEthToWei(
transferParams.tokenAmount,
transferParams.fromChainDecimal,
),
route: transferRoute.route, // response from the `/qoute` endpoint
type: 'swap',
});Here's a sample response from this request:
{
"id": 258996,
"fromToken": {
"address": "btc",
"symbol": "BTC",
"name": "BTC",
"decimals": 8,
"logoURI": "https://raw.githubusercontent.com/polkaswitch/assets/master/blockchains/zksync-era/assets/0xBBeB516fb02a01611cBBE0453Fe3c580D7281011/logo.png"
},
"toToken": {
"address": "0x0000000000000000000000000000000000000000",
"symbol": "ETH",
"name": "ETH",
"decimals": 18,
"logoURI": "https://raw.githubusercontent.com/polkaswitch/assets/master/blockchains/solana/assets/7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs/eth.jpg"
},
"fromChain": {
"chainId": 0,
"name": "Bitcoin",
"slug": "bitcoin",
"protocolType": "bitcoin"
},
"toChain": {
"chainId": 1,
"name": "Ethereum",
"slug": "ethereum",
"protocolType": "evm"
},
"route": [
{
"bridge": "thorswap",
"bridgeTokenAddress": "btc",
"steps": ["allowance", "approve", "send"],
"name": "BTC",
"part": 100
}
],
"tx": {
"from": "bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x",
"to": "0x",
"value": "0x",
"data": "70736274ff0100d80200000002b05b268c9f39123623c19077fd8be9ea3eb4be2cc9bf2b9679a03eaef853e4de0200000000ffffffff5f1d0367c097ea1af3dfae2eeba4c66887b4b4fea3a4853e7fdb73d3dab59d280000000000ffffffff0330750000000000001600145c8e21c7446ac47b8537eeee77116d1bb33d82350000000000000000356a333d3a653a3078653165303939326265393930326539323436306163306666363235646363316334383566636636623a3a743a30f617000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed430000000000001011f3910000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed4300001011f499d000000000000160014ce50b3ee191c82edf49f4ec234c1d83696eed43000000000",
"meta": {
"from": "bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x",
"recipient": "bc1qtj8zr36ydtz8hpfhamh8wytdrwenmq34e0l6zc",
"amount": {
"amount": "30000",
"decimals": 8
},
"memo": "=:e:0xe1e0992be9902e92460ac0ff625dcc1c485fcf6b::t:0",
"slippage": 1146
}
}
}The definition for the sendTransactionRequest response can be found in src/interfaces/send.interface.ts.
export interface SendTransactionApiResponse {
id: number;
fromToken: Token;
toToken: Token;
fromChain: Chain;
toChain: Chain;
route: Route[];
tx: TransactionDetails;
}Since we're only interested in the tx object which contains our callData in the response, we'll extract it:
// src/components/Swaps.tsx
const { from, recipient, amount, memo } = transfer.tx.meta;Using our wallet provider, we will send a transaction to the user's wallet using xDefi's Injected Browser SDK which should be availabe to you if you have xDefi installed in your browser:
(window.xfi as any)?.bitcoin.request(
{
method: 'transfer',
params: [
{
from,
recipient,
amount,
memo,
},
],
},
(error: any, result: any) => {
console.log(error, result);
if (error) {
toast({
variant: 'destructive',
title: 'Something went wrong!',
description: 'Swap error, please check your balance or swap config',
});
setIsLoading(false);
setTransStatus(null);
}
const txHash = result;
pollTransactionStatus(transfer.id.toString(), txHash);
console.log(txHash);
},
);Executing this request, will bring up an xDefi prompt in your browser:
Bridging Assets from EVM to BTC
To Bridge assets from any EVM chain to the Bitcoin network, we essentially only have to reverse our transactionParams and perform a sendTransactionRequest:
const transferParams: TransferParams = {
tokenAmount: '1',
fromChain: 'ethereum',
fromUserAddress: '',
fromTokenAddress: '0x0000000000000000000000000000000000000000',
fromChainDecimal: 18,
tokenSymbol: 'ETH',
toTokenAddress: 'btc',
toTokenSymbol: 'BTC',
toChain: 'bitcoin',
toUserAddress: 'bc1qeegt8mserjpwmaylfmprfswcx6twa4psusas8x', // enter your bitcoin wallet here
toChainDecimal: 8,
};
const transfer = await sendTransactionRequest({
fromChain: transferParams.fromChain,
fromTokenAddress: transferParams.fromTokenAddress,
fromUserAddress: transferParams.fromUserAddress,
tokenSymbol: transferParams.tokenSymbol,
toTokenAddress: transferParams.toTokenAddress!,
toChain: transferParams.toChain,
toTokenAmount: transferRoute.quote.amount,
toTokenSymbol: transferParams.toTokenSymbol!,
toUserAddress: transferParams.toUserAddress!,
tokenAmount: convertEthToWei(
transferParams.tokenAmount,
transferParams.fromChainDecimal,
),
route: transferRoute.route, // response from the `/qoute` endpoint
type: 'swap',
});The tx object in our response from our sendTransactionRequest for an EVM to BTC bridge will look something like this:
{
....
"tx": {
"from": "0x018c15DA1239B84b08283799B89045CD476BBbBb",
"to": "0x39E3e49C99834C9573c9FC7Ff5A4B226cD7B0E63",
"data": "0x301a3720000000000000000000000000eeeeeeeeeeee........",
"value": "0x0e35fa931a0000",
"gas": "0x06a02f"
}
....
}Next, we will use our signer object to execute our callData transaction via xDefi or any Ethereum supported wallet:
First, let's extract the txData:
// src/components/Swaps.tsx
let txData: any = {
data: transfer.tx.data,
from: transfer.tx.from,
to: transfer.tx.to,
value: transfer.tx.value,
gasLimit: transfer.tx.gas,
};Using our signer, we will send a transaction to the user's wallet using the sendTransaction function from our signer:
// src/components/Swaps.tsx
const txResponse = await signer?.sendTransaction(txData); // <- `txResponse` contains the `txHash` of our transaction. You will need this later for getting a transaction's status.
const receipt = await txResponse?.wait();
console.log('Transaction receipt:', receipt);