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:
- A list query returns a time-ordered set of actions beginning with the most recent.
- A sum query is an aggregate over the
amountfields 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
endSum 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
endData StructureLink to this section
Field DescriptionsLink to this section
| Field | Type | Description |
|---|---|---|
| id | string | Unique identifier of the action. |
| timestamp | string | Time (in RFC3339 format) that the action was committed to the ledger. |
| type | string | Type of action – either issue, transfer, or retire. |
| amount | integer | Amount of tokens issued, transferred, or retired. |
| asset id | string | The id of the asset. |
| source account id | string | The id of the source account. |
| filter | string | The filter provided at the time of transaction to select tokens. |
| filter params | array of strings | The ordered set of values for any placeholders (e.g $1) included in the filter. |
| destination account id | string | The id of the destination account. |
| snapshot | object | A snapshot of all associated tags at the time of the transaction. |
| tags | JSON object | The current tags on the action. |
Snapshot ObjectLink to this section
| Field | Type | Description |
|---|---|---|
| action tags | JSON object | The tags of the action (at time of transaction). |
| asset tags | JSON object | The tags of the asset (at time of transaction). |
| source account tags | JSON object | The tags of the source account (at time of transaction). |
| destination account tags | JSON object | The tags of the destination account (at time of transaction). |
| token tags | JSON object | The tags added to the tokens as they arrived in the destination account (at time of transaction). |
| transaction tags | JSON object | The 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
endList 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
endList 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
endList 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
endSum 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