Tutorials
No Results
Tutorial Image

Beginner · 15 minutes or less

Create an Asset using JavaScript

This tutorial demonstrates the steps involved in creating a basic Algorand Standard Asset (ASA). This tutorial can be completed on its own or can be done in conjunction with the follow-up tutorials: Asset Opt-In, Asset Transfer, Asset Freeze, Asset Revoke tutorials. Completing this tutorial will set you up for the subsequent four tutorials. Only two accounts are required to create an ASA in this tutorial, but we will need three accounts total for the subsequent tutorials.

Completed code for this tutorial can be found at the bottom of the page. A complete set of code for all ASA tutorials can be found here CreateNewAccounts.js and TutorialASA.js.

Requirements

Recommended sequence, if you are new to ASA:

Optional:

Background

Algorand Standard Assets (ASA) allow developers to create fungible and non-fungible assets with a few method calls. ASA’s are highly customizable with parameters that allow developers to define total issuance of an asset, name of asset, units of an asset, as well as access controls privileges over an asset.

There are a few items to be aware of before getting started with assets as documented in the ASA feature guide overview on the developer portal.

Also, see more information on decimals and fees.

Note: Copy off the AssetID , from this tutorial as it will be used in subsequent tutorials.

1. Instantiate Algod Wrapper

In this step, we are passing in the token, server, and port values from a local node or local sandbox instance. You can also connect to remote node using a third-party service.

const algosdk = require('algosdk');

const token = <"algod-token">;
const server = <"http://algod-address">;
const port = <algod-port>;

//instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);


Learn More
- Connect to an Algorand Node
- Algorand Node Setup

2. Recover, Define and Print Accounts

Hardcoding and recovering accounts in this way is not advised, for security purposes, but is sufficient for this tutorial.

Note: If you have not already done so, use this tutorial to Create Accounts

This tutorial will use TestNet accounts that have been pre-created from the Create Accounts tutorial. Be sure to dispense Algos to these accounts before continuing, using the TestNet Dispenser.

var account1_mnemonic = "indoor project long invite vehicle toy travel image leopard true alpha mix know exhaust curious giggle day biology parent coffee pigeon black lunch abandon inquiry";
var account2_mnemonic = "shoulder grunt system render critic possible fortune float season weapon luxury jar patient build wheat siege behind patrol churn liberty catalog tongue drift above bring";
var account3_mnemonic = "indoor project long invite vehicle toy travel image leopard true alpha mix know exhaust curious giggle day biology parent coffee pigeon black lunch abandon inquiry";

var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
var recoveredAccount3 = algosdk.mnemonicToSecretKey(account3_mnemonic);
console.log("Account One: " + recoveredAccount1.addr);
console.log("Account Two: " + recoveredAccount2.addr);
console.log("Account Three: " + recoveredAccount3.addr);


Learn More
- Algorand Standalone Account Creation Methods

3. Define Asset Create Transaction Parameters

Here we structure the changing blockchain parameters and include a utility function to update parameters from the blockchain. This will come in handy in the following tutorials where we will need to pass in these same parameters several times.

var cp = {
    fee: 0, 
    firstRound: 0,  
    lastRound: 0, 
    genID: "",
    genHash: ""    
}
var getChangingParms = async function( algodclient ) {
    let params = await algodclient.getTransactionParams();
    cp.firstRound = params.lastRound;
    cp.lastRound = cp.firstRound + parseInt(1000);
    let sfee = await algodclient.suggestedFee();
    cp.fee = sfee.fee;
    cp.genID = params.genesisID;
    cp.genHash = params.genesishashb64;
}

Create an async function and write all the logic in there.

(async() => {

    await getChangingParms(algodclient);
    let note = undefined;
    let addr = recoveredAccount1.addr;
    let defaultFrozen = false;
    let totalIssuance = 100;
    let unitName = "t-c"; 
    let assetName = "Tutorial-Coin";
    let assetURL = "http://someurl";
    let assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d";
    let manager = recoveredAccount2.addr;
    let reserve = recoveredAccount2.addr;
    let freeze = recoveredAccount2.addr;
    let clawback = recoveredAccount2.addr;

})().catch(e => {
    console.log(e);
    console.trace();
});


Learn More
- Algorand Asset Parameters
- Common Transaction Fields

4. Create ASA transaction object

Use this code to create an asset transaction.

    let txn = algosdk.makeAssetCreateTxn(addr, cp.fee, cp.firstRound, cp.lastRound, note,
            cp.genHash, cp.genID, totalIssuance, defaultFrozen, manager, reserve, freeze, clawback,
            unitName, assetName, assetURL, assetMetadataHash);

5. Sign Transaction

Sign the transaction.

    let rawSignedTxn = txn.signTxn(recoveredAccount1.sk)

6. Send Create ASA Transaction to the Blockchain and print the Tx ID

Broadcast the transaction to the Blockchain.

    let tx = (await algodclient.sendRawTransaction(rawSignedTxn));
        console.log("Asset Creation Txn : " + tx.txId);

7. Check the transaction on a block explorer

Once you’ve completed these steps you’re output should look like this:

Account One: WCQNTSIKNAYRWYQBJBRWUG7QEBLSNQRKEQI7FDYKAIHG555ZZ5FGNNIUJY
Account Two: CYY47X6CZNO2HY4VCW5QLLIZL4UN7IZP6NALUQFRZKO7MCZ2YSZPSS5HZQ
Account Three: WCQNTSIKNAYRWYQBJBRWUG7QEBLSNQRKEQI7FDYKAIHG555ZZ5FGNNIUJY
Asset Creation Txn : LISSHM5YU2EU6OERZJTJWYTVKJZ22MK4AG4SYMGCOTWZO4VHARFA

You can check the asset creation transaction on a block explorer for reference.

Note: Copy off the AssetID , as it will be used in subsequent tutorials.


Learn More
- Algorand Block Explorers

8. Complete Example

Here is the completed code to Create an Asset.

const algosdk = require('algosdk');


// Retrieve the token, server and port values for your installation in the 
// algod.net and algod.token files within the data directory

// UPDATE THESE VALUES
// const token = "TOKEN";
// const server = "SERVER";
// const port = PORT;

// sandbox
const token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const server = "http://localhost";
const port = 4001;

// Structure for changing blockchain params
var cp = {
    fee: 0,
    firstRound: 0,
    lastRound: 0,
    genID: "",
    genHash: ""
}
// Utility function to update params from blockchain
var getChangingParms = async function (algodclient) {
    let params = await algodclient.getTransactionParams();
    cp.firstRound = params.lastRound;
    cp.lastRound = cp.firstRound + parseInt(1000);
    let sfee = await algodclient.suggestedFee();
    cp.fee = sfee.fee;
    cp.genID = params.genesisID;
    cp.genHash = params.genesishashb64;
}

// Function used to wait for a tx confirmation
const waitForConfirmation = async function (algodclient, txId) {
let lastround = (await algodclient.status()).lastRound;
  while (true) {
    const pendingInfo = await algodclient.pendingTransactionInformation(txId);
    if (pendingInfo.round !== null && pendingInfo.round > 0) {
      //Got the completed Transaction
      console.log("Transaction " + pendingInfo.tx + " confirmed in round " + pendingInfo.round);
      break;
    }
    lastround++;
    await algodclient.statusAfterBlock(lastround);
  }
};


// Recover accounts
// paste in mnemonic phrases here for each account

// var account1_mnemonic = "PASTE your phrase for account 1";
// var account2_mnemonic = "PASTE your phrase for account 2";
// var account3_mnemonic = "PASTE your phrase for account 3"

var account1_mnemonic = "portion never forward pill lunch organ biology" +
    " weird catch curve isolate plug innocent skin grunt" +
    " bounce clown mercy hole eagle soul chunk type absorb trim";
var account2_mnemonic = "place blouse sad pigeon wing warrior wild script" +
    " problem team blouse camp soldier breeze twist mother" +
    " vanish public glass code arrow execute convince ability" +
    " there";
var account3_mnemonic = "image travel claw climb bottom spot path roast" +
    " century also task cherry address curious save item" +
    " clean theme amateur loyal apart hybrid steak about blanket"


var recoveredAccount1 = algosdk.mnemonicToSecretKey(account1_mnemonic);
var recoveredAccount2 = algosdk.mnemonicToSecretKey(account2_mnemonic);
var recoveredAccount3 = algosdk.mnemonicToSecretKey(account3_mnemonic);
console.log(recoveredAccount1.addr);
console.log(recoveredAccount2.addr);
console.log(recoveredAccount3.addr);

// Instantiate the algod wrapper
let algodclient = new algosdk.Algod(token, server, port);

// Debug Console should look similar to this

// THQHGD4HEESOPSJJYYF34MWKOI57HXBX4XR63EPBKCWPOJG5KUPDJ7QJCM  
// AJNNFQN7DSR7QEY766V7JDG35OPM53ZSNF7CU264AWOOUGSZBMLMSKCRIU   
// 3ZQ3SHCYIKSGK7MTZ7PE7S6EDOFWLKDQ6RYYVMT7OHNQ4UJ774LE52AQCU   


(async () => {
    // Asset Creation:
    // The first transaciton is to create a new asset
    // Get last round and suggested tx fee
    // We use these to get the latest round and tx fees
    // These parameters will be required before every 
    // Transaction
    // We will account for changing transaction parameters
    // before every transaction in this example
    await getChangingParms(algodclient);
    let note = undefined; // arbitrary data to be stored in the transaction; here, none is stored

    // Asset creation specific parameters
    // The following parameters are asset specific
    // Throughout the example these will be re-used. 
    // We will also change the manager later in the example
    let addr = recoveredAccount1.addr;
    // Whether user accounts will need to be unfrozen before transacting    
    let defaultFrozen = false;
    // integer number of decimals for asset unit calculation
    let decimals = 0;
    // total number of this asset available for circulation   
    let totalIssuance = 1000;
    // Used to display asset units to user    
    let unitName = "LATINUM";
    // Friendly name of the asset    
    let assetName = "latinum";
    // Optional string pointing to a URL relating to the asset
    let assetURL = "http://someurl";
    // Optional hash commitment of some sort relating to the asset. 32 character length.
    let assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d";
    // The following parameters are the only ones
    // that can be changed, and they have to be changed
    // by the current manager
    // Specified address can change reserve, freeze, clawback, and manager
    let manager = recoveredAccount2.addr;
    // Specified address is considered the asset reserve
    // (it has no special privileges, this is only informational)
    let reserve = recoveredAccount2.addr;
    // Specified address can freeze or unfreeze user asset holdings 
    let freeze = recoveredAccount2.addr;
    // Specified address can revoke user asset holdings and send 
    // them to other addresses    
    let clawback = recoveredAccount2.addr;
    // signing and sending "txn" allows "addr" to create an asset
    let txn = algosdk.makeAssetCreateTxn(addr, cp.fee, cp.firstRound, cp.lastRound, note,
        cp.genHash, cp.genID, totalIssuance, decimals, defaultFrozen, manager, reserve, freeze,
        clawback, unitName, assetName, assetURL, assetMetadataHash);

    let rawSignedTxn = txn.signTxn(recoveredAccount1.sk)
    let tx = (await algodclient.sendRawTransaction(rawSignedTxn));
    console.log("Transaction : " + tx.txId);
    let assetID = null;
    // wait for transaction to be confirmed
    await waitForConfirmation(algodclient, tx.txId);
    // Get the new asset's information from the creator account
    let ptx = await algodclient.pendingTransactionInformation(tx.txId);
    assetID = ptx.txresults.createdasset;
    console.log("AssetID = " + assetID);
    //your terminal output should ber similar to this
    // Transaction: RXSAJUYVPDWUF4XNGA2VYQX3NUVT5YJEZZ5SJXIIASZK5M55LVVQ
    // Transaction RXSAJUYVPDWUF4XNGA2VYQX3NUVT5YJEZZ5SJXIIASZK5M55LVVQ confirmed in round 4272786
    // AssetID = 149657

})().catch(e => {
    console.log(e);
    console.trace();
});

Note: Copy off the AssetID , as it will be used in subsequent tutorials.

assets

javascript

create assets

April 12, 2020