Daml
Transaction History Parsing
This page explains how to inspect the ledger to parse transaction history for a given party, in
order to identify executed mints, burns, and transfers.
to identify a transfer.
While this mechanism is arguably simpler than the CIP-0056 guidelines, it is not very robust: template
choice exercises are subject to change and are not guaranteed to be stable across releases.
CIP-0112 transaction parsing guidelines
CIP-0112 introduces a dedicated DamlEventLog interface to record transaction events. This
interface exposes a nonconsuming choice which is exercised within a transaction to record
relevant events.
A ledger client can query events on this interface to obtain an ordered series of events from the
participant node. You can refer to the relevant pieces of the Canton Network documentation
for additional details.
The
EventLog interface is not implemented in Registry Daml models prior to the 0.14 release. These
guidelines unfortunately do not apply to these earlier versions.As long as you support Registry 0.13 and older, you will need to use the below CIP-0056
transaction parsing guidelines.Example ledger query
Example ledger query
Here is an example query, using the JSON API endpoint for paginated updates
You will then need to filter the output events for exercises of the
v2/updates/get-updates-page.{
"beginOffsetExclusive": 0,
"endOffsetInclusive": 3703,
"maxPageSize": 100,
"updateFormat": {
"includeTransactions": {
"transactionShape": "TRANSACTION_SHAPE_LEDGER_EFFECTS",
"eventFormat": {
"filtersByParty": {
"registrar-dLhm20fxdH8_dL17::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895": {
"cumulative": [
{
"identifierFilter": {
"InterfaceFilter": {
"value": {
"interfaceId": "#splice-api-token-transfer-events-v2:Splice.Api.Token.TransferEventsV2:EventLog"
}
}
}
}
]
}
},
"verbose": false
}
}
}
}
EventLog_HoldingsChange
choice and look at the content of the choiceArgument object.Transfer parsing example
Transfer parsing example
For a transfer from Note that both the
issuer to holder, the choiceArgument object of the ExercisedEvent
includes the relevant information:- instrument admin
- relevant account
- transfer leg (
SenderSideif the relevant account is the sender,ReceiverSideotherwise)
"admin": "registrar-S92p6Rp513u3mvsg::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895",
"account": {
"owner": "issuer-S92p6Rp513u3mvsg::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895",
"provider": null,
"id": ""
},
"inputHoldingCids": [
"00bb9c3dc01c7cebc82d29ffcb677a2b50bddbb9a096cde58000ec97ec0eb9abc8ca121220b950163ec54c0b03cd1e1ed19e20d64862aa9dd2cacf02d8884423dd4c266fe8"
],
"transferLegSides": [
{
"transferLegId": "",
"side": "SenderSide",
"otherside": {
"owner": "holder-S92p6Rp513u3mvsg::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895",
"provider": null,
"id": "holder-account-1"
},
"amount": "100.0000000000",
"instrumentId": "INST",
"meta": {
"values": {
"splice.lfdecentralizedtrust.org/reason": "reference"
}
}
}
],
...
SenderSide and ReceiverSide are logged separately. The same format is used
for allocations (where there could be multiple TransferLegs for a given event).Mint parsing example
Mint parsing example
Mints only have a Likewise, burns only log a
ReceiverSide leg."admin": "registrar-dLhm20fxdH8_dL17::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895",
"account": {
"owner": "issuer-dLhm20fxdH8_dL17::12205dd5bd685449653161d47d2a7cb01c25d5b0a02dab5c79cafc8dafd811c79895",
"provider": null,
"id": ""
},
"transferLegSides": [
{
"transferLegId": "mint",
"side": "ReceiverSide",
"otherside": {
"owner": null,
"provider": null,
"id": "CIP-0112/mint"
},
"amount": "100.0000000000",
"instrumentId": "burn-mint-request-dLhm20fxdH8_dL17",
"meta": {
"values": {}
}
}
],
SenderSide leg.CIP-0056 transaction parsing guidelines
The first iteration of the Token Standard introduced a set of transaction history parsing guidelines. These are documented in the relevant pieces of the Canton Network documentation.Mint and Burn workflows
Mint and burn workflows are not part of the Token Standard and use Daml templates rather than interfaces. Choice exercises resulting in a successful mint or burn are tagged with the appropriate metadata as part of their choice result. For instance, the choice result for a successful burn includes"meta": {
"values": {
"splice.lfdecentralizedtrust.org/burned": "100.0",
"splice.lfdecentralizedtrust.org/reason": "",
"splice.lfdecentralizedtrust.org/tx-kind": "burn"
}
}
Other transaction parsing options
A third transaction parsing option is to rely on concrete template choice exercises, such as exercises of nonconsuming choice TransferRule_DirectTransfer : TransferRule_DirectTransfer_Result
-- ^ Used for executing a direct transfer.
-- This choice was added as of version `0.5.0` of this package.
A note on ledger pruning
In order to keep a Canton participant node healthy, it should be pruned at regular intervals. This means that the ledger will generally not retain all of the transaction history. The methodology described in this guide only applies to data that has not been pruned from the ledger. If the user needs to retain transaction data for a period of time longer than their pruning window, they should move the data outside of the Canton participant node before it gets pruned. For reference, the Registry operator node uses a retention period of 30 days for pruning.Migrating away from Executed* contracts
Up until version0.13 of the Registry App, an ExecutedTransfer contract is created by default
on each transfer transaction. Similar contracts are created for mint and burn operations.
While these contracts are very convenient to use, they are not sustainable as they lead to unbounded
ACS growth unless they get regularly archived by the instrument admin.
Thus, starting with version 0.14, these “execution” contracts will no longer be created.
Tokenizers that rely on these contracts to determine whether a transfer, mint, or burn have occurred
must switch to transaction history parsing based on ledger events before adopting the 0.14
release.
The following sub-section outlines a possible migration path, which
- relies on
Executed*contracts for transactions using0.13DARS or older - uses ledger events-based parsing for transactions using
0.14DARS
1
Determine a storage solution for transaction history
It is not the role of the Canton participant node to store your entire transaction history,
especially if your data retention requirements span a period of months or years.You should determine a durable store for the history that you need to retain, such as a
Postgres DB. See the note on ledger pruning for why this data should be
stored outside the Canton participant node.
2
Populate storage from Executed* contracts
Query the active
ExecutedMint, ExecutedBurn, and ExecutedTransfer contracts for the
parties and instruments whose history you need to retain.Copy the relevant contract payloads and transaction identifiers (updateId, recordTime) into
the durable store.Continue ingesting newly created result contracts until you have fully switched to ledger
event-based transaction parsing.Archive the ingested Executed* contracts to reduce burden on the participant node. This step
is optional, but recommended. Archival of these contracts can be done in a batched fashion in
order to minimize transaction cost.3
Introduce ledger events-based transaction parsing based on exercises of the `EventLog_HoldingsChange` interface
Introduce a process that updates the stored transaction history based on the parsing guidelines
introduced with CIP-0112.
4
Install the `0.14` DARS
You can now install the
0.14 DARS. Transactions using these models will be caught only by the
ingestion process introduced in step 3.5
Disable ingestion of Executed* contracts
Once you (or the Registry operator) no longer support versions of the Registry App prior to
0.14, you can safely- unvet the corresponding DARS
- switch off the ingestion process based on
Executed*contracts from Step 2
Disable the creation of Executed* contracts prior to 0.14
Parties with theregistrar role can disable the creation of Executed* contracts on versions of
the app prior to 0.14.
This is controlled by a flag in the RegistrarService template, which can be set by calling
choice RegistrarService_Set : ContractId RegistrarService
-- ^ Sets the `enableResultContracts` flag.
-- This choice is introduced as of version `0.5.0` of this package.
-- As of version `0.9.0` of this package the value of the `enableResultContracts` flag is ignored.
with
enableResultContracts : Optional Bool
-- ^ New value for the flag.
Was this page helpful?
YesNo
⌘I