# AleoJS Developer Guide
## Introduction
AleoJS is a powerful and lightweight library designed for seamless interaction with the Aleo blockchain and its diverse ecosystem. Drawing inspiration from the [zk-gaming-toolkit](https://github.com/kryha/zk-gaming-toolkit), Aleo.js fully harnesses existing tools while offering a user-friendly interface for developers keen on building atop the Aleo blockchain.
## Installation
Before beginning, make sure you have the following set up:
**1. Rust**: [Installation Guide](https://www.rust-lang.org/tools/install)
**2. SnarkOS**: [Installation Guide](https://github.com/aleoHQ/snarkos)
> In case there are some issues with build try from [here](https://github.com/eqlabs/snarkOS/tree/fix/compile)
**3. Leo language**:
[Installation Guide](https://github.com/aleoHQ/leo)
### From NPM
Install Aleo.js globally using npm:
```npm install -g @aleojs/cli@latest```
### From Source
1. Clone the Aleo.js repository:
```bash
# Download the source file
git clone https://github.com/venture23-zkp/aleojs
cd aleojs
# Build the project
npm run build
# Install aleojs
npm run install:cli
```
## Usage
To use AleoJS, in your terminal, run:
```bash
aleojs-cli-dev
```
The expected output is as following:
```bash _ _ _ ____
/ \ | | ___ ___ | / ___|
/ _ \ | |/ _ \/ _ \ _ | \___ \
/ ___ \| | __/ (_) | |_| |___) |
/_/ \_\_|\___|\___/ \___/|____/
Usage: aleojs-cli-dev [options] [command]
AleoJS CLI
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
init [options] <project-name> Initialize your AleoJS project
add <program-name> Add a new component or resource
compile Compile your AleoJS project
unflatten Create leo build for programs
autogen Generate ts types for contracts - use only after the build has been generated
start [options] <node> Run your AleoJS project
run [options] <file> Run file
deploy [options] <program-name> Deploy program
execute <file-path> Execute script
help [command] display help for command
```
### Initialize a New Project
Initialize a new project by giving the name of the project.
```
aleojs-cli-dev init <PROJECT_NAME>
```
Let's create a new project called `token`.
> This will internally install the dependencies for the project.
After project initialization, AleoJS generates the following directory structure:
```
├── contract
│ └── base-contract.ts
├── node_modules/
├── programs
│ ├── sample_program.leo
│ └── token.leo
├── scripts
│ └── deploy.ts
├── test
│ ├── sample_program.test.ts
│ └── token.test.ts
├── .env
├── .gitignore
├── aleo-config.js
├── babel.config.json
├── jest.config.json
├── package-lock.json
├── package.json
├── README.md
├── node_modules/
└── tsconfig.json
```
After initializing a projects, it will create following directories:
* contract: This directory contains a single file - `base-contract.ts`, a class containing common method and config for aleo programs in js.
* programs: This directory is made to hold all the leo programs. [`token.leo`](https://github.com/AleoHQ/workshop/blob/master/token/src/main.leo) file is created during the initialization along with `sample_program.leo`
* scripts: This directory is made to hold specific tasks and user scripts.
* test: This directory is made to hold all the tests.
* `aleo-config.js` -> This is a configuration file consisting of private key, method to execute on chain or dry run and different networks.
Let's explore `aleo-config.js`.
```js
import dotenv from 'dotenv';
dotenv.config();
export default {
accounts: [process.env.ALEO_PRIVATE_KEY],
mode: 'execute',
mainnet: {},
networks: {
testnet3: {
endpoint: 'http://localhost:3030',
accounts: [process.env.ALEO_PRIVATE_KEY_TESTNET3],
priorityFee: 0.01
},
mainnet: {
endpoint: 'https://api.explorer.aleo.org/v1',
accounts: [process.env.ALEO_PRIVATE_KEY_MAINNET],
priorityFee: 0.001
}
},
defaultNetwork: 'testnet3'
};
```
We have two modes of execution supported:
1. `execute`: In this mode, proof is generated and broadcasted on chain. Internally, it calls `snarkos developer execute` command.
2. `evaluate`: In this mode, no proof is generated and broadcasted on chain. Internally, it calls `leo run` command.
> `aleo-config` acts as a default configuation for the entire project. It can be overwritten on per program basis as well.
### Adding / Modifying a Program
To add a new program create a new file inside the `programs/` directory.
To modify the existing file, simply modify the existing file.
### Compliation
To compile the project, run:
```
aleojs-cli-dev compile
```
This will create the `artifacts` folder. The artifacts folder has the two main directories:
* leo - This directory contains the Leo packages. For each program in `programs` directory, a corresponding Leo package is created. The leo code from `programs` is copied to the `src/main.leo` file and is then compiled. If the compilation for all the programs are successful, the generated `.aleo` files are parsed to generate Leo and JS types which are inside the js directory.
* js - This directory contains the both Leo types, JS types, `js2leo` (Leo type to Js type conversion), `leo2js` (JS type to Leo type conversion). For each of the program, it also creates <PROGRAM-NAME>.ts file that contains all the transitions and mappings of the program.
```
├── js
│ ├── js2leo
│ │ ├── index.ts
│ │ └── token.ts
│ ├── leo2js
│ │ ├── index.ts
│ │ └── token.ts
│ └── types
│ ├── index.ts
│ └── token.ts
│ ├── sample_program.ts
│ ├── token.ts
└── leo
├── sample_program
│ ├── README.md
│ ├── build
│ ├── inputs
│ ├── leo.lock
│ ├── outputs
│ ├── program.json
│ └── src
└── token
├── README.md
├── build
├── inputs
├── leo.lock
├── outputs
├── program.json
└── src
```
> Since, `sample_program` did not have any types, there is no need for js2leo, leo2js or type file.
### Running Tests
After the successful compilation, tests can be written based on the files generated after compilation.
A sample test file is created for both the `sample_program` and `token` program. Run all the tests with:
```
npm run test
```
If you want to test a particular test file:
```
npm run test -- sample_program.test.ts
```
> Pro Tip: You don't need to enter the full test file name. You can use part of the name of the file and the tests that matches the entered name will run.
> Example: `npm run test -- sample`
## Conclustion
This documentation provides a comprehensive guide to installing Aleo.js, starting a project, adding programs, compiling, running tests, and deploying programs. Happy coding with Aleo.js!
--------------
## Advanced Testing (WIP)
Create a test file (e.g., token.test.ts) inside the test directory. An example test file is provided below:
```js
import { TokenContract } from '../artifacts/js/token';
// mode is explicitly defined here, execute mode is given as value to execute the transactions in chain. If mode is not given, default of aleo-config.js is used.
const Token = new TokenContract({mode: "execute"});
// for execution of Token program through different wallet
const Token_from_aleoUser3 = new TokenContract({mode: "execute", networkName: "testnet3", privateKey: "APrivateKey1zkp2GUmKbVsuc1NSj28pa1WTQuZaK5f1DQJAT6vPcHyWokG"});
describe("Token Testing", () => {
let tx;
// // User address on Aleo
const aleoUser1 = "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px";
const aleoUser2 = "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t";
const aleoUser3 = "aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg"
const Timeout = 20000_000;
test("should deploy", async() => {
// program deployment
tx = await Token.deploy();
// @ts-ignore
// transaction takes time to broadcast so we have to wait until transaction is completed
await tx.wait();
}, Timeout);
test("should mint publicly", async () => {
// minting publicly to aleuouser2 wallet
tx = Token.mint_public(aleoUser2, BigInt(500));
await tx.wait();
// checking balance of aleouser2 to see token has minted or not
expect(Token.account(aleoUser2)).toBe(BigInt(500));
}, Timeout);
test("should not transfer publicly if account has not balance", async() => {
// executing transfer public
tx = await Token_from_aleoUser3.transfer_public(aleoUser2, BigInt(500));
const receipt = tx.wait();
// expecting the transaction will fail. In this case transaction is said to be failed in finalize block so failed transaction will be broadcasted which we expect
expect(receipt.error).toBeTruthy();
}, Timeout);
test("should transfer publicly", async() => {
// minting for balance
tx = Token.mint_public(aleoUser1, BigInt(500));
await tx.wait();
// transfer public
tx = await Token.transfer_public(aleoUser1, BigInt(250));
await tx.wait();
expect(Token.account(aleoUser3)).toBe(BigInt(250));
expect(Token.account(aleoUser1)).toBe(BigInt(250));
}, Timeout);
});
```
**Execute the test file:**
> npm test -- --runInBand token.test.ts