Aptos Tutorial Episode 0: Baseline

|
by: Wayne Culbreth

I’ve been digging into the Aptos world since their funding announcement last week. I’m learning the platform from a “zero knowledge” baseline (see what I did there??? ain’t no bad joke like a dad joke). As I find my way through how to build on the platform, I’m going to document those learnings here.

Before I jump into the meat of the content, I wanted to do this intro lesson as a coda to the tutorials on atpos.dev. For the rest of these posts, I’m going to assume you have read and somewhat understand the tutorials there, as I don’t intend on rehashing what they have already covered. I do want to highlight a few things and start with some code that will make life much easier, though.

By the way, this will all be in Typescript/Rust/Move - but the focus will be on Move. The repo is here. I’m working in VS Code - so I’ll have some specific recommendations there. First off is a Move plugin. There are a handful available. I’ve been using move-analyzer which has been helpful with syntax coloring.

If you’ve completed the initial coding tutorials, you have already experienced the pain of a lack of a command line tool for simple setup like creating and funding accounts. I must have copied/pasted Alice’s address 100x playing around with the tutorial code before actually breaking down and coding some utility helpers.

To start, I’ve taken first_transaction.ts from the tutorial and turned it into utility.ts and added some capability (which I’ll shortly submit as a PR to the aptos repo). The first thing I added was the ability to save/load the accounts to a file:

  saveAccount(path: string) {
    // saving as a string to make file human readable
    writeFileSync(path, this.signingKey.secretKey.toString());
  }

  loadAccount(path: string): SignKeyPair {
    // readable file incurs more work to load back to keypair
    const content = readFileSync(path).toString();
    const keyArray = Uint8Array.from(
      content.split(",").map((value) => {
        return parseInt(value);
      })
    );
    return sign.keyPair.fromSecretKey(Buffer.from(keyArray));
  }

All of the data in the Account is built from the private key of the key pair. So we are saving that private key to a file. I sort of took the long way around so that the file would be human readable. Even though we’re operating on devnet that resets every week - you still want to practice good security with private key files. Never put them in a repo, etc - standard disclaimers apply.

With that capability, I’ve also overloaded the ‘constructor’ of Account so we can instantiate an Account object from a saved key file:

constructor(path: string = "", seed?: Uint8Array | undefined) {
    if (seed) {
      this.signingKey = sign.keyPair.fromSeed(seed);
    } else if (path) {
      this.signingKey = this.loadAccount(path);
    } else {
      this.signingKey = sign.keyPair();
    }
  }

This is going to save you tons of time - as you’ve already learned if you tried to extend the tutorial code to do other things. Putting those capabilities to use - we can create some simple initialization code to setup our accounts to run:

  const restClient = new RestClient();
  const faucetClient = new FaucetClient(restClient);

  const alice = new Account();
  alice.saveAccount("./.secrets/alice.key");
  await faucetClient.fundAccount(alice.pubKey(), 10_000_000);

So now we’ve got Alice with her own account, saved, and funded. We can run that once, and then next time we want to use that account we can just reload it:

  const restClient = new RestClient();

  const alice = new Account("./.secrets/alice.key");
  console.log(`Alice: ${await
    restClient.accountBalance(alice.address())}`);

We’ve got Alice’s account back and can take a peek at her current balance. In the repo - I’ve got three accounts setup for init/load that we’ll be using the actual tutorials (this post was more “tips” to get started). We’ve going to stick with Alice and Bob, but they are going to buy some concert tickets from a venue and then trade/buy/sell them with each other. We’ll start hitting some fundamental principles of building in Move/Aptos in the next entry.

I did a few other minor things in utility.ts - deconstructed the imports and moved ‘publishModule’ into the utility. Feel free to ask question in the repo discussion. And certainly feel free to challenge my thinking. This is 100% new to me and I’m “learning in public.”