Skip to main content

Actions

An action is an individual component of a transaction that issues, transfers, or retires tokens of a single flavor.

In this document, we will examine action queries, which are useful for retrieving historical state of the ledger.

For more information about creating actions, see Transactions.

Queries

There are two different types of queries that you can perform on actions:

  1. A list query returns a time-ordered set of actions beginning with the most recent.
  2. A sum query is an aggregate over the amount fields in a set of actions.

Both queries accept a filter to narrow the results.

Group By

The group-by query parameter on the sum actions query indicates how amounts of a set of actions should be summed.

The query will break the results into groups where all values of the each group-by field are identical. This is analogous to the "GROUP BY" clause in SQL.

If no group-by parameter is specified, all results will be summed to a single amount.

List actions

If your transaction structure has more than one action, you may wish to query a list of only one type.

For example, you could query all the actions where usd is issued:

Action.ItemIterable actions = new Action.ListBuilder()
.setFilter("type=$1 AND flavorId=$2")
.addFilterParameter("issue")
.addFilterParameter("usd")
.getIterable(ledger);
for (Action action : actions) {
System.out.println("amount: " + action.amount);
System.out.println("issued at: " + action.timestamp);
}

Sum actions

If you want to calculate historical totals of specific actions, you can perform a sum query using a filter.

For example, imagine a mobile wallet ledger where every transaction has two actions - one that transfers a payment amount of cash from a user to a merchant and one that transfers a fee amount of cash from the merchant to a company fee account.

{
actions: [
{
type: "transfer",
flavorId: "cash",
amount: 10000,
sourceAccountId: "alice",
destinationAccountId: "merchant1",
},
{
type: "transfer",
flavorId: "cash",
amount: 200,
sourceAccountId: "merchant1",
destinationAccountId: "feeAccount",
}
]
}

You could use a sum query to calculate the amount of fees earned since timestamp t.

Since we are looking for a single value, we do not need to provide a group-by parameter.

ActionSum.ItemIterable totals = new Action.SumBuilder()
.setFilter("destinationAccountId=$1 AND timestamp > $2")
.addFilterParameter("feeAccount")
.addFilterParameter(t)
.getIterable(ledger);
for (ActionSum total : totals) {
System.out.println("amount: " + total.amount);
}

Data Structure

Field Descriptions

FieldTypeDescription
idstringUnique identifier of the action.
timestampstringTime (in RFC3339 format) that the action was committed to the ledger.
typestringType of action – either issue, transfer, or retire.
amountintegerAmount of tokens issued, transferred, or retired.
flavor idstringThe id of the flavor.
source account idstringThe id of the source account.
filterstringThe filter provided at the time of transaction to select tokens.
filter paramsarray of stringsThe ordered set of values for any placeholders (e.g $1) included in the filter.
destination account idstringThe id of the destination account.
snapshotobjectA snapshot of all associated tags at the time of the transaction.
tagsJSON objectThe current tags on the action.
Snapshot Object
FieldTypeDescription
action tagsJSON objectThe tags of the action (at time of transaction).
flavor tagsJSON objectThe tags of the flavor (at time of transaction).
source account tagsJSON objectThe tags of the source account (at time of transaction).
destination account tagsJSON objectThe tags of the destination account (at time of transaction).
token tagsJSON objectThe tags added to the tokens as they arrived in the destination account (at time of transaction).
transaction tagsJSON objectThe tags added to the transaction (at time of transaction).

Example Objects

Issue Action
{
type: "issue",
id: "",
timestamp: "",
flavorId: "",
amount: 1,
destinationAccountId: "",
tags: {},
snapshot: {
actionTags: {},
flavorTags: {},
destinationAccountTags: {},
tokenTags: {},
transactionTags: {}
}
}
Transfer Action
{
type: "issue",
id: "",
timestamp: "",
flavorId: "",
amount: 1,
sourceAccountId: "",
filter: "",
filterParams: [""],
destinationAccountId: "",
tags: {},
snapshot: {
actionTags: {},
flavorTags: {},
sourceAccountTags: {},
destinationAccountTags: {},
tokenTags: {},
transactionTags: {}
}
}
Retire Action
{
type: "retire",
id: "",
timestamp: "",
flavorId: "",
amount: 1,
sourceAccountId: "",
filter: "",
filterParams: [""],
tags: {},
snapshot: {
actionTags: {},
flavorTags: {},
sourceAccountTags: {},
transactionTags: {}
}
}

SDK Examples

List query by flavor

List all actions that transferred USD.

Action.ItemIterable actions = new Action.ListBuilder()
.setFilter("type=$1 AND flavorId=$2")
.addFilterParameter("transfer")
.addFilterParameter("usd")
.getIterable(ledger);
for (Action action : actions) {
System.out.println("amount: " + action.amount);
System.out.println("transferred at: " + action.timestamp);
}

List query by account

List all actions where Alice transferred tokens (of any flavor) to Bob

Action.ItemIterable actions = new Action.ListBuilder()
.setFilter("sourceAccountId=$1 AND destinationAccountId=$2")
.addFilterParameter("alice")
.addFilterParameter("bob")
.getIterable(ledger);
for (Action action : actions) {
System.out.println("amount: " + action.amount);
System.out.println("flavor: " + action.flavorId);
System.out.println("transferred at: " + action.timestamp);
}

List query by action tags

Assuming that tokens are issued when a deposit occurs in some external system and the source of the deposit is recorded as a field in the action tags, list all issue actions where deposit source was wire transfer.

Action.ItemIterable actions = new Action.ListBuilder()
.setFilter("type=$1 AND tags.source=$2")
.addFilterParameter("issue")
.addFilterParameter("wire")
.getIterable(ledger);
for (Action action : actions) {
System.out.println("amount: " + action.amount);
System.out.println("flavor: " + action.flavorId);
System.out.println("deposited at: " + action.timestamp);
}

List query by flavor tags snapshot

Assuming each currency flavor is tagged with "type": "currency", list all actions where any type of "currency" was issued.

Action.ItemIterable actions = new Action.ListBuilder()
.setFilter("type=$1 AND snapshot.flavorTags.type=$2")
.addFilterParameter("issue")
.addFilterParameter("currency")
.getIterable(ledger);
for (Action action : actions) {
System.out.println("type: " + action.snapshot.flavorTags.get("type"));
System.out.println("currency: " + action.flavorId);
System.out.println("amount: " + action.amount);
System.out.println("issued at: " + action.timestamp);
}

Sum query by type over a time range

Assuming each currency flavor is tagged with "type": "currency", calculate the amount of each "currency" issued between timestamp t1 and t2.

ActionSum.ItemIterable sums = new Action.SumBuilder()
.setFilter("type = $1 AND snapshot.flavorTags.type = $2 AND timestamp >= $3 AND timestamp =< $4")
.addFilterParameter("issue")
.addFilterParameter("currency")
.addFilterParameter(t1)
.addFilterParameter(t2)
.addGroupByField("flavorId")
.getIterable(ledger);
for (ActionSum sum : sums) {
System.out.println("currency: " + sum.flavorId);
System.out.println("amount issued: " + sum.amount);
}