Swapping
Integrations
Advanced Scenarios
Vault Swaps
Encoding Reference

Vault Swap Encoding Reference

It is strongly recommended to use the provided request_swap_parameter_encoding RPC rather than encoding the payload yourself.

If you want to encode a Vault Swap without the aid of a Chainflip RPC node or Broker API, this section gives an overview of the types and encodings required. Note this is not a complete reference. The canonical reference should be considered the Rust code. All types are encoded using Parity's Scale Codec unless otherwise stated.

Input parameters

ParameterDescriptionData Type
source_assetInput asset for the swapAsset
destination_assetOutput asset for the swapAsset
destination_addressDestination address the swap is paid out toAddressString
broker_commissionBroker commission in Basis pointu16
extra_parametersChain specific extra parameters. For details see each chain's dedicated pageVaultSwapExtraParametersRpc
channel_metadataOptional: Information for CCMOption<CcmChannelMetadata>
boost_feeOptional: Boost fee for the swap ingressOption<u16>
affiliate_feesOptional: A list of affiliates and their feesOption<Affiliates<AccountId32>>
dca_parametersOptional: Parameters for DCA swapsOption<DcaParameters>

Type References

The following are references for the Types used in Vault Swap calls. This can be used for references when building your RPC call.

/// For CCM message
pub struct CcmChannelMetadata {
	/// A Vec of bytes with maximum length of 15_000. `BoundedVec<u8, ConstU32<15_000>>`
	pub message: CcmMessage,
	/// User funds designated to be used for gas.
	pub gas_budget: GasAmount,
	/// Additional parameters for the cross chain message. Only used for Solana CCMs 
	/// A Vec of bytes with maximum length of 1_000. `BoundedVec<u8, ConstU32<1_000>>`
	pub ccm_additional_data: CcmAdditionalData,
}
 
/// Bounded vec of affiliates and fees in Basis Points. Max size of 5
pub type Affiliates<Id> = BoundedVec<Beneficiary<Id>, ConstU32<MAX_AFFILIATES>>;
 
pub struct Beneficiary<Id> {
	pub account: Id,
	pub bps: u16,
}
 
/// Parameters for DCA
pub struct DcaParameters {
	/// The number of individual swaps to be executed
	pub number_of_chunks: u32,
	/// The interval in blocks between each swap.
	pub chunk_interval: u32,
}

Supported Chain and Asset Notation

Chainflip uses its own notation for chain and token within our Vault smart contracts. These are the values for the source and destination chains and assets parameters described above. The same values apply for the the corresponding testnets (e.g. Ethereum mainnet and Sepolia share the same value).

AssetChainAsset IDChainChain ID
ETHEthereum1Ethereum1
FLIPEthereum2Polkadot2
USDCEthereum3Bitcoin3
DOTPolkadot4Arbitrum4
BTCBitcoin5Solana5
arbETHArbitrum6
arbUSDCArbitrum7
USDTEthereum8
SOLSolana9
solUSDCSolana10

Chainflip parameters (cf_parameters)

This section is only relevant if you want to encode EVM and Solana Vault swap transactions manually instead of using the provided RPC helpers. If you use the broker_request_swap_parameter_encoding RPC call to build the call, this field is automatically encoded for you.

As described in the EVM smart contract interface and the Solana program interface, the cf_parameters must be passed as part of the transaction data. The protocol expects a VersionedCfParameters encoded into bytes format using Parity's Scale.

#[derive(Encode, Decode)]
pub enum VersionedCfParameters<CcmData = ()> {
	V0(CfParameters<CcmData>),
}
 
/// By default, the CfParameters do not contain CCM message. Therefore the CcmData is the () type.
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)]
pub struct CfParameters<CcmData = ()> {
	/// CCMs may require additional data (e.g. CCMs to Solana requires a list of addresses).
	pub ccm_additional_data: CcmData,
	pub vault_swap_parameters: VaultSwapParameters,
}
 
/// If CCM is included as part of the Vault Swap, additional data should be included here.
/// Additional data is Byte array with a maximum size of 1_000. See below for more details.
pub type VersionedCcmCfParameters = VersionedCfParameters<CcmAdditionalData>;
pub type CcmAdditionalData = BoundedVec<u8, ConstU32<1_000>>;
 
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Clone, PartialEq, Debug)]
pub struct VaultSwapParameters {
  // Refund parameter, using Chainflip's internal `ForeignChainAddress` address format.
	pub refund_params: ChannelRefundParametersDecoded,
  // DCA parameters. See Vault Swaps page for its type reference.
	pub dca_params: Option<DcaParameters>,
	pub boost_fee: u8,
  // List of accounts and amount of fees to pay to (in BasisPoint)
	pub broker_fee: Beneficiary<AccountId>,
  // List of Affiliates to pay fees to.
	pub affiliate_fees: BoundedVec<AffiliateAndFee, ConstU32<5>>,
}

Here is an encoding example of the cf_parameters in typescript using the scale-ts library and some other utility functions from some other libraries. Those dependencies will be needed in your package.json file.

 
import { bytesToHex, hexToBytes } from '@chainflip/utils/bytes';
import * as ss58 from '@chainflip/utils/ss58';
import { isHex } from '@chainflip/utils/string';
import { u32, Struct, Option, u16, u256, Bytes as TsBytes, Enum, Vector, u8 } from 'scale-ts';
 
const vaultSwapParametersCodec = Struct({
  refundParams: Struct({
    retryDurationBlocks: u32,
    refundAddress: Enum({
      Ethereum: TsBytes(20),
      Polkadot: TsBytes(32),
      Bitcoin: TsBytes(),
      Arbitrum: TsBytes(20),
      Solana: TsBytes(32),
    }),
    minPriceX128: u256,
  }),
  dcaParams: Option(Struct({ numberOfChunks: u32, chunkIntervalBlocks: u32 })),
  boostFee: u8,
  brokerFees: Struct({ account: TsBytes(32), commissionBps: u16 }),
  affiliateFees: Vector(Struct({ account: u8, commissionBps: u8 })),
});
 
const vaultCcmCfParametersCodec = Enum({
  V0: Struct({
    ccmAdditionalData: TsBytes(),
    vaultSwapParameters: vaultSwapParametersCodec,
  }),
});
 
const vaultCfParametersCodec = Enum({
  V0: Struct({
    vaultSwapParameters: vaultSwapParametersCodec,
  }),
});
 
function encodeCfParameters(
  sourceChain: 'Bitcoin' | 'Ethereum' | 'Polkadot' | 'Arbitrum' | 'Solana',
  fillOrKillParams: {
    retryDurationBlocks: number;
    refundAddress: string;
    minPriceX128: string;
  },
  brokerFees: {
    account: string;
    commissionBps: number;
  },
  ccmAdditionalData?: string | undefined,
  boostFeeBps?: number,
  dcaParams?: {
    numberOfChunks: number;
    chunkIntervalBlocks: number;
  },
  affiliateFees?: {
    account: number;
    commissionBps: number;
  }[],
): string {
  const vaultSwapParameters = {
    refundParams: {
      retryDurationBlocks: fillOrKillParams.retryDurationBlocks,
      refundAddress: {
        tag: sourceChain,
        value: hexToBytes(fillOrKillParams.refundAddress as `0x${string}`),
      },
      minPriceX128: BigInt(fillOrKillParams.minPriceX128),
    },
    dcaParams,
    boostFee: boostFeeBps ?? 0,
    brokerFees: {
      account: isHex(brokerFees.account)
        ? hexToBytes(brokerFees.account)
        : ss58.decode(brokerFees.account).data,
      commissionBps: brokerFees.commissionBps,
    },
    affiliateFees: affiliateFees ?? [],
  };
 
  return bytesToHex(
    ccmAdditionalData !== undefined
      ? vaultCcmCfParametersCodec.enc({
          tag: 'V0',
          value: {
            ccmAdditionalData: hexToBytes(ccmAdditionalData as `0x${string}`),
            vaultSwapParameters,
          },
        })
      : vaultCfParametersCodec.enc({
          tag: 'V0',
          value: {
            vaultSwapParameters,
          },
        }),
  );
}