> For the complete documentation index, see [llms.txt](https://docs.tradecraft.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tradecraft.fi/integrations/integrate-tradecraft/guide-dar-integration.md).

# Guide: DAR Integration

## Building on *Tradecraft*.

**INTEGRATION GUIDE - V1.1.13**\
A developer's reference for integrating the Canton-native AMM into your application : pool discovery, trading balances, orders, and withdrawals.

***

The Tradecraft Daml package is available on request. Contact us by email at <info@tradecraft.fi>.

***

{% hint style="danger" %}

#### Critical safety notice: ***Do not use the\*\*\*\* ****`delegatedOrder`**** \*\*\*\*parameter***

`delegatedOrder` is intentionally undocumented. Incorrect use can lead to **irrecoverable loss of funds**, and it is highly unlikely to be useful for your integration.

By continuing to use Tradecraft, you confirm that any use of `delegatedOrder` is at your own risk and that you are solely responsible for any resulting losses.
{% endhint %}

## 1.0 - Overview

### How Tradecraft works

Tradecraft is a decentralized exchange built natively on the Canton Network in Daml. As an integrator, you will work with a small set of templates and a single shared contract:

**`AMMRules`** : *singleton*\
The protocol contract that exposes every order-creation choice. All choices on it are *nonconsuming*, so the same contract is reused across every interaction. You will need its disclosure once per pool.

**`TradingBalance`** : *per user, per instrument*\
A vault-held balance of a single token, owned by the user. Tokens must be inside a TradingBalance before they can participate in a swap, deposit, or withdraw.

**`SwapOrder` - `DepositOrder` - `WithdrawOrder`**\
The three order types. Each is created by exercising a choice on AMMRules and consumes the relevant TradingBalance(s) atomically when it fills.

#### The five-step flow

1. **Discover** available trading pairs.
2. **Fund** a TradingBalance with the user's tokens.
3. **Submit** a SwapOrder (or DepositOrder / WithdrawOrder).
4. **Monitor** the order until it fills.
5. **Withdraw** the resulting balance back to the user's wallet.

{% hint style="info" %}
**NOTE:** Swap orders can optionally be configured for **direct settlement**, which delivers the swap output to a wallet - see Step 3 below.
{% endhint %}

## 2.0 - Network Reference

### Endpoints & protocol parties

The following parameters identify the live AMMs on each network. Treat them as configuration that your application should read from a single place rather than hard-coding at call sites.

**API base**

* **Mainnet** - `https://api.tradecraft.fi/v1`
* **Devnet** - `https://tradecraft.validator.dev.canton.obsidian.systems/amm-http-api`

**Venue**

* **Mainnet** - `Tradecraft::122096fe076cc065af0cb38f94caa60e8ddfecbe8f0cfe10655ae7aa06fab99c66b7`
* **Devnet** - `Tradecraft::122090f9041ae7a635c8471c7d496cf3158c294c154dd5468b19f8d37e949875203e`

**Vault**

* **Mainnet** - `cs-vault::1220b4cd6098eebafd4c88efd2b3986e86542bdc391060675432cd195ad26bcf013b`
* **Devnet** - `decentralized-party::1220b1f5f3fe39721e02a886b36a5a57dc215f5d2de275d9823107bcd825b186689d`

## 3.0 - The Integration Workflow

### Step 1 - Discover trading pairs

Fetch the list of every active AMM pool. The response gives you the `ammId` you'll need for every subsequent order.

```shell
$ curl https://api.tradecraft.fi/v1/pools | jq
```

{% hint style="info" %}
**NOTE:** Each pool's `ammId` is the only identifier you need to route an order to it. The venue and vault are the same across every pool on a given network.
{% endhint %}

### Step 2 - Fund a Trading Balance

Before a user can trade, their tokens must sit inside a `TradingBalance` contract. This is a two-call sequence. Fetch the disclosure for the AMMRules contract, then exercise the deposit choice.

#### Step 2a - Fetch the AMMRules disclosure

The path segments are the two instruments of the pool you intend to trade against. The example below targets the CBTC/CC pool.

```shell
$ curl https://api.tradecraft.fi/v1/disclosures/CBTC/CC | jq ".amm_rules"
```

#### Step 2b - Exercise `AMMRules_AddTradingBalance` (\~10.5 kB)

With the disclosure in hand, exercise the deposit choice. The user is the actor; their wallet's allocation context provides the tokens.

**Choice Signature**

```daml
nonconsuming choice AMMRules_AddTradingBalance : ContractId TradingBalance
  with
    actor : Party
      -- ^ The user depositing tokens
    allocationContext : (ContractId Allocation, ExtraArgs)
      -- ^ Allocation of tokens the actor is transferring to the vault
    existingBalances : [ContractId TradingBalance]
      -- ^ Existing balances to consolidate with this one
  controller actor
```

{% hint style="info" %}
**TIP:** Avoid UTXO Fragmentation. Pass ***every*** known `TradingBalance` contract ID for the given asset into `existingBalances` on every call. They will be consolidated atomically into a single new balance, keeping your contract set tidy and reducing downstream gas costs.
{% endhint %}

### Step 3 - Submit orders

All three order types (`SwapOrder`, `DepositOrder`, and `WithdrawOrder`) are created by exercising a nonconsuming choice on the same `AMMRules` singleton. The resulting order contracts are themselves templates you can query for status.

#### Swap orders *- exchanging two tokens* (\~5.67 kB)

Most integrations will spend the majority of their time here. The `what` field's two constructors describe the two natural shapes of a swap intent:

**`Long`** : *Buy* a fixed quantity of the instrument. Pay whatever the AMM quotes.\
**`Short`** : *Sell* a fixed quantity of the instrument. Receive whatever the AMM quotes.

If you've integrated against Tradecraft's Pool Addresses before, that product is built on `Short`.

**Choice Signature**

```daml
nonconsuming choice AMMRules_CreateSwapOrder : ContractId SwapOrder
  with
    actor : Party
    ammId : Text
    what : SwapDirection
    minOut : Optional Decimal
    requestTradingBalanceWithdrawal : Optional Party
      -- ^ When set, the swap output is settled directly to this party's
      --   wallet instead of being credited to a TradingBalance
      --   (see "Direct settlement" below)
```

**Resulting Template (Queryable)**

```daml
template SwapOrder
  with
    actor : Party
      -- ^ The party requesting the swap
    venue : Party
      -- ^ The AMM venue/operator party (see Network Reference)
    vault : Party
      -- ^ The AMM vault party (see Network Reference)
    ammId : Text
      -- ^ Identifies which AMM pool this order is for, as returned by /pools
    what : SwapDirection
      -- ^ Direction and amount of swap
    minOut : Optional Decimal
      -- ^ Minimum output amount (slippage protection)
    createdAt : Time
      -- ^ When this order was created. Must be monotonically increasing.
    expiresAt : Optional Time
      -- ^ When this order expires (orders can be filled up until this time).
      --   Optional for SCU compatibility; None means no automatic expiry (5 minutes).
    requestTradingBalanceWithdrawal : Optional Party
      -- ^ Request direct settlement of the swap output to the party
      --   specified, bypassing the TradingBalance
```

**The `SwapDirection` Enum**

```daml
data SwapDirection
  = Long with
      instrument : InstrumentId  -- Token the user wants to BUY
      amount : Decimal           -- How much they want to receive
  | Short with
      instrument : InstrumentId  -- Token the user wants to SELL
      amount : Decimal           -- How much they want to give
```

#### Swap orders *- direct settlement, skip the withdrawal step* (\~5.67 kB)

By default, a filled swap credits its output to a new `TradingBalance`, which you must then return to the user's wallet using `AMMRules_WithdrawTradingBalance`. Optionally setting `requestTradingBalanceWithdrawal = Some party` collapses the two steps into one. When the order is filled, the output is settled directly to the specified party's wallet and **no output TradingBalance is created**. The recipient is typically the actor themselves, but any party may be specified.

When a direct-settlement order is filled by the venue, the same transaction that archives the `SwapOrder` creates a `PhysicalSettlement` contract - an obligation to deliver the output, visible to the actor.

**Resulting Template (Queryable)**

```daml
template PhysicalSettlement
  with
    actor : Party
      -- ^ Party that requested the swap
    recipient : Party
      -- ^ Destination wallet
    venue : Party
      -- ^ Venue operator party
    vault : Party
      -- ^ Decentralized party who owns the pool holdings
    instrument : InstrumentId
      -- ^ Instrument to send
    amount : Decimal
      -- ^ Amount to send
    createdAt : Time
      -- ^ When this record was created
    releasedToActor : Optional Bool
      -- ^ Some True once the venue hands delivery to the actor
```

{% hint style="info" %}
**NOTE:** If the recipient has a transfer pre-approval for the output instrument, the tokens arrive in the recipient's wallet with no further action from you. If the recipient has **no pre-approval**, the tokens will appear as a transfer offer which the recipient must accept.
{% endhint %}

{% hint style="info" %}
**NOTE:** Direct settlement is only available for output instruments on the venue's settlement whitelist. An order requesting direct settlement of an unsupported output instrument will not fill. It is cancelled with the reason `"Withdrawal request not supported for this output instrument"`. Confirm whitelist coverage for your pairs with your Tradecraft contact, and exercise the flow on devnet before going live.
{% endhint %}

{% hint style="info" %}
**NOTE:** Monitoring and detection of filled orders is unchanged. Watch for the `SwapOrder`'s archival. The archiving transaction contains a `PhysicalSettlement` in place of the output `TradingBalance`.
{% endhint %}

#### Swap orders *- using holdings as input, with direct settlement, in a single choice*

{% hint style="danger" %}

### **WARNING: Pre-approval of both the input and output token is REQUIRED!**

{% endhint %}

The single-exercise variant. One call allocates the input amount from the actor's wallet holdings, funds the `TradingBalance`, and creates the `SwapOrder` atomically. On fill, the output settles directly to the actor's wallet. Step 2b and Step 5 drop out; only the Step 2a disclosure is still needed. Note that specifying `requestTradingBalanceWithdrawal = Some party` is not required.

{% hint style="danger" %}

#### **Critical safety notice:&#x20;*****A transfer pre-approval MUST be active for both tokens the user is swapping between BEFORE the order is submitted.***

{% endhint %}

Without it, **the swap still occurs** where the input is consumed on fill, but **NO funds are returned to the wallet**. If the order fails or is cancelled, pre-approval is required to receive the input tokens back. In both scenarios, the transfer-offer fallback under direct settlement above does **not** apply here. Missing pre-approval = **loss of funds**.

We highly recommend you test this version of swap order creation on devnet, confirming that tokens are received in the destination wallet before going live.

**Choice Signature**

```daml
nonconsuming choice AMMRules_CreateSwapOrderFromHoldings : AMMRules_CreateSwapOrderFromHoldings_Result
  with
    actor : Party
      -- ^ The user performing the swap
    ammId : Text
      -- ^ Identifies which AMM pool this order is for, as returned by /pools
    what : SwapDirection
      -- ^ Direction and amount of swap. Short only - see NOTE below.
    minOut : Optional Decimal
      -- ^ Minimum output amount (slippage protection)
    holdingCids : [ContractId Holding]
      -- ^ The actor's wallet holdings of the input instrument. Holdings in
      --   excess of the swap amount are returned to the actor as change.
    allocationContext : (ContractId AllocationFactory, ExtraArgs)
      -- ^ The input instrument's AllocationFactory and its ExtraArgs, used to
      --   allocate the input amount from the holdings to the vault
```

**Result Type**

```daml
data AMMRules_CreateSwapOrderFromHoldings_Result = AMMRules_CreateSwapOrderFromHoldings_Result
  with
    swapOrderCid : ContractId SwapOrder
      -- ^ The pending order (the same queryable SwapOrder template shown above)
    changeCids : [ContractId Holding]
      -- ^ Wallet change : input holdings in excess of the swap amount
```

{% hint style="info" %}
**NOTE:** Only `Short` is currently supported. `Long` orders fail with `"Only short orders are currently supported"`.
{% endhint %}

{% hint style="info" %}
**NOTE:** Monitoring is identical to direct settlement : watch for the `SwapOrder`'s archival; a `PhysicalSettlement` replaces the output `TradingBalance`.
{% endhint %}

{% hint style="info" %}
**NOTE:** Orders from this choice populate `delegatedOrder` internally. This is expected. The critical safety notice at the top of this guide still stands. Never set it yourself.
{% endhint %}

{% hint style="warning" %}
**Reminder : no pre-approval on the output token = the swap will execute but no funds will be returned.**
{% endhint %}

#### Deposit orders *- adding liquidity to a pool* (\~5.2 kB)

This choice deposit liquidity into a pool and mints LP tokens. Both `amount1` and `amount2` must already exist as funded TradingBalances for the actor.

**Choice Signature**

```daml
nonconsuming choice AMMRules_CreateDepositOrder : ContractId DepositOrder
  with
    actor : Party
    ammId : Text
    amount1 : Decimal
    amount2 : Decimal
    minOut : Optional Decimal
    changeAmounts : Optional [InstrumentAmount]
```

**Resulting Template (Queryable)**

```daml
template DepositOrder
  with
    actor : Party
      -- ^ The party requesting the deposit
    venue : Party
    vault : Party
    ammId : Text
      -- ^ Identifies which AMM pool this deposit is for
    amount1 : Decimal
      -- ^ Amount of instrument1 to deposit (must be pre-funded in TradingBalance)
    amount2 : Decimal
      -- ^ Amount of instrument2 to deposit (must be pre-funded in TradingBalance)
    createdAt : Time
    minOut : Optional Decimal
```

{% hint style="warning" %}
**NOTE:** `amount1` and `amount2` ***must*** be aligned with the current ratio of the pool. Fetch the current price with `GET /ratio/{tokenA}/{tokenB}`, or let the API compute aligned amounts for you with `GET /quoteLPDeposit/{tokenA}/{tokenB}`.
{% endhint %}

#### Withdraw orders *- removing liquidity from a pool* (\~5.2 kB)

This choice burns LP tokens, which must live in a TradingBalance, in exchange for the underlying pair.

**Choice Signature**

```daml
nonconsuming choice AMMRules_CreateWithdrawOrder : ContractId WithdrawOrder
  with
    actor : Party
    ammId : Text
    lpTokenAmount : Decimal
    minAmount1 : Optional Decimal
    minAmount2 : Optional Decimal
```

**Resulting Template (Queryable)**

```daml
template WithdrawOrder
  with
    actor : Party
      -- ^ The party requesting the withdrawal
    venue : Party
    vault : Party
    ammId : Text
      -- ^ Identifies which AMM pool this withdrawal is for
    lpTokenAmount : Decimal
      -- ^ Amount of LP tokens to burn (from TradingBalance)
    minAmount1 : Optional Decimal
      -- ^ Minimum amount of instrument1 to receive
    minAmount2 : Optional Decimal
      -- ^ Minimum amount of instrument2 to receive
    createdAt : Time
```

{% hint style="info" %}
**NOTE:** Every order template carries `actor`, `venue`, `vault`, and `ammId` - the same four identity fields. Parameterize these once in your client and reuse across all three constructors.
{% endhint %}

### Step 4 - Monitor for filled orders

When an order is filled by the venue, the original order contract, the consumed input `TradingBalance`(s), and the new output `TradingBalance`(s) are produced in the *same* transaction. Detection is therefore as simple as watching for the order's archival.

**Recommended**\
Use **PQS** (Participant Query Store) to subscribe to the relevant template streams.

**Without PQS**\
Query the participant's contracts endpoint directly for active `SwapOrder` contracts filtered by your actor. When the contract disappears, the fill has occurred; the new `TradingBalance` is created in the same transaction.

{% hint style="info" %}
**TIP:** If you need to surface the fill price to the user, walk the transaction tree that archived the `SwapOrder`. The same tree contains the new `TradingBalance`, so you can compute the realized rate directly.
{% endhint %}

{% hint style="info" %}
**NOTE:** Swap orders created with `requestTradingBalanceWithdrawal` set produce a `PhysicalSettlement` in the archiving transaction instead of an output `TradingBalance`. Order-archival detection works identically.
{% endhint %}

### Step 5 - Withdraw funds

When the user is ready to take their tokens back to their wallet, return them using `AMMRules_WithdrawTradingBalance`. Similar to deposits, this is a two-call sequence.

**TIP:** If you anticipate that the output of a swap order is the only thing you'd be withdrawing, set `requestTradingBalanceWithdrawal` when creating the order instead. The output is settled directly to the user's wallet and never lands in a `TradingBalance`.

#### Step 5a - Fetch the vault holdings

The withdrawal choice needs a list of holding contract IDs from the vault. Request them for the specific token, amount, and recipient.

```shell
$ curl -s -X POST \
    https://api.tradecraft.fi/v1/vault-holdings \
    -H 'Content-Type: application/json' \
    -d '{
      "token": "CC",
      "amount": 1.0,
      "vault": "cs-vault::1220b4cd6098eebafd4c88efd2b3986e86542bdc391060675432cd195ad26bcf013b",
      "receiver": "YourParty::YourNode"
    }' | jq
```

#### Step 5b - Exercise `AMMRules_WithdrawTradingBalance` (\~14.2 kB)

The choice supports both full and partial withdrawals, and consolidates fragmented balances in a single transaction.

```daml
nonconsuming choice AMMRules_WithdrawTradingBalance : TransferInstructionResult
  with
    actor : Party
    tradingBalanceCids : [ContractId TradingBalance]
      -- ^ TradingBalances to withdraw from. All will be archived;
      --   they must share the same actor and instrument.
      --   Multi-input is supported : fragmented balances are consolidated.
    amount : Optional Decimal
      -- ^ None = withdraw the full consolidated balance.
      --   Some x = partial withdrawal; remainder stays in a new TradingBalance.
    recipient : Party
      -- ^ Who to send the tokens to
    instrumentTransferInfo : InstrumentTransferInfo
      -- ^ Transfer infrastructure (TransferFactory, expectedAdmin, etc.)
    holdingCids : [ContractId Holding]
      -- ^ The holdings returned by /vault-holdings
```

{% hint style="info" %}
**NOTE:** If the recipient has a transfer pre-approval for the output instrument, the tokens arrive in the recipient's wallet with no further action from you. If the recipient has **no pre-approval**, the tokens will appear as a transfer offer which the recipient must accept.
{% endhint %}

## 4.0 - Type Reference

This is a consolidated list of every choice and template you'll touch as an integrator. Each lives on or is produced by the singleton `AMMRules` contract.

**Choices on `AMMRules`**

* `AMMRules_AddTradingBalance` → `ContractId TradingBalance`
* `AMMRules_CreateSwapOrder` → `ContractId SwapOrder`
* `AMMRules_CreateDepositOrder` → `ContractId DepositOrder`
* `AMMRules_CreateWithdrawOrder` → `ContractId WithdrawOrder`
* `AMMRules_WithdrawTradingBalance` → `TransferInstructionResult`

**Templates Produced**

* `TradingBalance` : per user, per instrument, holds tokens for use in orders
* `SwapOrder` : pending swap; archived on fill
* `DepositOrder` : pending LP deposit; archived on fill
* `WithdrawOrder` : pending LP redemption; archived on fill
* `PhysicalSettlement` : obligation to deliver a direct-settled swap output; created on fill when `requestTradingBalanceWithdrawal` is set

**Enums**

* `SwapDirection` : `Long` (buy fixed amount) or `Short` (sell fixed amount)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tradecraft.fi/integrations/integrate-tradecraft/guide-dar-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
