Tutorials
No Results
Tutorial

Intermediate · 30 minutes

Algorand Builder Tutorial: Part 1 - Creating Local Network and Deploying ASA

In this tutorial series we will outline the features of Algorand Builder.

The main tool, algob provides an opinionated framework to manage Algorand apps with functionality to create and deploy assets and smart contracts, manage accounts and network configuration, organize projects. The recently released algob v0.3, stabilizes the API for creating and deploying ASA and ASC.

Requirements

  • Node v14+
  • yarn or npm
  • Algorand Node installed (optional, otherwise docker and Sandbox instance is required)
  • algob installed (check instructions)
  • make
  • git

Background

Algorand Builder fills a gap in the Algorand ecosystem to create and manage projects. Our goal is to make shipping Algorand applications simple, efficient, and scalable. Check our articles in the developer portal.

In this tutorial we will present how to create a reproducible private net, deploy ASA and create ASA transactions.

Steps

Step 1: Algorand Node Setup

This step is optional. We recommend doing it, to reproduce the same test account setup.

We start with setting up an Algorand Node. You can use Sandbox, but here we will show you how you can use our infrastructure scripts. Firstly make sure you have an algorand node installed and available in your PATH:

% algod -v
8590131200
2.3.0.stable [rel/stable] (commit #07bc97b7)

If the node is installed, but the algod command is not accessible, then search how to add a binary / executable to your OS PATH.

Next we clone our repository. If you installed algob from source, then you can skip this step and just go to the repository root.

git clone https://github.com/scale-it/algorand-builder.git

Go to infrastructure directory and call make:

cd infrastructure
make create-private-net start-private-net
make setup-master-account

The first command will setup the private algorand network with one node and run it. The second command will create a master account and fund it with lot of Algos. The master account is the main account we will use in all our tutorials. If you are using different configuration (eg Sandbox) then in all steps below you will need to use different master account. Let’s verify if everything works:

% make status-private-net
goal network status -r ./node_data

[PrimaryNode]
Last committed block: 69
Time since last block: 1.6s
Sync Time: 0.0s
...

% goal account list -d ./node_data/PrimaryNode
[online]    IXX4X3NNZXMAN3YCX64XR2KFORFDDDKJIVUKSEVT5L37IJAL2PIZXJFJLM  IXX4X3NNZXMAN3YCX64XR2KFORFDDDKJIVUKSEVT5L37IJAL2PIZXJFJLM  9998019995998998 microAlgos
[offline]   Unnamed-0   WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE  2000004000000 microAlgos    *Default

WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE is our master account. If you use different account, then don’t forget to update the file in the next step by setting right account parameters. You can do it by setting memo, private key or even connect to KDM. You can find details in the config documentation linked in the step below.

Step 2: create an algob project

If you installed algob correctly, you should be able to run algob --version. If not, then go back and inspect your installation.

Let’s create a new project:

% algob init algob-part1-asa
% cd algob-part1-asa

Now we need to add @algorand-builder/algob as a dependency (you can use npm instead of yarn).

# If you installed from npm:
yarn add @algorand-builder/algob

# otherwise, if you installed from souce and linked algob
yarn link @algorand-builder/algob

Now our project has an access to @algorand-builder libraries. The generate project is pre-configured to use the credentials of the private network created in step1. If you use different network, then open the algob.config.js file and update network object:

let defaultCfg = {
  host: "http://localhost",
  port: 8080,
  token: "aade468d25a7aa48fec8082d6a847c48492066a2741f3731e613fdde086cd6e9",
  accounts: accounts,
};

The accounts attribute should contain a master account, which will be used later in the tutorial to activate other accounts and pay transaction fees.

Tip

If you don’t use the same node setup as described in Step 1, you must update the master account to an account with ALGO you control. You can do it by setting private key, memo or connecting to KMD. Please read our config documentation for more details about algob configuration, options to set accounts and configure networks.

Let’s verify that it’s wired up correctly:

% algob node-info
NETWORK NAME default
NODE ADDRESS {
  host: 'http://localhost',
  port: 8080,
  token: 'aade468d25a7aa48fec8082d6a847c48492066a2741f3731e613fdde086cd6e9',
  accounts: [
    {
      name: 'master',
      addr: 'WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE',
      sk: [Uint8Array]
    }
  ]
}
NODE STATUS {
  ...
}

Step 3: inspect project structure

The generated project has the following structure:

├── algob.config.js
├── assets
│   ├── accounts_user.yaml
│   ├── asa.yaml
│   └── fee-check.teal
├── node_modules
│   └── ...
├── package.json
├── README.md
├── scripts
│   ├── 0-sampleScript.js
│   └── 1-sampleScript.js
└── tests

algob.config.js is a place where we store node access information (network), accounts and other settings. The assets directory is used to store smart contracts, accounts (optionally) and smart contract code. scripts is where we put all code related to transactions and deployment.

Step 4: Create Gold ASA

Open the assets/asa.yaml file. It contains definition of sample ASA: minimumASA and allFieldASA. Each ASA is a map of all possible ASA parameters. The allFieldASA is an example with list of all possible parameters.

Let’s define our own ASA. Delete the content of the file and fill it with the following content:

gold:
  total: 5912599999515
  decimals: 0
  defaultFrozen: false
  unitName: "GLD"
  url: "url"
  # User may get "signature validation failed" from node if shorter hash is used.
  metadataHash: "12312442142141241244444411111133"
  note: "note"
  noteb64: "noteb64"
  manager: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  reserve: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  freeze: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  clawback: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  optInAccNames: ["john"]
tesla:
  total: 300000
  decimals: 0
  defaultFrozen: false
  unitName: "TSLA"
  url: "url"
  # User may get "signature validation failed" from node if shorter hash is used.
  metadataHash: "12312442142141241244444411111133"
  note: "note"
  noteb64: "noteb64"
  manager: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  reserve: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  freeze: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"
  clawback: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE"

This contains definition of two assets: gold and tesla. It’s worth to note the optInAccNames attribute - it contains a list of account names (as defined in the algob.config.js) which will be automatically opted-in when the ASA will be deployed.

Step 4: add accounts to the config

Open the algob.config.js file. Find the accounts variable definition and update it to:

let accounts = mkAccounts([
  {
    // This account is created using `make setup-master-account` command from our
    // `/infrastructure` directory.
    // If you want to use different account then change it to other address you control.
    // To export a mnemonic you may use the following command:
    // goal account export -a "your_account_address" -d $ALGORAND_DATA
    name: "master-account",
    addr: "WWYNX3TKQYVEREVSW6QQP3SXSFOCE3SKUSEIVJ7YAGUPEACNI5UGI4DZCE",
    mnemonic: "enforce drive foster uniform cradle tired win arrow wasp melt cattle chronic sport dinosaur announce shell correct shed amused dismiss mother jazz task above hospital"
  },
  // These are generated account, we will fund them later in this tutorial using algob
  {
    name: "elon-musk",
    addr: "WHVQXVVCQAD7WX3HHFKNVUL3MOANX3BYXXMEEJEJWOZNRXJNTN7LTNPSTY",
    mnemonic: "resist derive table space jealous person pink ankle hint venture manual spawn move harbor flip cigar copy throw swap night series hybrid chest absent art"
  }, {
    name: "john",
    addr: "2UBZKFR6RCZL7R24ZG327VKPTPJUPFM6WTG7PJG2ZJLU234F5RGXFLTAKA",
    mnemonic: "found empower message suit siege arrive dad reform museum cake evoke broom comfort fluid flower wheat gasp baby auction tuna sick case camera about flip"
  }
]);

If you run again algob node-info you should see the new accounts in the output.

Step 5: create a deployment script

All scripts are stored in the scripts directory. Remove files from scripts, and create a new one: scripts/0-gold.js with the following content:

const { executeTransaction, balanceOf } = require('@algorand-builder/algob');

// a helper function used to create fund transaction
function mkParam(senderAccount, receiverAddr, amount, payFlags) {
  return {
    type: TransactionType.TransferAlgo,
    sign: SignType.SecretKey,
    fromAccount: senderAccount,
    toAccountAddr: receiverAddr,
    amountMicroAlgos: amount,
    payFlags: payFlags
  };
};


// This is an entry function in our script (a default, exported function)
async function run (runtimeEnv, deployer) {
  console.log('[gold]: Script has started execution!');

  // we start with extracting acocunt objects from the config.
  const masterAccount = deployer.accountsByName.get('master-account');
  const goldOwner = deployer.accountsByName.get('alice');
  const john = deployer.accountsByName.get('john');
  const bob = deployer.accountsByName.get('bob');

  // Accounts can only be active if they poses minimum amont of ALGOs.
  // Here we fund the accounts with 5e6, 5e6 and 1e6 AlGOs.
  const message = 'funding account';
  const promises = [
    executeTransaction(deployer, mkParam(masterAccount, goldOwner.addr, 5e6, { note: message })),
    executeTransaction(deployer, mkParam(masterAccount, john.addr, 5e6, { note: message })),
    executeTransaction(deployer, mkParam(masterAccount, bob.addr, 1e6, { note: message }))];
  await Promise.all(promises);


  // Let's deploy ASA. The following commnad will open the `assets/asa.yaml` file and search for
  // the `gold` ASA. The transaction can specify standard transaction parameters. If skipped
  // node suggested values will be used.
  const asaInfo = await deployer.deployASA('gold', {
    creator: goldOwner
    // totalFee: 1001,
    // feePerByte: 100,
    // firstValid: 10,
    // validRounds: 1002
  });
  console.log(asaInfo);

  // In asa.yaml we only added `john` to opt-in accounts. Let's add `bob` as well using the
  // script;
  await deployer.optInToASA('gold', 'bob', {});

  // to interact with an asset we need asset ID. We can get it from the returned object:
  const assetID = asaInfo.assetIndex;

  // we can inspect the balance of the goldOnwer. It should equal to the `total` value defined
  // in the asa.yaml.
  await balanceOf(deployer, goldOwner.addr, assetID);

  console.log('[gold]: Script execution has finished!');
}

module.exports = { default: run };

The script above defines run function - it is set as a default, exported function from that module. algob will run the default function and pass runtime information and deployer into it’s argument. The deployer is an object which provides Algodv2 client (algosdk-js algorand driver instance), and lot of useful functions to deploy and manage assets as well as running transactions. You can read about algob deployer here. You can inspect all types provided by algob at our API types documentation

Firstly we query accounts defined in our config file. Then we transfer some ALGOs to fund and activate that accounts. Finally we deploy gold and opt-in john to gold.

We can run the script with:

algob deploy scripts/0-gold.js

In the output you will see transactions and additional information requested in the script. This command will create artifacts directory. There are 2 important files created:

  • artifacts/scripts/0-gold.js..log - contains a transaction log of all transaction run by deployer. This file is useful in the future to inspect transactions.
  • artifacts/scripts/0-gold.js.cp.yaml - a deployer checkpoint. It contains a lit of assets and smart contract deployed. Moreover, this file is used to protect a deployment script to be run twice in the same network. Let’s check! If we run algob deploy scripts/0-gold.js for the second time we will see:

    ```
    Skipping: Checkpoint exists for script scripts/0-gold.js

    ```

Read more about checkpoint concept here.

Step 6: create a script to transfer ASA

Create a subdirectory in scripts:

mkdir scripts/transfer

And create a scripts/transfer/gold-to-john.js file with the following content:

const { executeTransaction, balanceOf, TransactionType, SignType } = require('@algorand-builder/algob');

async function run (runtimeEnv, deployer) {
  // query gold ASA from deployer (using checkpoint information),
  const goldAsset = deployer.asa.get('gold')
  if (goldAsset) {
    console.error("Gold was not deployed. You must run `algob deploy` first.")
    return
  }

  const goldAssetID = goldAsset.assetIndex;

  // query accounts from config
  const john = deployer.accountsByName.get('john');
  const goldOwner = deployer.accountsByName.get('alice');

  // execute asset transfer transaction
  await executeTransaction(deployer, {
    type: TransactionType.TransferAsset,
    sign: SignType.SecretKey,
    fromAccount: goldOwner,
    toAccountAddr: john.addr,
    amount: 1,
    assetID: goldAssetID,
    payFlags: {}
  });

  await balanceOf(deployer, john.addr, goldAssetID);
}

module.exports = { default: run };

Similarly to scripts/0-gold.js, this file exports one default function. This function, however, will not be run using algob deploy. Instead, we will use algob run:

algob run scripts/transfer/gold-to-john.js

The main difference between run and deploy is that: * run doesn’t create checkpoints * run provides a limited version of deployer. It’s stripped from deployment functionality, and can only run standard transactions and query deployed objects. * run is used for auxiliary transaction (which can be run multiple times), deploy is used for deployment (things which should be run only once per network).

You can read more about two deployer modes (run and deploy) at Deployer Specification.

Summary

In this tutorial we created and deployed gold ASA, we show how we can access and manage basic accounts and used the deployer object in a separate script to load deployed ASA object and create an asset transfer transaction.

Full source code is available in the scale-it/algorand-builder-tutorial repository (branch: part-1).

Algob supports much more: you can load accounts from KMD or ENV variables, you can run a REPL, generate accounts, compile smart contracts and execute tests. In next episodes we will discover more algob features.

We would like to encourage you to read our documentation and share a feedback using GitHub issues.

algorand standard assets

standalone accounts

asa

privatenetwork

private network

January 28, 2021