Digital Asset SDK sample - Track and Trace

This application sample illustrates the creation of a digital asset and the transfer of this asset between different owners.

Video

The video provides some context about the Track and Trace sample application and shows you how you can run the sample application.

GCP_SamplesTT

Steps

The track and trace application sample involves multiple operations:

  • the manufacturer creates a digital asset (a car)
  • the manufacturer transfers the ownership of the car to Alice
  • Alice transfers the ownership of the car to Bob
  • Bob transfers the ownership of the car to Charlie
  • the asset history of the car is fetched
  • the transaction history of each person along with the metadata is fetched.

This flow is illustrated by the following diagram:

2Diagram_TrackTrace

In addition to retrieving the asset and transaction history, the sample contains two important functions:

  • Create a digital asset
  • Transfer a digital asset

You can see the source code (Javascript) of the sample here.

Run the sample application

In a terminal session, run the track and trace sample found in folder ng-rt-digitalasset-sdk-sample:

node ng-rt-digitalAsset-sdk-samples/examples/usecases/track_and_trace.js

(alias: track)

You should see output similar to this:

[INFO] examples.basic.createAssetDefinition - { digitalAsset: 'sample_vehicle',
digitalAssetDescription: 'Sample vehicle asset description',
createTransactionAllowedBySystem: true,
transferOwnershipAllowedBySystem: true,
createTransactionAllowedByUser: true,
transferOwnershipAllowedByUser: true,
divisibleAsset: false,
fungibleAsset: false,
blockchainProvider: 'T',
blockchainProviderVersion: '0.32.8',
blockchainDriver: 'bdbDriver',
blockchainDriverVersion: '3.2.0' }
[INFO] examples.usecases.track_and_trace - Public Key of Car Manufacturer :  72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - Public Key of Alice :  89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - Public Key of Bob :  5JLRv9p1myDmJgWG2rFRfYD4xg8y116z3tK1RRN8hebZ
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - CREATE transaction id :  759af9b75274f48a788e76d8e4810260714eb699cedae13a67799aaaa6e9a86e
[INFO] examples.usecases.track_and_trace - 759af9b75274f48a788e76d8e4810260714eb699cedae13a67799aaaa6e9a86e
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - TRANSFER 1 transaction id: 2e981959cfe5dc4e2d7cf262f29df7f5aca099887fbdb15c76988fe89ad7ee4a
[INFO] examples.usecases.track_and_trace - 2e981959cfe5dc4e2d7cf262f29df7f5aca099887fbdb15c76988fe89ad7ee4a
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - TRANSFER 2 transaction id: 058ae98cf13d595ce5349919ebca54002cada83d4ac31e3948c1696d2b86d0b5
[INFO] examples.usecases.track_and_trace - 058ae98cf13d595ce5349919ebca54002cada83d4ac31e3948c1696d2b86d0b5
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - Current owner of asset is :5JLRv9p1myDmJgWG2rFRfYD4xg8y116z3tK1RRN8hebZ
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - Asset history of car asset:
[INFO] examples.usecases.track_and_trace - 3 entries
[INFO] examples.usecases.track_and_trace - [ { txId:
    '759af9b75274f48a788e76d8e4810260714eb699cedae13a67799aaaa6e9a86e',
  from: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  to: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  amount: 1,
  timestamp: 1602513864155 },
{ txId:
    '2e981959cfe5dc4e2d7cf262f29df7f5aca099887fbdb15c76988fe89ad7ee4a',
  from: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  to: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  amount: 1,
  timestamp: 1602513865523 },
{ txId:
    '058ae98cf13d595ce5349919ebca54002cada83d4ac31e3948c1696d2b86d0b5',
  from: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  to: [ '5JLRv9p1myDmJgWG2rFRfYD4xg8y116z3tK1RRN8hebZ' ],
  amount: 1,
    timestamp: 1602513866478 } ]
[INFO] examples.usecases.track_and_trace -
[INFO] examples.usecases.track_and_trace - Tx history of manufacturer:
[INFO] examples.usecases.track_and_trace - 2 entries
[INFO] examples.usecases.track_and_trace - [ { txId:
    '759af9b75274f48a788e76d8e4810260714eb699cedae13a67799aaaa6e9a86e',
  direction: 'create',
  from: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  to: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  amount: 1,
  assetType: 'sample_vehicle',
  timestamp: 1602513864155 },
{ txId:
    '2e981959cfe5dc4e2d7cf262f29df7f5aca099887fbdb15c76988fe89ad7ee4a',
  direction: 'out',
  from: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  to: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  amount: 1,
  assetType: 'sample_vehicle',
    timestamp: 1602513865523 } ]
[2020-10-12T14:44:27.403] [INFO] examples.usecases.track_and_trace - Tx history of alice:
[2020-10-12T14:44:27.403] [INFO] examples.usecases.track_and_trace - 2 entries
[2020-10-12T14:44:27.403] [INFO] examples.usecases.track_and_trace - [ { txId:
    '2e981959cfe5dc4e2d7cf262f29df7f5aca099887fbdb15c76988fe89ad7ee4a',
  direction: 'in',
  from: [ '72yRMDnRRtYuDFy4ebfF4G4kqAKh5Qd2ptp15rZ3aoms' ],
  to: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  amount: 1,
  assetType: 'sample_vehicle',
  timestamp: 1602513865523 },
{ txId:
    '058ae98cf13d595ce5349919ebca54002cada83d4ac31e3948c1696d2b86d0b5',
  direction: 'out',
  from: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  to: [ '5JLRv9p1myDmJgWG2rFRfYD4xg8y116z3tK1RRN8hebZ' ],
  amount: 1,
  assetType: 'sample_vehicle',
  timestamp: 1602513866478 } ]
[2020-10-12T14:44:27.488] [INFO] examples.usecases.track_and_trace - Tx history of bob:
[2020-10-12T14:44:27.489] [INFO] examples.usecases.track_and_trace - 1 entries
[2020-10-12T14:44:27.489] [INFO] examples.usecases.track_and_trace - [ { txId:
    '058ae98cf13d595ce5349919ebca54002cada83d4ac31e3948c1696d2b86d0b5',
  direction: 'in',
  from: [ '89A4gxxYDDzRkRTuBxJJNZJaGtYQhUDq1BfSwowSvXYW' ],
  to: [ '5JLRv9p1myDmJgWG2rFRfYD4xg8y116z3tK1RRN8hebZ' ],
  amount: 1,
  assetType: 'sample_vehicle',
    timestamp: 1602513866478 } ]

To understand the output, click here.

Functions

The section below describes the code contained in the sample application and SDK that has been cloned to your local development machine.

Create a digital asset

This composite function createDigitalAsset is used when the manufacturer creates the digital asset (the car):

const createTxResult = await digitalAssetDriver.createDigitalAsset(txContext, carAsset, amount, carAssetMetadata, manufacturer.signKp.publicKey, manufacturer.signKp.privateKey);

This function is a composite function; it contains a number of simpler functions that carry out a single action.

Here, the creation of the digital asset actually comprises three single functions:

  • composeAndSignCreateTx : creation of the data structure of the transaction and signing of the transaction by the owner of the asset
  • postSignedCreateTx : posting of the transaction to the server (blockchain)

Example:

const createDigitalAsset = async (txContext, asset, amount, txMetadata, ownerPublicKey, ownerPrivateKey) => {
const signedTx = driver.composeAndSignCreateTx(asset, outputs, txMetadata, ownerPublicKeys, ...ownerPrivateKeys);
const createDaResponse = awaitdigitalAssetApi.postSignedCreateTx(txContext, signedTx, ownerPublicKeys, ASSET_FORMAT);
return createDaResponse;

Transfer a digital asset

The function transferDigitalAsset is used when the manufacturer of the digital asset (the car) transfers ownership to Alice:

const transfer1TxResult = await digitalAssetDriver.transferDigitalAsset(txContext, createTransactionId, carAssetMetadata,
manufacturer.signKp.publicKey,manufacturer.signKp.privateKey,alice.signKp.publicKey);

Similar to createDigitalAsset, there are also three single functions:

  • composeAndSignCreateTx : creation of the data structure of the transaction and signing of the transaction by the owner of the asset
  • postSignedCreateTx : posting of the transaction to the server (blockchain)

Example:

const transferDigitalAsset = async(txContext, unspentTransactions, txMetadata, senderPublicKey, senderPrivateKey, outputs) => {
if (!Array.isArray(unspentTransactions))
unspentTransactions = [unspentTransactions];
letunspentTxs = awaitPromise.all(unspentTransactions.map(ut=>getUnspentTx(txContext, ut)));
constsignedTx = driver.composeAndSignTransferTx(unspentTxs, txMetadata, outputs, senderPrivateKey);
consttransferDaResponse = awaitdigitalAssetApi.postSignedTransferTx(txContext, signedTx, senderPublicKey, ASSET_FORMAT);
returntransferDaResponse;
};

In both composite functions, the creation of the data structure for the transaction, the signing of the transaction, and the posting of the transaction takes place on the client side.

Customize a composite function

Generally speaking, you can run the sample track_and_trace without modifying the code if all these functions take place on the client side.

However, a number of use cases may require the modification of the functions within.

As an example, your use case requires the signing of the transaction on the server when you create a digital asset.

Here, you can simply remove the function signedTx from the call. As well, replace the function postSignedCreateTx with postUnsignedCreateTx to send an unsigned transaction to the server:

const createDigitalAsset = async (txContext, asset, amount, txMetadata, ownerPublicKey, ownerPrivateKey) => {
const signedTx = driver.composeAndSignCreateTx(asset, outputs, txMetadata, ownerPublicKeys, ...ownerPrivateKeys);
const createDaResponse = awaitdigitalAssetApi.postSignedCreateTx(txContext, signedTx, ownerPublicKeys, ASSET_FORMAT);
return createDaResponse;

Next Steps

Run another sample application here.
Access the database to see a record of all the transactions in this sample. Find out more here.

Return to Sample Applications