Skip to content

Commit

Permalink
chore(boxes): adding clone contract option (#4980)
Browse files Browse the repository at this point in the history
  • Loading branch information
signorecello authored Mar 12, 2024
1 parent 426bd6d commit a427aa5
Show file tree
Hide file tree
Showing 21 changed files with 793 additions and 220 deletions.
2 changes: 1 addition & 1 deletion boxes/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

node_modules
dest
src/contracts/target
boxes/**/contracts/target
19 changes: 18 additions & 1 deletion boxes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,20 @@ If you have [node](https://nodejs.org/en/download) installed, you can open a ter

`npx create-aztec-app`

The script will install the sandbox, run it, and clone the boilerplate you chose. If at any time you encounter problems, refer to the guides at [docs.aztec.network](https://docs.aztec.network) for more information.
or

`npm create aztec-app`

The script will install the sandbox, run it, and clone the boilerplate you chose. You can pass some options:

| Option | Description |
| --- | --- |
| -d, --debug | Displays some more information for debug reasons. |
| -gh, --github_token | You can pass a github_token in case you hit API rate limit |
| -v, --version | You can specify a semver version, or "MASTER" |
| -h, --help | Shows up this help menu |

If at any time you encounter problems, refer to the guides at [docs.aztec.network](https://docs.aztec.network) for more information.

## Templates

Expand All @@ -23,6 +36,10 @@ Currently there are two boxes:
- React - A React boilerplate with a minimal UI.
- Vanilla JS and HTML - Some say if you get something working in vanilla JS and HTML, you can make it work on any framework. If you can't find the box you need, this could be a good starting point.

And one contract-only box:

- Token - An example token contract on Aztec

## Support

Need any support? Reach out on [discord](https://discord.gg/DgWG2DBMyB), [discourse](https://discourse.aztec.network/) or [twitter](https://twitter.com/aztecnetwork).
103 changes: 82 additions & 21 deletions boxes/bin.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#!/usr/bin/env node
import { Command } from "commander";
const program = new Command();
import { chooseAndCloneBox } from "./scripts/steps/chooseBox.js";
import { chooseProject } from "./scripts/steps/chooseBox.js";
import { sandboxRun } from "./scripts/steps/sandbox/run.js";
import { sandboxInstallOrUpdate } from "./scripts/steps/sandbox/install.js";
import { axios } from "./scripts/utils.js";
import axios from "axios";
import pino from "pino";
import pretty from "pino-pretty";
import ora from "ora";
import { AZTEC_REPO } from "./scripts/config.js";

const getLatestStable = async () => {
const { data } = await axios.get(
Expand All @@ -13,29 +17,86 @@ const getLatestStable = async () => {
return data[0].tag_name.split("-v")[1];
};

// versioning is confusing here because "latest" and "master" point to the same thing at times
// so let's clarify a bit:
//
// if the user has set a version (ex. "master" or "0.23.0"), use that
// otherwise use the stable release (ex. 0.24.0)
const latestStable = await getLatestStable();
const versionToInstall = process.env.VERSION || latestStable;

// if the user has set a semver version (matches the regex), fetch that tag (i.e. aztec-packages-v0.23.0)
// otherwise use the version as the tag
const tagToUse = versionToInstall.match(/^\d+\.\d+\.\d+$/)
? `aztec-packages-v${versionToInstall}`
: versionToInstall;

program.action(async () => {
const init = async ({ debug, github_token, version }) => {
const axiosOpts = {
timeout: 5000,
headers: github_token ? { Authorization: `token ${github_token}` } : {},
};

const prettyOpts = {
sync: true,
colorize: true,
include: debug ? "time" : "",
customLevels: "success:80",
customColors: "success:bgGreen",
};

const prettyStream = pretty(prettyOpts);
const logger = pino(
{
customLevels: {
success: 80,
},
level: debug ? "debug" : "info",
},
prettyStream,
);

global.debug = (msg) => logger.debug(msg);
global.info = (msg) => logger.info(msg);
global.success = (msg) => logger.success(msg);

global.warn = (msg) => logger.warn(msg);
global.error = (msg) => logger.error(msg);

global.github = async ({ path, raw = false }) => {
try {
const url = raw
? `https://raw.githubusercontent.com/${AZTEC_REPO}/${path}`
: `https://api.github.com/repos/${AZTEC_REPO}/contents/${path}`;
const { data } = await axios.get(url, axiosOpts);
global.debug(data);
return data;
} catch (e) {
global.error(e);
}
};

// versioning is confusing here because "latest" and "master" point to the same thing at times
// so let's clarify a bit:
//
// if the user has set a version (ex. "master" or "0.23.0"), use that
// otherwise use the stable release (ex. 0.24.0)
global.latestStable = await getLatestStable();
global.version = version || global.latestStable;

// if the user has set a semver version (matches the regex), fetch that tag (i.e. aztec-packages-v0.23.0)
// otherwise use the version as the tag
global.tag = global.version.match(/^\d+\.\d+\.\d+$/)
? `aztec-packages-v${global.version}`
: global.version;

global.debug(`Version: ${global.version}`);
global.debug(`Tag: ${global.tag}`);
global.debug(`LatestStable: ${global.latestStable}`);

global.spinner = ora({ color: "blue" });
};

program.option("-d, --debug", "output extra debugging");
program.option("-gh, --github_token <github_token>", "a github token");
program.option("-v, --version <version>", "a version number or master tag");
program.action(async (options) => {
// SETUP: Initialize global variables
await init(options);

// STEP 1: Choose the boilerplate
await chooseAndCloneBox(tagToUse, versionToInstall);
await chooseProject();

// STEP 2: Install the Sandbox
await sandboxInstallOrUpdate(latestStable, versionToInstall);
await sandboxInstallOrUpdate();

// STEP 3: Running the Sandbox
await sandboxRun(versionToInstall);
await sandboxRun();
});

program.parse();

This file was deleted.

15 changes: 5 additions & 10 deletions boxes/boxes/react/src/hooks/useContract.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useState } from 'react';
import { deployerEnv } from '../config';

import { Contract, ContractDeployer, Fr } from '@aztec/aztec.js';
import { Contract, Fr } from '@aztec/aztec.js';
import { BoxReactContract } from '../../artifacts/BoxReact';
import { toast } from 'react-toastify';

export function useContract() {
const { artifact, at } = BoxReactContract;
const [wait, setWait] = useState(false);
const [contract, setContract] = useState<Contract | undefined>();

Expand All @@ -15,22 +14,18 @@ export function useContract() {

setWait(true);
const wallet = await deployerEnv.getWallet();
const contractDeployer = new ContractDeployer(artifact, wallet);

const salt = Fr.random();
const tx = contractDeployer
.deploy(Fr.random(), wallet.getCompleteAddress().address)
.send({ contractAddressSalt: salt });
const { address: contractAddress } = await toast.promise(tx.deployed(), {
const tx = await BoxReactContract.deploy(wallet, Fr.random(), wallet.getCompleteAddress().address).send({
contractAddressSalt: salt,
});
const contract = await toast.promise(tx.deployed(), {
pending: 'Deploying contract...',
success: {
render: ({ data }) => `Address: ${data.address}`,
},
error: 'Error deploying contract',
});

const deployerWallet = await deployerEnv.getWallet();
const contract = await at(contractAddress!, deployerWallet);
setContract(contract);
setWait(false);
};
Expand Down
10 changes: 4 additions & 6 deletions boxes/boxes/react/tests/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@ const logger = createDebugLogger('aztec:http-pxe-client');
describe('BoxReact Contract Tests', () => {
let wallet: AccountWallet;
let contract: Contract;
const { artifact } = BoxReactContract;
const numberToSet = Fr.random();

beforeAll(async () => {
wallet = await deployerEnv.getWallet();
const pxe = deployerEnv.pxe;
const deployer = new ContractDeployer(artifact, wallet);
const salt = Fr.random();
const { address: contractAddress } = await deployer.deploy(Fr.random(), wallet.getCompleteAddress().address).send({ contractAddressSalt: salt }).deployed();
contract = await BoxReactContract.at(contractAddress!, wallet);
contract = await BoxReactContract.deploy(wallet, Fr.random(), wallet.getCompleteAddress().address)
.send({ contractAddressSalt: salt })
.deployed();

logger(`L2 contract deployed at ${contractAddress}`);
logger(`L2 contract deployed at ${contract.address}`);
}, 60000);

test('Can set a number', async () => {
Expand Down
11 changes: 3 additions & 8 deletions boxes/boxes/vanilla/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GrumpkinScalar, createPXEClient, AccountManager, ContractDeployer, Fr, Wallet } from '@aztec/aztec.js';
import { GrumpkinScalar, createPXEClient, AccountManager, Fr, Wallet } from '@aztec/aztec.js';

import { SingleKeyAccountContract } from '@aztec/accounts/single_key';
import { VanillaContract } from '../artifacts/Vanilla';
Expand All @@ -19,15 +19,10 @@ const setWait = (state: boolean): void =>
document.querySelector('#deploy').addEventListener('click', async ({ target }: any) => {
setWait(true);
wallet = await account.register();

const { artifact, at } = VanillaContract;
const contractDeployer = new ContractDeployer(artifact, wallet);
const { address: contractAddress } = await contractDeployer
.deploy(Fr.random(), wallet.getCompleteAddress().address)
contract = await VanillaContract.deploy(wallet, Fr.random(), wallet.getCompleteAddress().address)
.send({ contractAddressSalt: Fr.random() })
.deployed();
contract = await at(contractAddress, wallet);
alert(`Contract deployed at ${contractAddress}`);
alert(`Contract deployed at ${contract.address}`);

target.hidden = true;
document.querySelectorAll('#get, #set').forEach((e: HTMLButtonElement & HTMLFormElement) => (e.hidden = false));
Expand Down
12 changes: 12 additions & 0 deletions boxes/contract-only/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.yarn/*
!.yarn/releases

node_modules
dist
artifacts
src/contracts/target
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
codegenCache.json
2 changes: 2 additions & 0 deletions boxes/contract-only/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/artifacts/**/*.json
src/artifacts/**/*.ts
6 changes: 6 additions & 0 deletions boxes/contract-only/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 120,
"arrowParens": "avoid"
}
24 changes: 24 additions & 0 deletions boxes/contract-only/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Contract-Only Box

This box is a one-stop-shop for Aztec with the %%contract_name%% example contract. You can use it as a boilerplate to start developing your own Aztec app in seconds!

## How to start

The script copied one of the example contracts and put it into a one-size-fits-all "box". With it, you can run commands such as:

- `yarn test` -> Runs the built-in tests
- `yarn compile` -> Compiles your contract so it can be deployed
- `yarn codegen` -> Generates a handy TS interface file with all your contract's methods so they're easy to interact with
- `yarn clean` -> Removes artifacts and other things you may not want to have lying around
- `yarn formatting` -> Formats your code with prettier
-

## Testing

Contract-only boxes give you basic test functionality through `jest`, and check for existence and correct working of the sandbox.

If you want some ideas to test the contract you just bootstrapped, check out [our own e2e test suite!](%%e2e_test_url%%)

## More information

Visit the [Aztec Docs](https://docs.aztec.network) for more information on how Aztec works, and the [Awesome Aztec Repository](https://github.com/AztecProtocol/awesome-aztec) for more cool projects, boilerplates and tooling.
53 changes: 53 additions & 0 deletions boxes/contract-only/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "@aztec/contract_box",
"description": "My Aztec contract",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"compile": "cd src && ${AZTEC_NARGO:-aztec-nargo} compile",
"codegen": "${AZTEC_CLI:-aztec-cli} codegen target -o artifacts --ts",
"clean": "rm -rf ./dest .tsbuildinfo ./artifacts ./target",
"prep": "yarn clean && yarn compile && yarn codegen && tsc -b",
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand",
"formatting": "prettier --check ./src && eslint ./src",
"formatting:fix": "prettier -w ./src"
},
"dependencies": {
"@aztec/accounts": "latest",
"@aztec/aztec.js": "latest"
},
"jest": {
"preset": "ts-jest/presets/default-esm",
"transform": {
"^.+\\.(ts|tsx)$": [
"ts-jest",
{
"useESM": true
}
]
},
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
},
"testRegex": "tests/.*\\.test\\.ts$",
"rootDir": "./"
},
"devDependencies": {
"@playwright/test": "1.42.0",
"@types/jest": "^29.5.0",
"@types/node": "^20.11.17",
"copy-webpack-plugin": "^11.0.0",
"html-webpack-plugin": "^5.6.0",
"jest": "^29.6.4",
"stream-browserify": "^3.0.0",
"ts-loader": "^9.5.1",
"tty-browserify": "^0.0.1",
"typescript": "^5.0.4",
"util": "^0.12.5",
"webpack": "^5.90.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"packageManager": "yarn@4.0.2"
}
35 changes: 35 additions & 0 deletions boxes/contract-only/tests/node.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createPXEClient, PXE, GrumpkinScalar, AccountManager, Wallet } from '@aztec/aztec.js';
import { SingleKeyAccountContract } from '@aztec/accounts/single_key';
import { derivePublicKey } from '@aztec/circuits.js';

describe('Account Tests', () => {
const pxeURL = process.env.PXE_URL || 'http://localhost:8080';
let pxe: PXE;
let account: AccountManager;
let wallet: Wallet;

const privateKey = GrumpkinScalar.fromString('0x1234');
const expectedPublicKey = derivePublicKey(privateKey).toString();

test('Can start the PXE server', async () => {
pxe = createPXEClient(pxeURL);
const { chainId } = await pxe.getNodeInfo();
expect(chainId).toBe(31337);
});

beforeEach(() => {
const accountContract = new SingleKeyAccountContract(privateKey);
account = new AccountManager(pxe, privateKey, accountContract);
});

test('Can create an account contract with a known address', async () => {
const publicKey = account.getCompleteAddress().publicKey.toString();
expect(publicKey).toEqual(expectedPublicKey);
});

test('Can deploy a contract with a known address', async () => {
({ wallet } = await (await account.deploy()).wait());
const publicKey = wallet.getCompleteAddress().publicKey.toString();
expect(publicKey).toEqual(expectedPublicKey);
});
});
10 changes: 10 additions & 0 deletions boxes/contract-only/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "es2020",
"outDir": "artifacts/build",
"module": "ESNext",
"moduleResolution": "Bundler",
"skipLibCheck": true
},
"include": ["**/*.ts"]
}
Loading

0 comments on commit a427aa5

Please sign in to comment.