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:
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;
}
};
CopyCopied!
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
}
}
....
}
CopyCopied!
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 chains
CopyCopied!
Next, 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);
}
}
CopyCopied!
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 ,
...
};
CopyCopied!
Destination Chain Config
const transferParams : TransferParams = {
...
toTokenAddress: '0x0000000000000000000000000000000000000000' ,
toTokenSymbol: 'ETH' ,
toChain: 'ethereum' ,
toUserAddress: '0xE1e0992Be9902E92460AC0Ff625Dcc1c485FCF6b' ,
toChainDecimal: 8 ,
...
};
CopyCopied!
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' ,
});
CopyCopied!
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
}
}
}
CopyCopied!
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 ;
}
CopyCopied!
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;
CopyCopied!
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);
},
);
CopyCopied!
Executing this request, will bring up an xDefi prompt in your browser:
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' ,
});
CopyCopied!
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"
}
....
}
CopyCopied!
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,
};
CopyCopied!
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);
CopyCopied!