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&quote=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.