Tutorial

Issuing an Asset

The previous two examples covered the DefineAsset operation, an operation that registers assets with the Findora Ledger. This example will cover the IssueAsset operation. Asset issuers can use the IssueAsset operation to mint units of an asset that they have created. Concretely, the IssueAsset operation creates asset records that represent ownership by a public key of a certain amount of an asset. These asset records are stored in a structure called a transaction output (TXO).

After accepting a transaction, the ledger assign each TXO to a transaction output sequence identifier (TXOSID). The Findora Ledger can provide a cryptographic proof that a TXO with certain TXOSID exists on the ledger, just like it can provide a proof that a transaction with a certain TXNSID exists on the ledger.

Before being able to issue an asset, Alice must create an issuance key and define an asset. Refer to the Defining an Asset: Transaction Submission and Using a Keystore tutorials for more details.


const PASSWORD = 'findorarocks123';
const keyStore = new KeyStore.KeyStore(PASSWORD);
const masterKey = keyStore.genMasterKey(PASSWORD);
const aliceKeyPair = keyStore.genKeyPair(masterKey, 'Alice');
const network = new Network.Network(PROTOCOL, HOST, QUERY_PORT, SUBMISSION_PORT, LEDGER_PORT);

console.log('Key for Alice created.');

const tokenCode = Ledger.random_asset_type();
const memo = 'this is a test asset';
const assetRules = Ledger.AssetRules.new();
let blockCount = BigInt((await network.getStateCommitment())[1]);
const definitionTransaction = Ledger.TransactionBuilder
  .new(blockCount).add_operation_create_asset(aliceKeyPair, memo, tokenCode, assetRules).transaction();

await network.submitTransaction(definitionTransaction);

console.log('Asset created.');

await Utils.sleep(4);
blockCount = BigInt((await network.getStateCommitment())[1]);
const zeiParams = Ledger.PublicParams.new(); // Cryptography public parameters necessary for creating asset records
const seqID = BigInt(await network.getIssuanceNum(tokenCode)); // To prevent operation replays, each ```IssueAsset``` operation must include a unique and increasing issuance number.
const amount = BigInt(5); // Amount of the asset to issue.
const confidential = false; // Whether the amount field of the asset record should be encrypted. Advanced features like confidentiality will be covered in a later example.

The IssueAsset operation below will, if accepted by the ledger, create a new asset record owned by Alice with 5 units of the asset she has just created. It is important to note that asset issuers can only issue assets to themselves (the next example covers asset transfers).

console.log('Creating issuance transaction...');
const issueTxn = Ledger.TransactionBuilder.new(blockCount)
  .add_basic_issue_asset(aliceKeyPair, tokenCode, seqID, amount, confidential, zeiParams).transaction();

Alice will now attempt to submit her transaction.

console.log('Submitting transaction...');
const handle = await network.submitTransaction(issueTxn);
console.log(`Transaction submitted successfully! The transaction handle is ${handle}.`);

console.log('Getting transaction status...');
await Utils.sleep(5);
const transactionStatus = await network.getTxnStatus(handle);
console.log(transactionStatus);

Alice can also ask the query server about assets she has issued.

const base64PubKey = Ledger.public_key_to_base64(aliceKeyPair.get_pk());
await Utils.sleep(2);
console.log('Fetching assets issued by Alice...');
const aliceAssets = await network.getIssuedRecords(base64PubKey);
console.log(aliceAssets);
console.log(`Assets issued by Alice: ${aliceAssets}`);

Alice can also fetch the list of TXOSIDS corresponding to asset records that she owns.

const aliceTxoSids = await network.getOwnedSids(base64PubKey);
assert(aliceTxoSids.length == 1);

const sid = aliceTxoSids[0];
console.log(sid);

Recall that at the beginning of the example, we mentioned that it is possible to ask the ledger to prove that a supposed TXO is valid. Alice can authenticate the TXO she just issued against the ledger state commitment.

const stateCommitment = (await network.getStateCommitment())[0];
console.log(stateCommitment);
const authenticatedTxoJson = await network.getUtxo(sid);
console.log(authenticatedTxoJson);
const authenticatedTxo = Ledger.AuthenticatedAssetRecord.from_json_record(authenticatedTxoJson);
console.log('Authenticating the transaction that Alice just submitted...');

Alice can now verify that ledger has returned a valid proof that the txo she owns exists at the position stored by the variable sid. isValid will be true if the authentication proofs successfuly pass. The authentication proofs will only pass if the candidate TXO is unspent and is a valid part of the ledger history.

const isValid = authenticatedTxo
  .is_valid(JSON.stringify(stateCommitment));

assert(isValid);

console.log('TXO authenticated!');