LP API
The LP API bundle exposes a JSON API that allows liquidity providers to easily integrate with Chainflip, and is built on top of RPCs exposed directly by the Chainflip State Chain. It connects to a State Chain node, and handles the complexities of submitting extrinsics, and provides some utilities for assessing the state of the liquidity pools.
Command line arguments
The ws_endpoint
should point at a synced RPC node, the signing_key_file
should be the private key for their on-chain account, and that account should already be funded.
./chainflip-lp-api --help
chainflip-lp-api
USAGE:
chainflip-lp-api [OPTIONS]
OPTIONS:
-h, --help
Print help information
--port <PORT>
The port number on which the LP server 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 LPs secret key for signing extrinsics.
[default: /etc/chainflip/keys/signing_key_file]
--state_chain.ws_endpoint <WS_ENDPOINT>
The state chain nodes RPC endpoint. [default: ws://localhost:9944]
-v, --version
Print the version of the API
RPC Parameters
The parameters list of any JSONRPC call can be encoded as a JSON array or as an object. The advantage of the latter is that it's more explicit and allows for optional values to be omitted.
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.
Amount
An integer encoded as a big-endian hex string, between 0
and 2^128 - 1
, representing a quantity of a token in it's smallest unit.
For example, ETH uses 18 decimal places, so 100ETH is 100,000,000,000,000,000,000 Units, which encoded as hex is "0x56bc75e2d63100000"
. As another example, USDC uses 6 decimals, so 10USDC is 10,000,000 Units, which encoded as hex is "0x989680"
.
Liquidity
An integer encoded as a big-endian hex string, between 0
and 2^128 - 1
, representing the amount of liquidity in/the size of a range order.
Asset
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" }
.
If the chain is unambiguous (for example for native currencies), the asset can be submitted simply as the upper-case string. For example, for BTC, "BTC"
and { chain: "Bitcoin", asset: "BTC" }
are both valid and resolve to the same asset.
Chain
Chains are specified as the full name of the chain, capitalised, for example "Ethereum"
, "Bitcoin"
, "Polkadot"
.
Order IDs
Order IDs are integers encoded as a big-endian hex string, between 0
and 2^64 - 1
.
Order IDs are assigned by the LP, are unique within each pool, order type, side, and account, and can be re-used. Note that two limit orders, one buy and one sell, in the same pool (i.e. ETH-USDC) could simultaneously have the same ID, but two buys or two sells could not.
Depending on the order type you need different information to uniquely identify it:
- For limit orders, you need the LP who created it, the pool it is in i.e. the base and quote asset of the pool, the side of the limit order, and its Order ID.
- For range orders, you need the LP who created it, the pool it is in, and its Order Id.
Order Updates
Changes in order size are communicated via an increase_or_decrease
object which has this structures for range orders:
{
"increase": <range_order_size>
}
// OR
{
"decrease": <range_order_size>
}
And this structure for limit orders:
{
"increase": <amount>
}
// OR for a decrease:
{
"decrease": <amount>
}
These are used when calling the update_limit_order
or update_range_order
rpcs/extrinsics.
Range order size
Range orders are made up from a ratio of both the base and quote assets. This ratio is determined by the current price of the pool, and must remain constant. Therfore the amounts that are added or removed from a range order must match this ratio.
When describing the size of a range order you can use a liquidity number which is independent of the ratio, and so any liquidity number is valid. As the liquidity number is not an easily understandable concept, alternatively you can specify ranges for the amounts of both assets you want to add or remove or set the order to contain, but this will only be valid if an amount of both assets exists inside the ranges that matches the range order's required ratio.
For example if the ratio is 1 ETH:50 USDC, and you specify minimums of 10 ETH:2000 USDC, and maximums of 100 ETH:10000 USDC. It will pick 100 ETH:5000 USDC, as these are the largest amounts inside the specified ranges that match the required ratio. But if the maximums where instead 20 ETH:10000 USDC then there is no amount of ETH or USDC inside those ranges that matches the required 1 ETH:50 USDC ratio.
Encoded as JSON, depending on if you want to specify the "size" as amount ranges or liquidity, theses can be encoded like this:
{
"AssetAmounts": {
"maximum": {
"base": <amount>,
"quote": <amount>
},
"minimum": {
"base": <amount>,
"quote": <amount>
}
}
}
// OR
{
"Liquidity": {
"liquidity": <liquidity>
}
}
Tick
An integer between -887272
and 887272
inclusively representing a price. To calculate the nearest tick to a given price in the quote asset, use this formula: log1.0001(price * <QUOTE_ASSET_PRECISION> / <BASE_ASSET_PRECISION>)
. The tick representation of a price can be calculated by taking the log1.0001 of the price in the quote asset, and rounded down to the nearest integer. A tick can be turned into a price (into the quote asset) with this formula: (1.0001^tick) * <BASE_ASSET_PRECISION> / <QUOTE_ASSET_PRECISION>
. <ASSET_PRECISION>
for ETH would be 10^18
and for USDC it would be 10^6
.
Wait For
Some RPCs that submit extrinsics take an optional parameter wait_for
, this allows you to control under what condition the RPC will wait for until returning successfully. It can have these values:
NoWait
: This will cause the RPC to return once the extrinsic has been successfully submitted to the node.InBlock
: This will cause the RPC to return once the extrinsic has been included in a block.Finalized
: This will cause the RPC to return once the extrinsic has been included in a block that has been finalized. This is the default if the argument is not specified.
This option also affects the data returned by the rpcs, see Wait For Result.
Wait For Result
RPCs that take a wait_for
parameter when successful will return a object with one of these structures:
// For "wait_for: NoWait"
{
"tx_hash": <hex encoded transaction hash of the submitted extrinsic>
}
// OR for "wait_for: InBlock/Finalized"
{
"tx_details": {
"tx_hash": <hex encoded transaction hash of the submitted extrinsic>,
"response": <details of the outcome of the extrinsic, which varies between each RPC>,
}
}
Fixed Point Numbers
Fixed point numbers work similarly to integers, except instead of the all the bits representing positive integer powers of 2, the lower bits represent negative integer powers of two. For example if you have a normal 8 bit unsigned integer 01011100
, this represents 64 + 16 + 8 + 4 = 92
, but if we treat the same binary as an unsigned fixed point number with 4 fractional bits it would represent 4 + 1 + 0.5 + 0.25 = 5.75
. This is because in the integer case the bit's values are [128, 64, 32, 16, 8, 4, 2, 1]
, but in the fixed point case they are [8, 4, 2, 1, 0.5, 0.25, 0.125, 0.0625]
. See how there are 4 bits that have fractional/non-integer values.
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.
For example the price 10000 USDC/ETH represented in this format would be floor_to_integer((10000 * 10^6 / 10^18) * 2^128) = 3402823669209384634633746074317
. Note the 10^6
is 1 USDC is USDC's smallest unit, 10^18
is 1 ETH in ETH's smallest unit (wei), and the 128
in 2^128
in the number of fractional bits in the price, which as stated above is 128.
Square Root Price
A big-endian hex string encoded 160 bit unsigned fixed point number, with 96 fractional bits, representing the square root of a Price. This is the highest precision representation of a given price, when compared to the other available representations i.e. Tick and Price.
Side
The "side" of a limit order indicates if the limit order is buying the pool's base asset, or is selling the pool's base asset. It can have two values either "buy"
or "sell"
.
RPC Methods
lp_register_account
Submits an extrinsic that registers your account as an LP, so that allow this account can provide liquidity. The role of an account only needs to be registered once, and cannot be changed after it has been. It waits for the extrinsic to be successfully included in a block, and returns an error if the extrinsic expires before being included, or the extrinsic dispatch fails on-chain.
Parameters: None
Returns: The transaction hash of the extrinsic, otherwise an error.
lp_liquidity_deposit
Submits an extrinsic that opens a deposit address that you can send assets to. Once any assets you send are detected they will be credited to this account's free balance, and can then be used to create orders. We recommend waiting until the extrinsic is finalized before sending any assets to the desposit address to ensure the assets are correctly credited to your account.
Parameters:
- The encoded deposit address that you should send the deposit to.
Example
curl -H "Content-Type: application/json" -d '{
"id":1,
"jsonrpc":"2.0",
"method": "lp_liquidity_deposit",
"params": ["ETH"]
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"tx_details": {
"tx_hash": "0x676157322a644e5ba09f3c097d27ec17ec4768a19a2989ff603506bd42fd1fc4",
"response": "0x3999463978baf0295d9afdbd4a186a7280655a1b"
}
},
"id": 1
}
lp_register_liquidity_refund_address
Submits an extrinsic that sets your lp account's refund address for one of the external chains. For your lp account to have any assets associated with it, you must set a refund address with the external chain, that thoses assets associated with. For example, to create an order in the DOT-USDC pool, you must have Polkadot and Ethereum refund addresses registered. You can change your registered addresses at anytime via this RPC.
Parameters:
chain
: The external chain the refund address exists on.address
: The refund address for the specified external chain. Any assets associated with that chain will be transferred there if a refund is needed, e.g. "USDC" would be transferred to the address associated with "Ethereum".
Return:
- The transaction hash of the extrinsic that registered the new withdrawal address.
Example
curl -H "Content-Type: application/json" -d '{
"id":1,
"jsonrpc":"2.0",
"method": "lp_register_liquidity_refund_address",
"params": {
"chain": "Ethereum",
"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": "0x006595fa7c1010fece1835c91cfb24971eebe3fa75c587b6b4a2b4b5e6dd7387",
"id": 1
}
lp_withdraw_asset
This RPC allows you to withdraw assets associated with your lp account that are not currently deployed in orders. Note fees you earn are not automatically redeployed into your orders, and are therefore immediately withdrawable via this RPC.
Parameters:
asset_amount
: The amount to be withdrawn.asset
: The withdrawn asset.destination_address
: The address to send the withdrawn funds to.wait_for
- Egress id, which is used as the identifier for the operation/s to egress/withdraw the requested funds. It is structured as a JSON object like this:
[<chain>, <unsigned 64 bit integer ID>]
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_withdraw_asset",
"params": {
"amount": "1000",
"asset": "ETH",
"destination_address": "0xcfE27Ce6D57B81Ea86046aD1789104E5B7F0a2E7"
}
}' http://localhost:10589
{
"jsonrpc":"2.0",
"result": {
"tx_details": {
"tx_hash": "0xd3ab0132b7b4fb3f8d693d5588bc0493932bdc4f5e102f0627892cdf81932d96",
"response": ["Ethereum", 1]
}
},
"id": 1
}
lp_transfer_asset
This RPC allows you to transfer assets internally between your lp accounts. The destination account must be registered as an LP account.
Parameters:
asset_amount
: The amount to be transfered.asset
: The asset to be transfered.destination_account
: The account to transfer the funds to.
Response:
- The transaction hash of the extrinsic that transferred the funds.
Example
curl -H "Content-Type: application/json" -d '{
"id":1,
"jsonrpc":"2.0",
"method": "lp_transfer_asset",
"params": {
"amount": "2386f26fc10000",
"asset": "ETH",
"destination_account": "5GBa2utuhVfFpQePwTsWT9aTF4vDLV326dgrr8iJJZj9fXnT"
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": "0x9a43bb0f60976345c58b05b7ebb80bec2091070971bc4da4df628d31f03559b2",
"id": 1
}
lp_update_range_order
This RPC submits an extrinsic that will increase or decrease the size of an existing range order in the specified pool. If you try to increase the size of a non-existant order, that will result in a new range order being created with that id. If you decrease the size of an order by an amount equal to or greater than the order's size, that will close the order.
It can also be used to move assets from one range order to a new range order (in the same pool), by setting the optional argument tick_range
to the new tick range you want to move them to, and specifying the id
of an existing order. Any leftover assets, i.e. those that cannot be moved due to the new asset ratio requirement at the new tick range, will be deposited back into your free balance.
When creating a new order via this method you must specify the initial tick_range
to use, but assuming you don't wish to change the tick_range
as described above and you only want to increase or decrease the size of the existing order, you don't need to specify the tick_range
in future updates to that order.
Parameters:
base_asset
quote_asset
id
tick_range
(Optional): A JSON array of two Ticks, representing the lower and upper bound of the order's price range. Must be specified if no range order with the specifiedid
exists in this pool. If not specified, the tick range of the existing order with the sameid
will be used.size_change
wait_for
Response: A chronological list of all the updates that were done as part of the operation. Each item in the JSON array is an object with this structure:
{
"base_asset:" <asset>,
"quote_asset": <asset>,
"id": <order_id>,
"tick_range": [<tick>, <tick>],
"liquidity_total": <liquidity>,
"collected_fees": { "base": <amount>, "quote": <amount> },
"size_change": <order-update>
}
For example if a lp_update_range_order
request moves an existing range order to a new tick_range, the return would contain two of these, one for the decrease to zero/destruction of the order at the previous tick range, and then one for the increase/creation of the order at the new tick range.
Also this list will begin with updates to range orders, that do nothing to those range orders, and are just reporting the collected_fees
, from any range orders thst have collected fees since the last successful order update/asset withdrawal. So you will likely want to filter these out.
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_update_range_order",
"params": {
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "11",
"tick_range": [
0,
10
],
"size_change": {
"increase": {
"AssetAmounts": {
"maximum": {
"base": "0xDE0B6B3A76400",
"quote": "0xF4240"
},
"minimum": {
"base": "0x0",
"quote": "0x0"
}
}
}
}
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"tx_details": {
"tx_hash": "0xd7b48f3064d6ba6c9d88f0cf1c5dd23f4968eeaf9606ce3ad9dfce5302497ba5",
"response": [
{
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "0x11",
"tick_range": {
"start": 0,
"end": 10
},
"liquidity_total": "0x6c73e720beb1104f",
"collected_fees": {
"base": "0x0",
"quote": "0x0"
},
"size_change": {
"increase": {
"liquidity": "0x6c73e720beb1104f",
"amounts": {
"base": "0xde0b6b3a76400",
"quote": "0x0"
}
}
}
}
]
}
},
"id": 1
}
lp_set_range_order
This RPC submits an extrinsic that will open/close a range order in the specified pool. If you set a range order to a "zero" size, that will result in that range order being closed. If you set a non-existent range order to a non-zero "size", that will result in the creation of a new order.
It can also be used to move assets from one range order to a new range order (in the same pool), by setting the optional argument tick_range
to the new tick range you want to move them to, and specifying the id
of an existing order. Any leftover assets, i.e. those that cannot be moved due to the new asset ratio requirement at the new tick range, will be deposited back into your free balance.
When creating a new order via this method you must specify the initial tick_range
to use, but assuming you don't wish to change the tick_range
as described above and you only want to change the size of the existing order, you don't need to specify the tick_range
in future updates to that order.
Parameters:
base_asset
quote_asset
id
tick_range
(Optional): A JSON array of two Ticks, representing the lower and upper bound of the order's price range. Must be specified if no range order with the specifiedid
exists in this pool. If not specified, the tick range of the existing order with the sameid
will be used.size
wait_for
Response: A chronological list of all the updates that were done as part of the operation. Each item in the JSON array is an object with this structure:
{
"base_asset:" <asset>,
"pair_asset": <asset>,
"id": <order_id>,
"tick_range": [<tick>, <tick>],
"liquidity_total": <liquidity>,
"collected_fees": { "base": <amount> , "pair": <amount> },
"size_change":
}
For example if a lp_set_range_order
request changes the total size of an existing range order, the return would contain two of these, one for the decrease to zero/destruction of the previous order, and then one for the increase/creation of the order with the new size.
Also this list will begin with updates to range orders, that do nothing to those range orders, and are just reporting the collected_fees
, from any range orders thst have collected fees since the last successful order update/asset withdrawal. So you will likely want to filter these out.
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_set_range_order",
"params": {
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "11",
"tick_range": [
0,
10
],
"size": {
"AssetAmounts": {
"maximum": {
"base": "0xDE0B6B3A76400",
"quote": "0xF4240"
},
"minimum": {
"base": "0x0",
"quote": "0x0"
}
}
}
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"tx_details": {
"tx_hash": "0xfc013c63d5b510c6f5a3f1657f93b796ca3e4d3bdb877bd5f1cfb37d2240d830",
"response": [
{
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "0x11",
"tick_range": {
"start": 0,
"end": 10
},
"liquidity_total": "0x6c73e720beb1104f",
"collected_fees": {
"base": "0x0",
"quote": "0x0"
},
"size_change": {
"increase": {
"liquidity": "0x6c73e720beb1104f",
"amounts": {
"base": "0xde0b6b3a76400",
"quote": "0x0"
}
}
}
}
]
}
},
"id": 1
}
lp_update_limit_order
This RPC submits an extrinsic that will increase or decrease the size of an existing limit order in the specified pool. If you try to increase the size of a non-existant order, that will result in a new limit order being created with that id. If you decrease the size of an order by an amount equal to or greater than the order's size, that will close the order.
It can also be used to change the price of an existing limit order, by setting the optional argument tick
to the new tick you want, and specifying the id
of the existing order.
When creating a new order via this method you must specify the tick
to use, but assuming you don't wish to change the tick
as described above and you only want to increase or decrease the size of the existing order, you don't need to specify the tick
in future updates to that order.
Parameters:
base_asset
quote_asset
side
id
tick
(Optional): The price of the limit order.amount_change
: The amount of assets to add or remove from the limit order. For "buy" orders, this is measured in the quote asset, and for "sell" orders, this is measured in the base asset.dispatch_at
(Optional): If specified this RPC instead of submitting an extrinsic that does the specified operation, will submit an extrinsic that schedules the operation to occur at the specified block number. Note the RPC doesn't wait until the operation is scheduled, but only for the extrinsic (to the extent specified by thewait_for
argument). If thedispatch_at
block has already elapsed, this method returns an error.wait_for
Response: A chronological list of all the updates that were done as part of the operation. Each item in the JSON array is an object with this structure:
{
"base_asset": <asset>,
"quote_asset": <asset>,
"side": <side>,
"id": <order_id>,
"tick": <tick>,
"sell_amount_total": <amount>,
"collected_fees": <amount>,
"bought_amount": <amount>,
"sell_amount_change": { <increase_or_decrease>: <amount> }
}
For example if a lp_update_limit_order
request changes the total size of an existing range order, the return would contain two of these, one for the decrease to zero/destruction of the previous order, and then one for the increase/creation of the order with the new size.
Also this list will begin with updates to limit orders, that do nothing to those limit orders, and are just reporting the collected_fees
, from any limit orders thst have collected fees since the last successful order update/asset withdrawal. So you will likely want to filter these out.
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_update_limit_order",
"params": {
"base_asset": "ETH",
"quote_asset": "USDC",
"side": "buy",
"id": "11",
"tick": 50,
"amount_change": {
"increase": "0x100000"
}
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"tx_details": {
"tx_hash": "0x3f03edc0180fc9c7852f6fb429870794f07be80c241c9b93c9864041f97d8903",
"response": [
{
"base_asset": "ETH",
"quote_asset": "USDC",
"side": "buy",
"id": "0x11",
"tick": 50,
"sell_amount_total": "0x200000",
"collected_fees": "0x0",
"bought_amount": "0x0",
"sell_amount_change": {
"increase": "0x100000"
}
}
]
}
},
"id": 1
}
NOTE: If you pass the dispatch_at
parameter the response may not return any results due to the fact that order is not created/updated yet. Instead the response
array will be empty. The exception to this would be if the transaction is included in the dispatch_at
block, in which case the operation is executed immediately.
lp_set_limit_order
This RPC submits an extrinsic that will set the size of an existing limit order in the specified pool. If you try to set the size of a non-existant order, that will result in a new limit order being created with that id. If you set the size of an order to zero, that will close the order.
It can also be used to change the price of an existing limit order, by setting the optional argument tick
to the new tick you want, and specifying the id
of the existing order.
When creating a new order via this method you must specify the tick
to use, but assuming you don't wish to change the tick
as described above and you only want to increase or decrease the size of the existing order, you don't need to specify the tick
in future updates to that order.
Parameters:
base_asset
quote_asset
side
id
tick
(Optional): The price of the limit order.sell_amount
: The amount of assets the limit order should sell. For "buy" orders, this is measured in the quote asset, and for "sell" orders, this is measured in the base asset.dispatch_at
(Optional): If specified this RPC instead of submitting an extrinsic that does the specified operation, will submit an extrinsic that schedules the operation to occur at the specified block number. Note the RPC doesn't wait until the operation is scheduled, but only for the extrinsic (to the extent specified by thewait_for
argument). If thedispatch_at
block has already elapsed, this method returns an error.wait_for
- A chronological list of all the updates that were made as part of the operation. Each item in the list is a JSON object:
{
"base_asset": <asset>,
"quote_asset": <asset>,
"side": <side>,
"id": <order_id>,
"tick": <tick>,
"sell_amount_total": <amount>,
"collected_fees": <amount>,
"bought_amount": <amount>,
"sell_amount_change": { <increase_or_decrease>: <amount> }
}
For example if a lp_set_limit_order
request changes the price of a limit order, the response would contain two of these, one for the decrease to zero/destruction of the previous order, and then one for the increase/creation of the order with the price/tick.
Also this list will begin with updates to limit orders, that do nothing to those limit orders, and are just reporting the collected_fees
, from any limit orders thst have collected fees since the last successful order update/asset withdrawal. So you will likely want to filter these out.
NOTE: If you pass the dispatch_at
parameter the response may not return any results due to the fact that order is not created/updated yet. The exception to this would be if the submitted extrinsic is included in the dispatch_at
block, in which case the operation is executed immediately.
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_set_limit_order",
"params": {
"base_asset": "ETH",
"quote_asset": "USDC",
"side": "buy",
"id": "11",
"tick": 50,
"sell_amount": "0x100000"
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"tx_details": {
"tx_hash": "0x3cb78cdbbfc34634e33d556a94ee7438938b65a5b852ee523e4fc3c0ec3f8151",
"response": [
{
"base_asset": "ETH",
"quote_asset": "USDC",
"side": "buy",
"id": "0x11",
"tick": 50,
"sell_amount_total": "0x100000",
"collected_fees": "0x0",
"bought_amount": "0x0",
"sell_amount_change": {
"increase": "0x100000"
}
}
]
}
},
"id": 1
}
lp_asset_balances
This RPC returns the free balances of your LP account at the latest finalized block. Your free balance is all the funds that are not currently associated with an existing order. We recommend you use cf_account_info
to determine your free balance, instead of using this rpc due to a known issue where this function will not always include all the fees you have earned. Therefore the returned number can be slightly less than the true number.
Parameters: None
Return:
- An JSON object where each key is a Chain, and the values are arrays of
{ <asset>, <amount> }
pairs.
Example
curl -H "Content-Type: application/json" -d '{
"id":1,
"jsonrpc": "2.0",
"method": "lp_asset_balances",
"params": []
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"Ethereum": [
{
"asset": "ETH",
"balance": "0x2386f26fc0bda2"
},
{
"asset": "FLIP",
"balance": "0xde0b6b3a763ec60"
},
{
"asset": "USDC",
"balance": "0x8bb50bca00"
}
],
"Polkadot": [
{
"asset": "DOT",
"balance": "0x2540be40b"
}
],
"Bitcoin": [
{
"asset": "BTC",
"balance": "0x186a0"
}
]
},
"id": 1
}
lp_get_open_swap_channels
Returns a list of all the open deposit addresses currently open for swaps at the current finalized block. These are addresses that swappers will send funds they want to swap. Once a deposit to one of these addresses is detected we will then perform the swap on the State Chain after a waiting period to confirm the deposit.
Parameters: None
Return:
- All the open swap channels and their associated details in JSON format.
Example
curl -H "Content-Type: application/json" -d '{
"id":1,
"jsonrpc": "2.0",
"method": "lp_get_open_swap_channels",
"params": []
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"ethereum": [
{
"deposit_address": "0x0360dc218f90ab7b051078d5e6f7dcaa3946e78b",
"source_asset": "FLIP",
"destination_asset": "ETH"
},
{
"deposit_address": "0x606c4a8ef964acd004ae0075a4ed1a88f92b78d4",
"source_asset": "FLIP",
"destination_asset": "ETH"
},
{
"deposit_address": "0x677e7329ef04fdd798db49aed91557f583bb5f49",
"source_asset": "ETH",
"destination_asset": "USDC"
},
{
"deposit_address": "0x8c7951c65bdb8e57745ce980a5325c43e9a45c63",
"source_asset": "FLIP",
"destination_asset": "ETH"
},
{
"deposit_address": "0xbfbc1bdc3687efb7178ca48ab99be6966096fabf",
"source_asset": "ETH",
"destination_asset": "USDC"
},
{
"deposit_address": "0xd9c547e7f4ce721ad5b1be186ee6e608fd8a53b3",
"source_asset": "FLIP",
"destination_asset": "ETH"
},
{
"deposit_address": "0xe720e23f62efc931d465a9d16ca303d72ad6c0bc",
"source_asset": "ETH",
"destination_asset": "USDC"
},
{
"deposit_address": "0xfbfce7788b31c536bbeef0658f107f3b2cdfd6e4",
"source_asset": "ETH",
"destination_asset": "USDC"
}
],
"bitcoin": [
{
"deposit_address": "bcrt1pyv39rawd28erjv8h7xjwvq98wpmswl8vmcw4qr2j2n2f8jpwnztsuukr75",
"source_asset": "BTC",
"destination_asset": "ETH"
},
{
"deposit_address": "bcrt1pflqt7c2mncux4l4j56xq84qn98agylesjtgusc5fgjqc0ku8mzfs23eqwz",
"source_asset": "BTC",
"destination_asset": "ETH"
},
{
"deposit_address": "bcrt1pe9nd6pn8fez64ynwfk86zvkh209p4utcyl0sxg3gl7d52wex382s42yw67",
"source_asset": "BTC",
"destination_asset": "ETH"
},
{
"deposit_address": "bcrt1paf8lre750rw4d7hzmf8tea542sudxe0ssms7f7sjzemq9dhezxkqpe32ns",
"source_asset": "BTC",
"destination_asset": "ETH"
}
],
"polkadot": [
{
"deposit_address": "1WjReaZbkFDZF4XZ2GqMBtGJnDnB2c6SXBaGA39quiS8J7d",
"source_asset": "DOT",
"destination_asset": "FLIP"
},
{
"deposit_address": "1tDZGgNpmiAgHoR1J6e9akKfgqcMn16yKRRq6RcizC6cmVg",
"source_asset": "DOT",
"destination_asset": "FLIP"
},
{
"deposit_address": "13LnFhoh83G13Wtgiz8HCqmVdPaE5Sme4CHAndifv2kZ3BpF",
"source_asset": "DOT",
"destination_asset": "FLIP"
},
{
"deposit_address": "14kEEbKVd5PTCn3z1NVFfccU9oQ1TBXeZgH2BqhFnQTDC2D6",
"source_asset": "DOT",
"destination_asset": "FLIP"
}
]
},
"id": 1
}
lp_request_redemption
Request a redemption of all $FLIP or a specified amount. Please see Redeeming Funds & Retiring for more details on redeeming. Returns the transaction hash of the extrinsic that requested the redemption.
Parameters:
redeem_address
: The Ethereum address to send the redeemed funds to.exact_amount
(Optional): The amount of flip to redeem. If not specified, all $FLIP will be redeemed.executor_address
(Optional): Restricts theexecuteRedemption
function call in the Gateway contract to only be callable by the specified address for this redemption. If not specified, anyone can execute the redemption.
Example
Redeem all $FLIP:
curl -H "Content-Type: application/json" \
-d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_request_redemption",
"params": ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]
}' \
http://localhost:10589
Redeem an exact amount
:
curl -H "Content-Type: application/json" \
-d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_request_redemption",
"params": {
"redeem_address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"exact_amount": "0x1000000000",
"executor_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
}
}' \
http://localhost:10589
lp_order_fills
(>1.1.5)
Returns a list of all the fills in a given block.
Parameters:
at
(Optional): The block hash of the fills to return. The default is the latest finalized block's hash.
Return:
- Block hash
- Block number
- JSON array of all the fills in this finalized block. Exactly matching the structures returned by
subscribe_order_fills
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_order_fills",
"params": {
"at": "0xc65c18f81c4a9b1b5cd7e203f09eaa2288b44771e13d43791e1319a2695c72e9"
}
}' http://localhost:10589
{
"jsonrpc": "2.0",
"result": {
"block_hash": "0xc65c18f81c4a9b1b5cd7e203f09eaa2288b44771e13d43791e1319a2695c72e9",
"block_number": 67,
"fills": [
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "FLIP",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x13fbe85edc90000",
"quote": "0x1e63a"
},
"liquidity": "0x7055df27b7e148"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "DOT",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x0",
"quote": "0x1d33c"
},
"liquidity": "0x2e033968552"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x330b9eb022000",
"quote": "0x262d6"
},
"liquidity": "0xb3bc983f8c9bb"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "BTC",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x2bc",
"quote": "0x6a5dd"
},
"liquidity": "0x253fca1c0"
}
}
]
},
"id": 1,
}
lp_subscribe_order_fills
A subscription that lists all the orders that have been filled/partially filled by swaps in each finalized block. Note swaps are only considered done once they are in a finalized block.
Parameters: None
Return:
-
Block hash
-
Block number
-
JSON array of all the fills in this finalized block.
- For range order fills these look like this:
{ "range_order": { "lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM", "base_asset": "FLIP", "quote_asset": "USDC", "id": "0x0", "range": { "start": -887272, "end": 887272 }, # The fees that were earned by this fill "fees": { "base": "0x13fbe85edc90000", "quote": "0x1e63a" }, # The liquidity inside the filled range order. Note this liquidity number is not changed by fills "liquidity": "0x7055df27b7e148" } }
- For limit order fills these look like this:
{ "limit_orders": { "lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM", "base_asset": "FLIP", "quote_asset": "USDC", # The side of the order that was filled "side": "buy", "id": "0x0", "tick": 0, # The amount of the order that was used, in the units of the asset that was sold (by the order) "sold": "0x1200", # The amount assets bought during this fill, in the units of the bought asset "bought": "0x1200", # The fees earned during this fill, in units of the bought asset (Which in the asset you actually earn the fees in) "fees": "0x100", # The remaining amount in the order after the fill. This is in units of the sold asset. "remaining": "0x100000", } }
Example
curl -H "Content-Type: application/json" -d '{
"id": 1,
"jsonrpc": "2.0",
"method": "lp_subscribe_order_fills",
"params": []
}' http://localhost:10589
{
"jsonrpc": "2.0",
"method": "lp_subscribe_order_fills",
"params": {
"subscription": 4818071931255759,
"result": {
"block_hash": "0xc65c18f81c4a9b1b5cd7e203f09eaa2288b44771e13d43791e1319a2695c72e9",
"block_number": 67,
"fills": [
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "FLIP",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x13fbe85edc90000",
"quote": "0x1e63a"
},
"liquidity": "0x7055df27b7e148"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "DOT",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x0",
"quote": "0x1d33c"
},
"liquidity": "0x2e033968552"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x330b9eb022000",
"quote": "0x262d6"
},
"liquidity": "0xb3bc983f8c9bb"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "BTC",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x2bc",
"quote": "0x6a5dd"
},
"liquidity": "0x253fca1c0"
}
}
]
}
}
}
{
"jsonrpc": "2.0",
"method": "lp_subscribe_order_fills",
"params": {
"subscription": 4818071931255759,
"result": {
"block_hash": "0x09af8fa48149d182e26eee32f6bab6b871af4cee613367c2cf986a9e29ecc6ac",
"block_number": 68,
"fills": [
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "ETH",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x330b9eb022000",
"quote": "0x1d67b"
},
"liquidity": "0xb3bc983f8c9bb"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "FLIP",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x13fbe85edc90000",
"quote": "0x1a599"
},
"liquidity": "0x7055df27b7e148"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "BTC",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x0",
"quote": "0x5958e"
},
"liquidity": "0x253fca1c0"
}
},
{
"range_order": {
"lp": "cFPdef3hF5zEwbWUG6ZaCJ3X7mTvEeAog7HxZ8QyFcCgDVGDM",
"base_asset": "DOT",
"quote_asset": "USDC",
"id": "0x0",
"range": {
"start": -887272,
"end": 887272
},
"fees": {
"base": "0x5f5e100",
"quote": "0x1341e"
},
"liquidity": "0x2e033968552"
}
}
]
}
}
}
{
"jsonrpc": "2.0",
"method": "lp_subscribe_order_fills",
"params": {
"subscription": 4818071931255759,
"result": {
"block_hash": "0xd8f0f1833fc7e98458cc300dce85e56450aa19aabd8883f6c6cbcc8d97a8cc7a",
"block_number": 69,
"fills": []
}
}
}
Working Example
- Run the LP API server with the following command:
./chainflip-lp-api \
--state_chain.ws_endpoint ws://localhost:9944 \
--state_chain.signing_key_file /path/to/my/signing_key \
--port 80 # or whatever port you want to use
It will print 🎙 Server is listening on 0.0.0.0:80.
and continue to run.
- In another terminal: Register as an liquidity provider if you are not already.
curl -H "Content-Type: application/json" \
-d '{"id":1, "jsonrpc":"2.0", "method": "lp_register_account", "params": [0]}' \
http://localhost:80
Returns {"jsonrpc":"2.0","result":null,"id":1}
- Request a liquidity deposit address:
curl -H "Content-Type: application/json" \
-d '{"id":1, "jsonrpc":"2.0", "method": "lp_liquidity_deposit", "params": ["Eth"]}' \
http://localhost:80
The response is a hex-encoded deposit address: {"jsonrpc":"2.0","result":"0x350ec3dfd773978277868212d9f1319cbc93a8bf","id":1}
.
Limitations
- The current API architecture supports only
ws
and notwss
.
Running the LP API with Docker Compose
For a quick start with LP API, we have provided a docker-compose setup that runs the LP API and a State Chain node.