Ledger objects

Actions

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

On this page

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.

QueriesLink to this section

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 ByLink to this section

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 actionsLink to this section

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 assetId=$2")
  .addFilterParameter("issue")
  .addFilterParameter("usd")
  .getIterable(ledger);
for (Action action : actions) {
  System.out.println("amount: " + action.amount);
  System.out.println("issued at: " + action.timestamp);
}
let all = ledger.actions.list({
  filter: 'type=$1 AND assetId=$2',
  filterParams: ['issue', 'usd']
}).all()

while (true) {
  let { value: action, done: done } = await all.next()
  if (done) { break }
  console.log('amount: ', action.amount)
  console.log('issued at: ', action.timestamp)
}
ledger.actions.list(
  filter: 'type=$1 AND asset_id=$2',
  filter_params: ['issue', 'usd']
).each do |action|
  puts 'amount: ', action.amount
  puts 'issued at: ', action.timestamp
end

Sum actionsLink to this section

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

For example, imagine a payment network where every transaction has two actions - one that transfers a payment amount of cash from a payer to a merchant and one that transfers a fee amount of cash from the merchant to the operator's fee account.

{
  actions: [
    {
      type: "transfer",
      assetId: "cash",
      amount: 10000,
      sourceAccountId: "alice",
      destinationAccountId: "merchant1",
    },
    {
      type: "transfer",
      assetId: "cash",
      amount: 200,
      sourceAccountId: "merchant1",
      destinationAccountId: "feeAccount",
    }
  ]
}
{
  actions [
    {
      type: "transfer",
      assetId: "cash",
      amount: 10000,
      sourceAccountId: "alice",
      destinationAccountId: "merchant1",
    },
    {
      type: "transfer",
      assetId: "cash",
      amount: 200,
      sourceAccountId: "merchant1",
      destinationAccountId: "feeAccount",
    }
  ]
}
{
  actions [
    {
      type: "transfer",
      asset_id: "cash",
      amount: 10000,
      source_account_id: "alice",
      destination_account_id: "merchant1",
    },
    {
      type: "transfer",
      asset_id: "cash",
      amount: 200,
      source_account_id: "merchant1",
      destination_account_id: "fee_account",
    }
  ]
}

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);
}
let all = ledger.actions.sum({
  filter: 'destinationAccountId=$1 AND timestamp > $2',
  filterParams: ['feeAccount', t]
}).all()

while (true) {
  let { value: total, done: done } = await all.next()
  if (done) { break }
  console.log('total fees: ', total.amount)
}
ledger.actions.sum(
  filter: 'destination_account_id=$1 AND timestamp > $2',
  filter_params: ['fee_account', t]
).each do |total|
  puts 'total fees: ', total.amount
end

Data StructureLink to this section

Field DescriptionsLink to this section

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.
asset idstringThe id of the asset.
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 ObjectLink to this section

FieldTypeDescription
action tagsJSON objectThe tags of the action (at time of transaction).
asset tagsJSON objectThe tags of the asset (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 ObjectsLink to this section

Issue ActionLink to this section

{
  type: "issue",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  destinationAccountId: "",
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    destinationAccountTags: {},
    tokenTags: {},
    transactionTags: {}
  }
}
{
  type: "issue",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  destinationAccountId: "",
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    destinationAccountTags: {},
    tokenTags: {},
    transactionTags: {}
  }
}
{
  type: "issue",
  id: "",
  timestamp: "",
  asset_id: "",
  amount: 1,
  destination_account_id: "",
  tags: {},
  snapshot: {
    action_tags: {},
    asset_tags: {},
    destination_account_tags: {},
    token_tags: {},
    transaction_tags: {}
  }
}

Transfer ActionLink to this section

{
  type: "issue",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  sourceAccountId: "",
  filter: "",
  filterParams: [""],
  destinationAccountId: "",
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    sourceAccountTags: {},
    destinationAccountTags: {},
    tokenTags: {},
    transactionTags: {}
  }
}
{
  type: "issue",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  sourceAccountId: "",
  filter: "",
  filterParams: [""],
  destinationAccountId: "",
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    sourceAccountTags: {},
    destinationAccountTags: {},
    tokenTags: {},
    transactionTags: {}
  }
}
{
  type: "issue",
  id: "",
  timestamp: "",
  asset_id: "",
  amount: 1,
  source_account_id: "",
  filter: "",
  filter_params: [""],
  destination_account_id: "",
  tags: {},
  snapshot: {
    action_tags: {},
    asset_tags: {},
    source_account_tags: {},
    destination_account_tags: {},
    token_tags: {},
    transaction_tags: {}
  }
}

Retire ActionLink to this section

{
  type: "retire",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  sourceAccountId: "",
  filter: "",
  filterParams: [""],
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    sourceAccountTags: {},
    transactionTags: {}
  }
}
{
  type: "retire",
  id: "",
  timestamp: "",
  assetId: "",
  amount: 1,
  sourceAccountId: "",
  filter: "",
  filterParams: [""],
  tags: {},
  snapshot: {
    actionTags: {},
    assetTags: {},
    sourceAccountTags: {},
    transactionTags: {}
  }
}
{
  type: "retire",
  id: "",
  timestamp: "",
  asset_id: "",
  amount: 1,
  source_account_id: "",
  filter: "",
  filter_params: [""],
  tags: {},
  snapshot: {
    action_tags: {},
    asset_tags: {},
    source_account_tags: {},
    transaction_tags: {}
  }
}

SDK ExamplesLink to this section

List query by assetLink to this section

List all actions that transferred USD.

Action.ItemIterable actions = new Action.ListBuilder()
  .setFilter("type=$1 AND assetId=$2")
  .addFilterParameter("transfer")
  .addFilterParameter("usd")
  .getIterable(ledger);
for (Action action : actions) {
  System.out.println("amount: " + action.amount);
  System.out.println("transferred at: " + action.timestamp);
}
let all = ledger.actions.list({
  filter: 'type=$1 AND assetId=$2',
  filterParams: ['transfer', 'usd']
}).all()

while (true) {
  let { value: action, done: done } = await all.next()
  if (done) { break }
  console.log('amount: ', action.amount)
  console.log('transferred at: ',action.timestamp)
}
ledger.actions.list(
  filter: 'type=$1 AND asset_id=$2',
  filter_params: ['transfer', 'usd']
).each do |action|
  puts 'amount: ', action.amount
  puts 'transferred at: ', action.timestamp
end

List query by accountLink to this section

List all actions where Alice transferred tokens (of any asset) 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("asset: " + action.assetId);
  System.out.println("transferred at: " + action.timestamp);
}
let all = ledger.actions.list({
  filter: 'sourceAccountId=$1 AND destinationAccountId=$2',
  filterParams: ['alice', 'bob']
}).all()

while (true) {
  let { value: action, done: done } = await all.next()
  if (done) { break }
  console.log('amount: ', action.amount)
  console.log('asset: ', action.assetId)
  console.log('transferred at: ', action.timestamp)
}
ledger.actions.list(
  filter: 'source_account_id=$1 AND destination_account_id=$2',
  filter_params: ['alice', 'bob']
).each do |action|
  puts 'amount: ', action.amount
  puts 'asset: ', action.asset_id
  puts 'transferred at: ', action.timestamp
end

List query by action tagsLink to this section

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("asset: " + action.assetId);
  System.out.println("deposited at: " + action.timestamp);
}
let all = ledger.actions.list({
  filter: 'type=$1 AND tags.source=$2',
  filterParams: ['issue', 'wire']
}).all()

while (true) {
  let { value: action, done: done } = await all.next()
  if (done) { break }
  console.log('amount: ', action.amount)
  console.log('asset: ', action.assetId)
  console.log('deposited at: ', action.timestamp)
}
ledger.actions.list(
  filter: 'type=$1 AND tags.source=$2',
  filter_params: ['issue', 'wire']
).each do |action|
  puts 'currency: ', action.asset_id
  puts 'amount: ', action.amount
  puts 'deposited at: ', action.timestamp
end

List query by asset tags snapshotLink to this section

Assuming each currency asset 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.assetTags.type=$2")
  .addFilterParameter("issue")
  .addFilterParameter("currency")
  .getIterable(ledger);
for (Action action : actions) {
  System.out.println("type: " + action.snapshot.assetTags.get("type"));
  System.out.println("currency: " + action.assetId);
  System.out.println("amount: " + action.amount);
  System.out.println("issued at: " + action.timestamp);
}
let all = client.actions.list(
  filter: 'type=$1 AND snapshot.assetTags.type=$2',
  filterParams: ['issue', 'currency']
).all()

while (true) {
  let { value: action, done: done } = await all.next()
  if (done) { break }
  console.log('type: ', action.snapshot.assetTags.type)
  console.log('currency: ', action.assetId)
  console.log('amount: ', action.amount)
  console.log('issued at: ', action.timestamp)
}
ledger.actions.list(
  filter: 'type=$1 AND snapshot.asset_tags.type=$2',
  filter_params: ['issue', 'currency']
).each do |action|
  puts 'type: ', action.snapshot.asset_tags['type']
  puts 'currency: ', action.asset_id
  puts 'amount: ', action.amount
  puts 'issued at: ', action.timestamp
end

Sum query by type over a time rangeLink to this section

Assuming each currency asset 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.assetTags.type = $2 AND timestamp >= $3 AND timestamp <= $4")
  .addFilterParameter("issue")
  .addFilterParameter("currency")
  .addFilterParameter(t1)
  .addFilterParameter(t2)
  .addGroupByField("assetId")
  .getIterable(ledger);
for (ActionSum sum : sums) {
  System.out.println("currency: " + sum.assetId);
  System.out.println("amount issued: " + sum.amount);
}
let all = client.actions.sum(
  filter: 'type = $1 AND snapshot.assetTags.type = $2 AND timestamp >= $3 AND timestamp <= $4',
  filterParams: ['issue', 'currency', t1, t2],
  groupBy: ['assetId']
).all()

while (true) {
  let { value: sum, done: done } = await all.next()
  if (done) { break }
  console.log('currency: ', sum.assetId);
  console.log('amount issued: ', sum.amount);
}
ledger.actions.sum(
  filter: 'type = $1 AND snapshot.asset_tags.type = $2 AND timestamp >= $3 AND timestamp <= $4',
  filter_params: ['issue', 'currency', t1, t2],
  group_by: ['asset_id']
).each do |sum|
  puts 'currency: ', sum.asset_id
  puts 'amount issued: ', sum.amount
end