Submit Order Example
This example will go through how to integrate your DEX with the Anthic Trade API and the Radix Dapp Toolkit so that a user may submit a Limit Order Subintent to Anthic.
In this example a user wants to:
Sell 0.0003 xwBTC for xUSDC
Stream Prices
Pricing of assets can be retrieved by calling GET /trade/order_book?base=xwBTC"e=xUSDC
.
{
"pair": {
"base": "xwBTC",
"quote": "xUSDC"
},
"bids": [
[ "95086", "0.000013" ],
[ "95075", "0.000254" ],
[ "95072", "3.522345" ]
],
"asks": [
[ "95263", "4.151835" ],
[ "95264", "0.229412" ]
]
}
bids
and asks
are price-sorted arrays of (price, amount) tuples, expressing the available liquidity which
a user may take at that point in time.
This endpoint can be polled to retrieve near real-time pricing.
Compute Limit Order
Using the bids
array, we keep taking from the front of the array until the amount of requested from the user
is satisfied. This will give us an amount of xUSDC
which the user is capable of "buying" from the amount of
xwBTC
the user is "selling".
xusdc_amount = (0.000013 * 95086) + (0.000254 * 95075) + (0.000033 * 3.522345) = 25.3852842374
This value must then be rounded down based on the token's divisibility. xUSDC
has a divisibility of
6
so we round down this value to 25.385284
.
The limit order is then:
{
"sell": {
"symbol": "xwBTC",
"amount": "0.0003"
},
"buy": {
"symbol": "xUSDC",
"amount": "25.385284"
}
}
There is a possibility that the order book changes by the time submission occurs and that the order when submitted may not be filled. In order to prevent this from happening, you may on behalf of the user reduce the "buy" amount or increase the "sell" amount by a small percent. This will give the user worse pricing but a greater chance of having their order filled.
Compute Fee Amount
Anthic requires two fees which must be computed:
- An Anthic Fee which is based on the level of the user's account address and is a percentage of the sell asset
- A fixed Settlement Fee which is based on the fee payment asset. This consists of a Solver Fee which is a fee paid to the solver and a Transaction Execution Fee which covers the transaction execution cost. A portion of the transaction execution fee may be rebated to the user when the transaction is executed.
The level of a user's account address can be retrieve by GET /trade/account_addresses/account_tdx_2_128cmrtgzw82ukaphgy7yrfddh34gjnyxpmm00vkckpwzjjstwxqajm
{
"level": 1
}
The fee table configuration can be retrieved by GET /trade/info
{
"verify_parent_access_rule_sbor_hex": "5c2202012200012200012200012102809a4c6318c6318c6cb554820c6318c6318cf7a951d7a9e547c6318c6318c6c0021de40b09665d6aa3c8c9d4bcb4e4af712d5960b638efe78206591d5c7c19",
"per_token_settlement_fee": [
{
"symbol": "xwBTC",
"solver_amount": "0.000001",
"transaction_execution_amount": "0.000002"
},
{
"symbol": "xUSDC",
"solver_amount": "0.002",
"transaction_execution_amount": "0.2"
}
],
"per_level_anthic_fee": [
{
"taker_fee": "0.001",
"maker_fee": "0"
},
{
"taker_fee": "0.0009",
"maker_fee": "0"
}
]
}
If the user's account address is level 1
, then their Anthic fee given the above info is computed as:
anthic_fee = 0.0009 * 0.0003 = 0.00000027
settlement_fee = 0.000001 + 0.000002 = 0.000003
This value must then be rounded up based on the token's divisibility. xwBTC
has a divisibility of
8
so no rounding is required.
The fees will then end up looking like:
{
"symbol": "xwBTC",
"anthic_amount": "0.00000027",
"settlement_amount": "0.000003"
}
Compose Subintent Manifest
To construct a subintent manifest from a user's limit order and fee amounts you can call POST /construction/compose
with the request:
{
"type": "LimitOrder",
"account": "account_tdx_2_128cmrtgzw82ukaphgy7yrfddh34gjnyxpmm00vkckpwzjjstwxqajm",
"sell": {
"symbol": "xwBTC",
"amount": "0.0003"
},
"buy": {
"symbol": "xUSDC",
"amount": "25.385284"
},
"fee": {
"symbol": "xwBTC",
"anthic_amount": "0.00000027",
"settlement_amount": "0.000003"
}
}
You will then receive a response with a subintent manifest:
{
"manifest": "VERIFY_PARENT\n Enum<2u8>(\n Enum<0u8>(\n Enum<0u8>(\n Enum<0u8>(\n NonFungibleGlobalId(\"resource_tdx_2_1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxx3e2cpa:[e40b09665d6aa3c8c9d4bcb4e4af712d5960b638efe78206591d5c7c19]\")\n )\n )\n )\n )\n;\nCALL_METHOD\n Address(\"account_tdx_2_128cmrtgzw82ukaphgy7yrfddh34gjnyxpmm00vkckpwzjjstwxqajm\")\n \"withdraw\"\n Address(\"resource_tdx_2_1t5e0853tynmm42rwjts37q4ssemxnxzx5c6ywd0fdpanm30mkkav79\")\n Decimal(\"0.00030327\")\n;\nTAKE_FROM_WORKTOP\n Address(\"resource_tdx_2_1t5e0853tynmm42rwjts37q4ssemxnxzx5c6ywd0fdpanm30mkkav79\")\n Decimal(\"0.0003\")\n Bucket(\"sell\")\n;\nASSERT_NEXT_CALL_RETURNS_ONLY\n Map<Address, Enum>(\n Address(\"resource_tdx_2_1t5ggr0lr9vzr3mezxfrwf4g6c82ykq7yuuedkxjyns56va7vpclrkf\") => Enum<2u8>(\n Decimal(\"25.385284\")\n )\n )\n;\nYIELD_TO_PARENT\n Bucket(\"sell\")\n;\nTAKE_FROM_WORKTOP\n Address(\"resource_tdx_2_1t5e0853tynmm42rwjts37q4ssemxnxzx5c6ywd0fdpanm30mkkav79\")\n Decimal(\"0.00000027\")\n Bucket(\"anthic-fee\")\n;\nTAKE_FROM_WORKTOP\n Address(\"resource_tdx_2_1t5e0853tynmm42rwjts37q4ssemxnxzx5c6ywd0fdpanm30mkkav79\")\n Decimal(\"0.000003\")\n Bucket(\"solver-fee\")\n;\nYIELD_TO_PARENT\n Bucket(\"anthic-fee\")\n Bucket(\"solver-fee\")\n;\nCALL_METHOD\n Address(\"account_tdx_2_128cmrtgzw82ukaphgy7yrfddh34gjnyxpmm00vkckpwzjjstwxqajm\")\n \"deposit_batch\"\n Expression(\"ENTIRE_WORKTOP\")\n;\nYIELD_TO_PARENT;\n"
}
If you would like to use a more custom manifest or manually create the manifest yourself, see Limit Order Subintents.
This manifest may then be passed to the user's wallet for signature request via a PreAuthorizationRequest
using the Radix Dapp Toolkit.
Anthic requires a delay of between 15
seconds and 60
seconds to accept a subintent. In this case, we will
use 45
seconds.
rdt.walletApi.sendPreAuthorizationRequest(
SubintentRequestBuilder()
.manifest(manifest)
.setExpiration('afterDelay', 45)).then((result) => {
return result.value.signedPartialTransaction;
})
.onSubmittedSuccess((transactionIntentHash) => {
console.log('Submitted Successfully', transactionIntentHash);
})
Submit Signed Partial Transaction To Anthic
Once the user's wallet signs the subintent a signed_partial_transaction
will be returned. You can then call
POST /orders
with the signed_partial_transaction
{
"signed_partial_transaction": "<signed-partial-transaction>"
}
On success, this will return:
{
"success": true,
"success_response": {
"subintent_id": "<transaction-subintent-id>"
}
}
Track Status of Signed Partial Transaction
The onSubmittedSuccess
callback on the subintent builder above will be called if the partial
transaction is successfully committed on-ledger.
It is possible that the partial transaction has expired before even becoming visible to the Gateway, in which case you can track if a transaction's expiry timestamp has passed and assume it will fail.