Broker API
The Broker API is a standalone client that exposes Broker functionality via a JSON API interface. It can be obtained from the same location as the chainflip-node, i.e. you can install it via apt
, use the provided docker image or compile it yourself from the sources on Github.
Brokers need to run the client for the API themselves, as the Broker holds keys used to sign extrinsics and collect any fees set for Deposit Channels. The API client works by pointing it to an RPC node — also run by the same Broker, ideally.
1. Running Broker API locally
Before you do anything, you need to generate a valid signing_key and fund the associated account. If you are planning to use our Docker setup, instructions on how to generate new keys and fund your account are provided in the github repo.
Option A: Using the pre-compiled binaries
Download the chainflip-broker-api
software and the chainflip-node
:
apt-get install chainflip-broker-api
apt-get install chainflip-node
Generate a new signing key:
docker run --platform=linux/amd64 --entrypoint=/usr/local/bin/chainflip-cli chainfliplabs/chainflip-cli:berghain-1.6.7 generate-keys --json > broker-keys.json
mkdir -p /etc/chainflip/keys
cat broker-keys.json | jq -r '.signing_account_id' > /etc/chainflip/keys/signing_key_file
For a full list of command line arguments, see chainflip-broker-api --help
and chainflip-node --help
.
To use the default configuration, run:
- Testnet
chainflip-node --chain /etc/chainflip/perseverance.chainspec.json --rpc-methods=unsafe --sync=warp
chainflip-broker-api --state_chain.signing_key_file /etc/chainflip/keys/signing_key_file
Make sure the signing key file is not exposed. Access to this key gives full control over the Broker account.
- Mainnet
chainflip-node --chain /etc/chainflip/berghain.chainspec.json --rpc-methods=unsafe --sync=warp
chainflip-broker-api --state_chain.signing_key_file /etc/chainflip/keys/signing_key_file
Avoid exposing the broker-api publicly with these settings, as anyone could redeem your earned fees!
Option B: Running the Broker API with Docker Compose
Alternatively, for a quick start with the Broker API, we have provided a docker-compose setup that runs the Broker API and a State Chain node (required).
Option C: Running the Broker API in Kubernetes
Chainflip maintains a helm chart for running the Broker API in Kubernetes.
This setup requires a running instance of the State Chain (chainflip-node
). You can use this helm chart to deploy the Broker API and the State Chain in the same Kubernetes cluster.
2. Registering the account
After being funded, before you can fully interact with the Broker API, your account needs to be registered as a Broker account.
Command line arguments and defaults
- The
state_chain.ws_endpoint
should point at a synced Chainflip State Chain RPC node. The default isws://localhost:9944
— assuming it is run locally. - The
state_chain.signing_key_file
should be a path to a file containing the hex-encoded private key for the on-chain Broker account. The default file path is/etc/chainflip/keys/signing_key_file
. The account should be funded and the account role should be set to Broker. - The
port
is the port on which the Broker API will listen for connections. Use0
to assign a random port. The default is80
. - New functionality available from version 1.7+: The
health_check.hostname
andhealth_check.port
describe the hostname and port where the Broker API will listen for health check requests. Both arguments have to be specified for the health check server to start.
chainflip-broker-api --help
chainflip-broker-api
USAGE:
chainflip-broker-api [OPTIONS]
OPTIONS:
-h, --help
Print help information
--health_check.hostname <HEALTH_CHECK_HOSTNAME>
Hostname for this server's health check. Requires the <HEALTH_CHECK_PORT> parameter to be
given as well.
--health_check.port <HEALTH_CHECK_PORT>
Port for this server's health check. Requires the <HEALTH_CHECK_HOSTNAME> parameter to be
given as well.
--max_connections <MAX_CONNECTIONS>
The maximum number of concurrent websocket connections to accept. [default: 100]
--port <PORT>
The port number on which the broker will listen for connections. Use 0 to assign a
random port. [default: 80]
--state_chain.signing_key_file <SIGNING_KEY_FILE>
A path to a file that contains the broker's secret key for signing extrinsics.
[default: /etc/chainflip/keys/signing_key_file]
--state_chain.ws_endpoint <WS_ENDPOINT>
The state chain node's RPC endpoint. [default: ws://localhost:9944]
-v, --version
Print version information
3. Using the Broker: RPC Methods
broker_request_swap_deposit_address
Parameters:
source_asset
: Source asset.destination_asset
: Egress asset.destination_address
: Egress Address.broker_commission
: Broker Commission in basis points (100th of a percent or 0.01%). Broker operators can choose to charge a fee for the use of their endpoint, and can be set at any value from 1 basis point to 1000 basis points (0.01% - 10%).channel_metadata
: (Optional) Json object with the [cross-chain messaging]((../advanced/cross-chain-messaging/cross-chain-messaging.mdx) metadata:message
: Hex encoded call data used after the message is egressed.gas_budget
: The amount of gas or compute units required by the user logic on the destination chain.ccm_additional_data
: Hex encoded additional data for the cross-chain message. Should be an empty array except for CCM Swaps to Solana.
boost_fee
: (Optional) Maximum accepted boost fee in basis points (100th of a percent).affiliate_fees
: (Optional) Array of affiliate brokers (up to 5)[{"account": <AccountId>, "bps": <number>}]
.refund_parameters
: (Optional) Minimum accepted price for swaps through the channel as JSON object:{"retry_duration": <number>, "refund_address": <address>, "min_price": <hex_string>}
. Whereretry_duration
is a number of blocks,refund_address
is an address, andmin_price
is a price.dca_parameters
: (Optional) DCA parameters for swaps through the channel as JSON object:{"number_of_chunks": <number>, "chunk_interval": <number>}
. Wherenumber_of_chunks
is the number of "sub-swaps" to perform, andchunk_interval
is the delay between them in number of blocks.
Where every affiliate broker is defined as follow:
{
"account": <AccountId>,
"bps": <BasisPoints>,
}
The total broker fee is the sum of the broker_commission
+ all the affiliate_fees
.
Return:
- deposit address.
broker_register_account
Parameters:
None
Return:
null
if successful, otherwise an error.
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_register_account"}' | jq
broker_withdraw_fees
Withdraw all accumulated fees for a given asset.
Parameters:
asset
: The asset to withdraw.destination_address
: The destination address to which the assets should be withdrawn.
Return:
- tx_hash: Hash,
- egress_id: [ForeignChain, Number],
- egress_amount: Amount,
- egress_fee: Amount,
- destination_address: Address,
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_withdraw_fees", "params": {"asset": {"chain": "Ethereum", "asset": "ETH"}, "destination_address": "0xabababababababababababababababababababab"}}' | jq
Example output:
{
"jsonrpc": "2.0",
"result": {
"tx_hash": "0x736c159fec96ea84b8eceb49258019625a17e68ab981a3a674261e1df00a0482",
"egress_id": [
"Ethereum",
103
],
"egress_amount": 99998499999503000,
"egress_fee": 490000,
"destination_address": "0xabababababababababababababababababababab"
},
"id": 1
}
broker_mark_transaction_for_rejection
Request an incoming transaction to be rejected. Only available for bitcoin. This call will always succeed, but the transaction will only be refunded if it hasn't been witnessed on-chain yet. For un-boosted channels this means prior to 6 blocks confirmation, for boosted channels its prior to 1 block confirmation, i.e. only while the transaction is in the mempool. Also, a broker can only mark transactions going into its own deposit-channels for rejection.
Parameters:
tx_id
: The transaction id of the transaction to be rejected. Only bitcoin is supported, the transaction hash has to be specified as shown in the example below. Also, note that the byte order of the hash is in reverse to the usual representation in bitcoin block explorers.
Return:
- Nothing if transaction was successfully marked for rejection, error message otherwise.
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_mark_transaction_for_rejection", "params": {"tx_id": {"Bitcoin": "0x736c159fec96ea84b8eceb49258019625a17e68ab981a3a674261e1df00a0482"}}}' | jq
Example output (success):
{
"jsonrpc": "2.0",
"result": "null",
"id": 1
}
broker_get_open_deposit_channels
Return all deposit channels which have been opened and are relevant for broker_mark_transaction_for_rejection
. Only returns bitcoin channels.
Parameters:
query
: Which deposit channels to take into account. Possible values areMine
andAll
.
Return:
- All currently open bitcoin deposit channels that match
query
.
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_get_open_deposit_channels", "params": {"query": "Mine"}}' | jq
Example output:
{
"jsonrpc": "2.0",
"result": {
"btc_chain_accounts": [
{
"Taproot": [ ... ]
},
{
"Taproot": [ ... ]
},
{
"Taproot": [ ... ]
}
]
},
"id": 1
}
broker_subscribe_transaction_screening_events
Subscribe to all runtime events related to screening of transactions.
Parameters: None
Return:
- A websocket subscription for transaction screening events. It sends notifications about all screening events, i.e. not filtered by broker.
There are the following event types:
TransactionRejectionRequestReceived
TransactionRejectedByBroker
TransactionRejectionRequestExpired
Example input (the websocat
utility is useful for testing websocket subscriptions):
websocat ws://localhost
{"id": 1, "jsonrpc": "2.0", "method": "broker_subscribe_transaction_screening_events"}
Example subscription message:
{
"jsonrpc": "2.0",
"method": "broker_subscribe_transaction_screening_events",
"params": {
"subscription": 1667528407325164,
"result": {
"block_hash": "0xf3562acd35af86b19a1b8464ef589743b4482b36854f780f4b72199a0759e602",
"block_number": 242,
"btc_events": [
{
"TransactionRejectionRequestReceived": {
"account_id": "cFM8kRvLBXagj6ZXvrt7wCM4jGmHvb5842jTtXXg3mRHjrvKy",
"tx_id": "0x8c985d3252aa7d02fade82c55e3423c583d09f544acf80c4116987ed3a5d8b7d"
}
}
]
}
}
}
broker_request_swap_parameter_encoding
Create an encoded swap with the given parameters. The encoding depends on the chain of the input asset. See Vault Swaps for more details.
Parameters:
source_asset
: The source asset who's chain we are encoding for.destination_asset
: Egress asset.destination_address
: Egress Address.broker_commission
: Broker Commission in basis points (100th of a percent).extra_parameters
: JSON object with different data depending on the chain of the input asset.chain
: The chain of the input asset. Use only one of the following, then provide the corresponding parameters:Bitcoin
:min_output_amount
: Minimum output amount in the smallest unit of the output asset.retry_duration
: Number of blocks to wait before refunding the swap.
Ethereum
orArbitrum
:input_amount
: Amount of the input asset in the smallest unit.refund_parameters
: JSON object:{"retry_duration": <number>, "refund_address": <address>, "min_price": <hex_string>}
. See broker_request_swap_deposit_address for more details.
Solana
:from
: Address of the sender.event_data_account
: Address of the event data account.input_amount
: Amount of the input asset in the smallest unit.refund_parameters
: JSON object:{"retry_duration": <number>, "refund_address": <address>, "min_price": <hex_string>}
. See broker_request_swap_deposit_address for more details.from_token_account
: (Optional) Associated token account (ATA) of thefrom
account.
channel_metadata
: (Optional) Json object with the cross-chain messaging metadata:message
: Hex encoded call data used after the message is egressed.gas_budget
: The amount of gas or compute units required by the user logic on the destination chain.ccm_additional_data
: Hex encoded additional data for the cross-chain message. Should be an empty array except for CCM Swaps to Solana.
boost_fee
: (Optional) Maximum accepted boost fee in basis points (100th of a percent).affiliate_fees
: (Optional) Array of affiliate brokers (up to 5)[{"account": <AccountId>, "bps": <number>}]
.dca_parameters
: (Optional) DCA parameters for swaps through the channel as JSON object:{"number_of_chunks": <number>, "chunk_interval": <number>}
. Wherenumber_of_chunks
is the number of "sub-swaps" to perform, andchunk_interval
is the delay between them in number of blocks.
Return:
- Encoded swap data depending on the input asset chain. See vault swaps for more details.
Example usage:
curl -H "Content-Type: application/json" -d '
{
"id":1,
"jsonrpc":"2.0",
"method":"broker_request_swap_parameter_encoding",
"params":
{
"source_asset": "BTC",
"destination_asset": "ETH",
"destination_address": "0xabababababababababababababababababababab",
"broker_commission": 10,
"extra_parameters":
{
"chain": "Bitcoin",
"min_output_amount": 0,
"retry_duration": 0
}
}
}' http://localhost:10997
Example output:
{
"chain": "Bitcoin",
"nulldata_payload": "0x0001abababababababababababababababababababab00000000000000000000000000000000000001000200000000",
"deposit_address": "bcrt1phs8wzjf79ga4y04ses8alz4dgjlz0jdx0r8uat6w04e5xcvqtqkqe4rx3c"
}
broker_open_private_btc_channel
A private Bitcoin channel is a dedicated persistent deposit channel unique to a single broker.
Opening a private Bitcoin channel is a requirement for Brokers who wish to support Vault Swaps with Bitcoin as the source asset. This is a one-time operation and requires the Broker to post a bond of 100 $FLIP, meaning the Broker must maintain a balance of at least 100 FLIP. The bond will be unlocked once the Broker closes the channel again.
Note that even though the channel is considered persistent, the corresponding deposit address will change every Epoch.
Private Channels are not required unless the Broker wishes to support Vault Swaps with Bitcoin as source asset.
Parameters: None
Return: The channel ID (Number)
broker_close_private_btc_channel
Close the private Bitcoin deposit channel. The bond will be returned to your free balance.
Parameters: None
Return: The channel ID (Number)
broker_register_affiliate
Registers an affiliate account and returns the account id of the affiliate.
Parameters:
withdrawal_address
: The withdrawal address of the affiliate.
Return:
- The account id of the affiliate.
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_register_affiliate", "params": {"withdrawal_address": "0x3499b9b27ec38fe019299498958c451d294f6b5e"}}' | jq
Example output:
{
"jsonrpc": "2.0",
"result": "cFPS1XY681MaJZUKMQ1fEwThFGZveDkpgkwinsJRC24sRG1MR",
"id": 1
}
broker_affiliate_withdrawal_request
Request a withdrawal of the affiliate's collected commissions. The affiliate will receive the funds to their registered withdrawal address.
Parameters:
affiliate_account_id
: The account id of the affiliate.
Return:
- TxHash: The transaction hash of state chain extrinsic.
- EgressId: The egress id of the withdrawal.
- EgressAmount: The amount of the withdrawal.
- EgressFee: The fee of the withdrawal.
- DestinationAddress: The destination address of the withdrawal.
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_affiliate_withdrawal_request", "params": {"affiliate_account_id": "cFPS1XY681MaJZUKMQ1fEwThFGZveDkpgkwinsJRC24sRG1MR"}}' | jq
Example output:
{
"jsonrpc": "2.0",
"result": {
"tx_hash": "0x2b130acc1b3d56f8caff1e1adc32b8fbcc25c5ce0d9daa559d073e438c136ce1",
"egress_id": [
"Ethereum",
174
],
"egress_amount": "0x6d4186e",
"egress_fee": "0x1843a",
"destination_address": "0x015c2baa0c23ce4340eb24ca0562883084aacef3"
},
"id": 1
}
broker_get_affiliates
Get a list of all affiliates registered to your broker account.
Parameters: None
Return: Array of registered Affiliate Account IDs and Affiliate Details: [[<AffiliateId>, {"short_id": <ShortId>, "withdrawal_address": <EthereumAddress>}]]
.
Example input:
curl 'http://localhost/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_get_affiliates", "params": []}' | jq
Example output:
{
"jsonrpc": "2.0",
"result": [
[
"cFNGCP7MUJCbRyktHizaYnEekiTAPp1Sgopsbt99FNWc6Q1LU",
{
"short_id": 0,
"withdrawal_address": "0xa646ff46ce321cf4259caa01bcc71b54a333532c"
}
]
],
"id": 1
}
Working Example
This example assumes the node that is exposing the Statechain RPC's is funded.
- Open a terminal and run:
RUST_LOG=info chainflip-broker-api \
--state_chain.ws_endpoint=ws://localhost:9944 \
--state_chain.signing_key_file /etc/chainflip/keys/signing_key_file \
--port 62378 # or whatever port you want to use
It will print 🎙 Server is listening on 0.0.0.0:62378.
and continue to run.
- Open another terminal and run:
Register as a broker if you are not already.
curl 'http://localhost:62378/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_register_account"}'
- Request a swap deposit address:
curl 'http://localhost:62378/' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data-raw '{"id": 1, "jsonrpc": "2.0", "method": "broker_request_swap_deposit_address", "params": ["ETH", "FLIP","0xabababababababababababababababababababab", 0]}'
The result is the hex encoded deposit address, channel id, expiry block, and the issued block:
{
"jsonrpc":"2.0",
"result":{
"address":"0xe720e23f62efc931d465a9d16ca303d72ad6c0bc",
"issued_block":5418,
"channel_id":6,
"source_chain_expiry_block":2954
},
"id":1
}
Limitations
- The current API architecture supports only
ws
and notwss
.
Reference
Assets
Assets are specified as a { chain, asset }
object, where the chain is as described below, and the asset is an upper-case string.
Assets returned from the RPCs will always take the explicit form, for example { chain: "Ethereum", asset: "ETH" }
Chains
Chains are specified as the full name of the chain, capitalized, for example "Ethereum"
, "Bitcoin"
, "Solana"
.
Addresses
Addresses should be encoded according to their host chains:
- Ethereum addresses should be encoded as Hex strings, for example
"0xfa36e03defc6e4d140cc61fcaab9d1fbef18642f"
. - Polkadot addresses can be encoded using SS58 or Hex strings, for example:
"13zyEWmmLDx63Y99TL9SkxBe1DqPVCrcjXytxM3ZHGRyEJV5"
or"0x84aec0876dbb3cb7391eeded2eef5fbcf0d1a34f7c9f86f9af205f944b461761"
- Bitcoin addresses should be encoded using the appropriate bitcoin standard for the address type. For example
"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"
is a valid bech32 address on Bitcoin testnet. - Solana addresses can be encoded using bs58 or Hex strings:
"9acHwMGmeoMr5o8Cw1V2U4HjMQwhced3eQP31yYEhYDU"
or"0x7f799121d6c125f312c5f423a51959ce1d41df06af977e9a17f48b2c82ecf89f"
.
Price
A 256 bit unsigned fixed point number, with 128 fractional bits, representing a price as the amount of quote asset a single unit of the base asset is valued at. Note the amounts are in the smallest units of both assets.