> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brale.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Canton Token Standard

> Transfer stablecoins to Canton Network parties using the Token Standard interface for offers and acceptance.

## Transfer Overview

Stablecoins issued by Brale are compatible with the Canton Token Standard, which specifies an interface which can be used to transfer any tokens that have smart contract Templates that comply in the same manner.

This is a 2-step process, in which the transfer is offered by the sender creating a Contract instance which implements the TransferInstruction interface and the recipient exercising the Accept choice on the TrnasferInstruction contract.

For transfers to parties also custodied by Brale, this acceptance is performed automatically.

For Canton network transfers to parties not custodied by Brale, a User with permission to ActAs the recipient party must use the Ledger API. Support for manually accepting transfers is included in the Canton Utility UI as well as other Token Standard-compliant wallet applications.

Offers must be accepted within 72 hours or they will expire and be automatically withdrawn.

## Instrument IDs and registrar parties

Token Standard calls identify a token by its instrument ID and its registrar (instrument admin) party. Use the registrar party in the `registrars/{party}` path of Token Standard API requests, such as the one in [Step 2](#step-2-get-the-contextual-data-needed-to-accept-the-transfer).

> [!WARNING]
>
> Instrument IDs and registrar parties are different on Canton mainnet (`canton`) and Canton testnet (`canton_testnet`). Don't reuse mainnet values on testnet. Requests that use the wrong registrar party fail with a "Registrar ... not found" error.

### SBC

**Mainnet (canton)**

| Field | Value |
| - | - |
| Instrument ID | `f29bdd7a-1469-498a-ba2a-796bf5387b31` |
| Registrar party | `party-28dc4516-b5ca-44ff-86c7-2107e90a6807::1220b8301e18aa8a401d6e34e6c20f8b0243183c514373bca8f1b6b9270246341a9e` |

**Testnet (canton\_testnet)**

| Field | Value |
| - | - |
| Instrument ID | `af5183ba-f6f5-4661-905f-bce6fdb1088e` |
| Registrar party | `brale-api-gateway::122056ed5f1222640cfab6d23b22e7e91446a72a5b226e0e8133f22687795228780a` |

SBC doesn't require holder credentials on either network. Any Canton party can hold and receive SBC.

### Other Brale-issued tokens

Each Brale-issued token on Canton, such as `CSC` or `4MGCC`, has its own instrument ID. Values also differ between mainnet and testnet. To get the instrument ID and registrar party for another token, contact Brale support and include the token's `value_type` and the network (`canton` or `canton_testnet`).

## Accepting a Transfer via the Ledger and Token Standard APIs

Acceptance can be automated by using the Ledger and Token Standard APIs to retrieve the necessary contextual information and exercise the Accept choice. The below example shows how to accept an offer using the HTTP JSON Ledger API of the recipient's participant.

### Step 1: Retrieve Pending Transfers

First, query your node to list all pending TransferInstructions associated with your party. This allows you to identify the specific transfer you intend to accept.

To query for the transfer instructions, it is first necessary to get the current ledger end offset.

```shell title="Get current ledger end offset" theme={null}
curl -s GET \
  --url "${HTTP_JSON_API}/v2/state/ledger-end" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${RECEIVER_TOKEN}"
```

Note the value of offset in the response, which will be used in the request to obtain the TransferInstructions.

```shell title="Get the active contracts as of the offset" theme={null}
curl -s \
  --url "${HTTP_JSON_API}/v2/state/active-contracts" \
  --header "Authorization: Bearer ${RECEIVER_TOKEN}" \
  --header "Content-Type: application/json" \
  --request POST \
  --data @- <<EOF
{
    "verbose": false,
    "activeAtOffset": "${OFFSET}",
    "filter": {
        "filtersByParty": {
            "${RECEIVER_PARTY_ID}": {
                "cumulative": [{
                    "identifierFilter": {
                        "InterfaceFilter": {
                            "value": {
                                "interfaceId":"55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281:Splice.Api.Token.TransferInstructionV1:TransferInstruction",
                                "includeInterfaceView": true,
                                "includeCreatedEventBlob": false
                            }
                        }
                    }
                }]
            }
        }
    }
}
EOF
```

Find the TransferInstruction you want to accept in the response and note its contractId and interfaceId, which will be used in subsequent steps.

### Step 2: Get the Contextual Data Needed to Accept the Transfer

In order to exercise the choice to accept the transfer, it is necessary to obtain some contextual information about it that cannot easily be obtained using the ledger, for which an off-ledger Token Standard API has been implemented.

```shell title="Use the Token Standard API to get the contextual information" theme={null}
curl -s \
    --url "https://api.utilities.digitalasset-dev.com/api/token-standard/v0/registrars/party-28dc4516-b5ca-44ff-86c7-2107e90a6807%3A%3A1220b8301e18aa8a401d6e34e6c20f8b0243183c514373bca8f1b6b9270246341a9e/registry/transfer-instruction/v1/${TRANSFERINSTRUCTION_CONTRACT_ID}/choice-contexts/accept" \
    --header "Content-Type: application/json" \
    --request POST \
    --data @- <<EOF
{
   "meta":{

   },
   "excludeDebugFields": true
}
EOF
```

Note the choiceContextData and disclosedContracts in the response, which will need to be provided to the accept choice.

### Step 3: Accept the Transfer Using the Ledger API

Once all the contextual information is obtained, the Accept choice of the TransferInstruction can be exercised via the ledger API to complete the transfer.

```shell title="Use the Ledger API to Excercise the Choice theme={null}
curl -s \
    --url "${HTTP_JSON_API}/v2/commands/submit-and-wait-for-transaction" \
    --header "Authorization: Bearer ${RECEIVER_TOKEN}" \
    --header "Content-Type: application/json" \
    --request POST \
    --data @- <<EOF
{
   "commands":{
        "commands":[
            {
                "ExerciseCommand":{
                    "templateId":"${TRANSFERINSTRUCTION_INTERFACE_ID}",
                    "contractId":${TRANSFERINSTRUCTION_CONTRACT_ID},
                    "choice":"TransferInstruction_Accept",
                    "choiceArgument":{
                        "extraArgs": {
                            "context": $CHOICECONTEXTDATA,
                            "meta":{
                                "values":{

                                }
                            }
                        }
                    }
                }
            }
        ],
        "workflowId":"",
        "userId":"${RECEIVER_USER_ID}",
        "commandId":"$(uuidgen | tr -d '\n')",
        "deduplicationPeriod":{
            "DeduplicationDuration":{
                "value":{
                    "seconds":30,
                    "nanos":0
                }
            }
        },
        "actAs":[
            "${RECEIVER_PARTY_ID}"
        ],
        "readAs":[

        ],
        "submissionId":"$(uuidgen | tr -d '\n')",
        "disclosedContracts": ${DISCLOSEDCONTRACTS},
        "domainId":"",
        "packageIdSelectionPreference":[]
    }
}
EOF
```
