Ledger objects

Tokens

All value in a ledger is represented as tokens. Each token is an indivisible, single unit of an asset, which denotes a specific type of value - for example, USD or acme-series-a.

On this page

To create new value in a ledger, you issue tokens into an account with a transaction. To transfer value in a ledger, you transfer tokens from one account to another. To remove value from a ledger, you retire tokens from an account.

Token TagsLink to this section

When issuing or transferring tokens into an account, you may wish to tag them for later distinction by providing token tags.

You can then specify a filter when transferring or retiring tokens from the account to target the tokens with specific tags.

Unlike the tags on other objects in the ledger, token tags only exist on the current state of the tokens in an account. Once those tokens are transferred in a transaction, the tags are removed and new tags can be added as they land in the destination account.

Updating tagsLink to this section

Since tokens are the fundamental state of the ledger, in order to update the tags on a group of tokens, you must create a transaction. In the future we will provide a special method for building a transaction that updates tags on tokens, but for now, you transfer them to and from the same account.

Data StructureLink to this section

The ledger does not store individual token objects, but rather token group objects, which each represent an amount of identical tokens.

If every token is unique, each token group will have an amount of 1.

Field DescriptionsLink to this section

FieldTypeDescription
amountintegerAmount of tokens.
tagsJSON objectArbitrary, user-supplied, key-value data about the tokens.
asset idstringThe id of the asset of the tokens.
asset tagsJSON objectThe tags of the asset of the tokens.
account idstringThe id of the account that holds the tokens.
account tagsstringThe tags of the account that holds the tokens.

Example ObjectLink to this section

{
  amount: 10,
  tags: {},
  assetId: ""
  assetTags: {},
  accountId: "",
  accountTags: {},
}
{
  amount: 10,
  tags: {},
  assetId: ""
  assetTags: {},
  accountId: "",
  accountTags: {},
}
{
  amount: 10,
  tags: {},
  asset_id: ""
  asset_tags: {},
  account_id: "",
  account_tags: {},
}

QueriesLink to this section

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

  1. A list query lists token groups in the ledger
  2. A sum query is an aggregate over the amount fields in a filtered list of token groups.

Both queries accept a filter to narrow the results.

List tokensLink to this section

The list tokens query is useful when you use token tags to differentiate tokens of the same asset in an account.

For example, if your application tracks stock certificates by tagging Acme stock tokens with a cost basis and purchase date in the token tags, you can list the token groups in Alice's account to see all her certificates.

Sum tokensLink to this section

The sum tokens query is how you calculate balances in the ledger.

For example, to calculate all the USD balance in Alice's account, you sum all the USD tokens in her account. Or to calculate the total amount of USD in the ledger, you sum all the USD tokens across all accounts.

ExamplesLink to this section

Issue tokensLink to this section

Issue 100 USD tokens to Alice's account.

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Issue()
    .setAssetId("usd")
    .setAmount(100)
    .setDestinationAccountId("alice")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.issue({
    amount: 100,
    assetId: 'usd',
    destinationAccountId: 'alice',
  })
})
tx = ledger.transactions.transact do |builder|
  builder.issue(
    asset_id: 'usd',
    amount: 100,
    destination_account_id: 'alice'
  )
end

Issue tokens with tagsLink to this section

Issue 100 debt tokens to Alice's account that are due December, 2018:

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Issue()
    .setAssetId("debt")
    .setAmount(100)
    .setDestinationAccountId("alice")
    .addTokenTagsField("due", "Dec2018")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.issue({
    amount: 100,
    assetId: 'debt',
    destinationAccountId: 'alice',
    tokenTags: { due: 'Dec2018' },
  })
})
tx = ledger.transactions.transact do |builder|
  builder.issue(
    asset_id: 'debt',
    amount: 100,
    destination_account_id: 'alice',
    token_tags: {due: 'Dec2018'}
  )
end

Transfer tokensLink to this section

Transfer 20 USD tokens from Alice's account to Bob's account.

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Transfer()
    .setAssetId("usd")
    .setAmount(20)
    .setSourceAccountId("alice")
    .setDestinationAccountId("bob")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.transfer({
    amount: 20,
    assetId: 'usd',
    sourceAccountId: 'alice',
    destinationAccountId: 'bob',
  })
})
tx = ledger.transactions.transact do |builder|
  builder.transfer(
    asset_id: 'usd',
    amount: 20,
    source_account_id: 'alice',
    destination_account_id: 'bob'
  )
end

Update tags by transferring tokens to same accountLink to this section

Update the due date from Dec2018 to Feb2019 on 20 debt tokens in Alice's account:

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Transfer()
    .setAssetId("debt")
    .setAmount(20)
    .setSourceAccountId("alice")
    .setDestinationAccountId("alice")
    .setFilter("tags.due=$1")
    .addFilterParameter("Dec2018")
    .addTokenTagsField("due", "Feb2019")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.transfer({
    amount: 20,
    assetId: 'debt',
    sourceAccountId: 'alice',
    destinationAccountId: 'alice',
    filter: 'tags.due=$1',
    filterParams: ['Dec2018'],
    tokenTags: { due: 'Feb2019' },
  })
})
tx = ledger.transactions.transact do |builder|
  builder.transfer(
    asset_id: 'debt',
    amount: 20,
    source_account_id: 'alice',
    destination_account_id: 'alice',
    filter: 'tags.due=$1',
    filter_params: ['Dec2018'],
    token_tags: {due: 'Feb2019'}
  )
end

Retire tokensLink to this section

Retire 5 USD tokens from Bob's account.

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Retire()
    .setAssetId("usd")
    .setAmount(5)
    .setSourceAccountId("bob")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.retire({
    amount: 5,
    assetId: 'usd',
    sourceAccountId: 'bob'
  })
})
tx = ledger.transactions.transact do |builder|
  builder.retire(
    asset_id: 'usd',
    amount: 5,
    source_account_id: 'bob'
  )
end

Retire tokens filtered by tagsLink to this section

Retire 80 of Alice's debt tokens due December 2018:

Transaction tx = new Transaction.Builder()
  .addAction(new Transaction.Builder.Action.Retire()
    .setAssetId("debt")
    .setAmount(80)
    .setSourceAccountId("alice")
    .setFilter("tags.due=$1")
    .addFilterParameter("Dec2018")
  ).transact(ledger);
await ledger.transactions.transact(b => {
  b.retire({
    assetId: 'debt',
    amount: 80,
    sourceAccountId: 'alice',
    filter: 'tags.due=$1',
    filterParams: ['Dec2018']
  })
})
tx = ledger.transactions.transact do |builder|
  builder.retire(
    asset_id: 'debt',
    amount: 80,
    source_account_id: 'alice',
    filter: 'tags.due=$1',
    filter_params: ['Dec2018']
  )
end

Sum tokens in an accountLink to this section

Query the first two pages of "balances" in Alice's account.

TokenSum.Page page1 = new Token.SumBuilder()
  .setFilter("accountId=$1")
  .addFilterParameter("alice")
  .addGroupByField("assetId")
  .setPageSize(10)
  .getPage(ledger);
for (TokenSum balance : page1.items) {
  System.out.println("amount: " + balance.amount);
  System.out.println("asset: " + balance.assetId);
}

String cursor = page1.cursor;

TokenSum.Page page2 = new Token.SumBuilder()
  .getPage(ledger, cursor);
for (TokenSum balance : page2.items) {
  System.out.println("amount: " + balance.amount);
  System.out.println("asset: " + balance.assetId);
}
let page1 = await ledger.tokens
  .sum({
    filter: 'accountId=$1',
    filterParams: ['alice'],
    groupBy: ['assetId'],
  })
  .page({ size: 10 })
page1.items.forEach(balance => {
  // console.log(balance)
})

let page2 = await ledger.tokens
  .sum()
  .page({ cursor: page1.cursor })
page2.items.forEach(balance => {
  // console.log(balance)
})
page1 = ledger.tokens.sum(
  filter: 'account_id=$1',
  filter_params: ['alice'],
  group_by: ['asset_id'],
).page(size: 10)

page1.each do |balance|
  puts 'amount: ', balance.amount
  puts 'asset: ', balance.asset_id
end

cursor = page1.cursor

page2 = ledger.tokens.sum.page(cursor: cursor)

page2.each do |balance|
  puts 'amount: ', balance.amount
  puts 'asset: ', balance.asset_id
end

List tokens in an accountLink to this section

Query the first two pages of token groups in Alice's account.

Token.Page page1 = new Token.ListBuilder()
  .setFilter("accountId=$1")
  .addFilterParameter("alice")
  .setPageSize(10)
  .getPage(ledger);
for (Token token : page1.items) {
  ...
}

String cursor = page1.cursor;

Token.Page page2 = new Token.ListBuilder()
  .getPage(ledger, cursor);
for (Token token : page2.items) {
  ...
}
page1 = await ledger.tokens
  .list({
    filter: 'accountId=$1',
    filterParams: ['alice'],
  })
  .page({ size: 10 })
page1.items.forEach(group => {
  // console.log(group)
})

page2 = await ledger.tokens
  .list()
  .page({ cursor: page1.cursor })
page2.items.forEach(group => {
  // console.log(group)
})
page1 = ledger.tokens.list(
  filter: 'account_id=$1',
  filter_params: ['alice'],
).page(size: 10)

page1.each do |group|
  puts group.to_json
end

cursor = page1.cursor

page2 = ledger.tokens.list.page(cursor: cursor)

page2.each do |group|
  puts group.to_json
end