EVM Vault swaps
Initiating a Vault Swap on an EVM chain (currently Ethereum or Arbitrum) requires making a smart contract call to Chainflip's Vault contract. The contract addresses can be found in Testnet addresses and Mainnet addresses.
EVM Vault Swaps follow the same pattern mentioned in the Vault Swaps overview:
- Request the swap parameter encoding.
- Use the return values to build a custom EVM transaction.
- Sign and broadcast the transaction to the target network.
Swap Parameter Encoding via Broker API
1. Request the encoded parameters via RPC
Example Request with refund parameters and a CCM message:
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "broker_request_swap_parameter_encoding",
"params": {
"source_asset": { "chain": "Ethereum", "asset": "ETH" },
"destination_asset": { "chain": "Ethereum", "asset": "FLIP" },
"destination_address": "0xcf0871027a5f984403aEfD2fb22831D4bEBc11Ef",
"broker_commission": 0,
"extra_parameters": {
"chain": "Ethereum",
"input_amount": 1000,
"refund_parameters": {
"retry_duration": 10,
"refund_address": "0xcf0871027a5f984403aEfD2fb22831D4bEBc11Ef",
"min_price": "0x0"
}
},
"channel_metadata": {
"message": "0x0011223344556677",
"gas_budget": 1000,
"ccm_additional_data": "0x"
}
}
}' http://localhost:10997
Example response:
{
"jsonrpc": "2.0",
"result": {
"chain": "Ethereum",
"calldata": "0x07933dd2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000014cf0871027a5f984403aefd2fb22831d4bebc11ef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000080011223344556677000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000a00000000cf0871027a5f984403aefd2fb22831d4bebc11ef000000000000000000000000000000000000000000000000000000000000000000009059e6d854b769a505d01148af212bf8cb7f8469a7153edce8dcaedd9d299125000000",
"value": "0x3e8",
"to": "0xb7a5bd0345ef1cc5e66bf61bdec17d2461fbd968"
},
"id": 1
}
Example response when the source asset is an ERC-20 token rather than native ETH or arbETH. Note the inclusion of the source_token_address
:
{
"jsonrpc": "2.0",
"result": {
"chain": "Ethereum",
"calldata": "0xbbddc2fb000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000010c6e9530f1c1af873a391030a1d9e8ed0630d2600000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000014cf0871027a5f984403aefd2fb22831d4bebc11ef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000080011223344556677000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f00000a000000cf0871027a5f984403aefd2fb22831d4bebc11ef000000000000000000000000000000000000000000000000000000000000000000002efeb485320647a8d472503591f8fce9268cc3bf1bb8ad02efd2e905dcd1f31e00000000",
"value": "0x3e8",
"to": "0xb7a5bd0345ef1cc5e66bf61bdec17d2461fbd968",
"source_token_address": "0x10c6e9530f1c1af873a391030a1d9e8ed0630d26"
},
"id": 1
}
2. Construct the Transaction
Note the return values from the above RPC call:
Field | Description |
---|---|
calldata | Hex-encoded EVM calldata. |
value | Hex-encoded amount of native currency - (Eth for Ethereum or ArbEth or Arbitrum). Always returns 0 for ERC-20 tokens. |
to | Chainflip's Vault Smart Contract address for either Ethereum or Arbitrum. |
source_token_address | (Optional) The token address requiring approval. |
The first three fields map closely to common EVM transaction building APIs and need to be included in the transaction. Other values such as gas
or gasPrice
can be estimated and set by the user or wallet.
Note that if source_token_address
is present, the returned address is the contract address of the ERC-20 token. This requires approval / whitelisting by the sender, before submitting the vault swap.
/*
Assume `calldata`, `value` and `to`;
*/
const web3 = new Web3("your-endpoint");
const tx = {
to: to,
data: calldata,
value: new BigNumber(value.slice(2), 16).toString(),
// .. possibly add gas details, or allow the API to set it.
};
// If `source_token_address` was returned from the RPC, the token requires approval.
// This is left as an excercise to the reader.
3. Sign and Send
The transaction needs to be finalised and signed by the sender.
As a basic example, using web3
and continuing from the previous code snippet:
// Assume a loaded `wallet`;
const signedTx = await web3.eth.accounts.signTransaction(tx, wallet.privateKey);
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction as string);
Full Example
This is a basic Typescript example combining the above steps.
import BigNumber from 'bignumber.js';
import Web3 from 'web3';
jsonrpc: "2.0",
method: "broker_request_swap_parameter_encoding",
params: {
source_asset: { chain: "Ethereum", asset: "ETH" },
destination_asset: { chain: "Bitcoin", asset: "BTC" },
destination_address: "bcrt1pesng8qzx6wn7m2a5xq480mmtwcme964nx60f7sfpjha8n8lsup8s2vdvvf",
broker_commission: 10,
extra_parameters: {
chain: "Ethereum",
input_amount: "0x100000000",
refund_parameters: {
retry_duration: 10,
refund_address: "0xcf0871127a5f984403aEfD2fb22831E4bEBc11Ef",
min_price: "0xabc"
}
},
dca_parameters: {
number_of_chunks: 4,
chunk_interval: 10
}
}
})
});
const encodedVaultSwapDetails = await response.json() as {
chain: 'Ethereum' | 'Arbitrum';
calldata: string;
value: string;
to: string;
};
chain: 'Ethereum' | 'Arbitrum';
calldata: string;
value: string;
to: string;
};
const web3 = new Web3("your-endpoint");
const tx = {
to: vaultSwapDetails.to,
data: vaultSwapDetails.calldata,
value: new BigNumber(vaultSwapDetails.value.slice(2), 16).toString(),
};
// Send and sign using the preferred method.
const signedTx = await web3.eth.accounts.signTransaction(tx, evmWallet.privateKey);
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction as string);
Vault contract interface reference
Incorrectly encoded parameters may result in the loss of user funds.
Therefore, it's advised to use the provided RPC to encode Vault Swap parameters. Otherwise make sure to thoroughly test your logic before initiating a swap with real funds. You can test against a local instance of the Chainflip network. Reach out on our Discord community server if you wish to know more.
The Vault smart contract can be called directly without using the provided RPCs to encode the transaction. Here is the reference for the Vault smart contract interface.
In the case of swapping ERC-20 tokens corresponding token approval is required.
// Swap native token
function xSwapNative(
uint32 dstChain,
bytes calldata dstAddress,
uint32 dstToken,
bytes calldata cfParameters
) external payable;
// Swap ERC20 token
function xSwapToken(
uint32 dstChain,
bytes calldata dstAddress,
uint32 dstToken,
IERC20 srcToken,
uint256 amount,
bytes calldata cfParameters
) external;
// Swap native token with CCM
function xCallNative(
uint32 dstChain,
bytes calldata dstAddress,
uint32 dstToken,
bytes calldata message,
uint256 gasAmount,
bytes calldata cfParameters
) external payable;
// Swap ERC20 token with CCM
function xCallToken(
uint32 dstChain,
bytes calldata dstAddress,
uint32 dstToken,
bytes calldata message,
uint256 gasAmount,
IERC20 srcToken,
uint256 amount,
bytes calldata cfParameters
) external;
Parameter reference
Param | Description | Data Type |
---|---|---|
dstChain | Destination chain ID for the swap. | uint32 |
dstAddress | Address where the swapped tokens will be sent to on the destination chain. Addresses must be encoded into a bytes type valid for the destination chain. You can check out a reference on how to do address encoding for each of the chains from our SDK (opens in a new tab). | address |
dstToken | Destination token | uint32 |
srcToken | Address of the token to be swapped from the source chain. | address |
amount | Amount of the source token to be swapped. When swapping a native asset, the msg.value passed in the call will be used instead. | uint |
message | Message that is passed to the destination address on the destination chain. It must be shorter than 15k bytes. | bytes |
gasAmount | Gas budget for the call on the destination chain in gas units or compute units. This amount should cover the execution of the receiver's logic. | uint |
cfParameters | Additional metadata for additional features. It cannot be empty and must be correctly encoded according to Chainflip Parameters. | bytes |