diff --git a/yarn-project/boxes/blank-react/.eslintrc.cjs b/yarn-project/boxes/blank-react/.eslintrc.cjs index 93359038995..8b84efd5d65 100644 --- a/yarn-project/boxes/blank-react/.eslintrc.cjs +++ b/yarn-project/boxes/blank-react/.eslintrc.cjs @@ -1,6 +1,9 @@ module.exports = { root: true, env: { browser: true, es2020: true }, + parserOptions: { + project: './tsconfig.json', + }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', @@ -15,14 +18,13 @@ module.exports = { node: true, }, }, - ignorePatterns: ['dist', '.eslintrc.cjs'], + ignorePatterns: ['dest', 'webpack.config.js', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], overrides: [ { files: ['*.ts', '*.tsx'], parserOptions: { - // hacky workaround for CI not having the same tsconfig setup project: true, }, }, diff --git a/yarn-project/boxes/blank-react/package.json b/yarn-project/boxes/blank-react/package.json index 86a250b8196..60abb15a1c7 100644 --- a/yarn-project/boxes/blank-react/package.json +++ b/yarn-project/boxes/blank-react/package.json @@ -6,7 +6,7 @@ "main": "./dest/index.js", "scripts": { "build": "yarn clean && tsc -b && webpack", - "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v aztec", + "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v NOIR_VERSION", "install:sandbox": "docker pull aztecprotocol/aztec-sandbox:latest", "clean": "rm -rf ./dest .tsbuildinfo", "start": "serve -p 3000 ./dest", diff --git a/yarn-project/boxes/blank-react/src/app/components/contract_function_form.tsx b/yarn-project/boxes/blank-react/src/app/components/contract_function_form.tsx index 69916e7061e..6c4e6b1d5ff 100644 --- a/yarn-project/boxes/blank-react/src/app/components/contract_function_form.tsx +++ b/yarn-project/boxes/blank-react/src/app/components/contract_function_form.tsx @@ -3,7 +3,7 @@ import { AztecAddress, CompleteAddress, Fr } from '@aztec/aztec.js'; import { ContractAbi, FunctionAbi } from '@aztec/foundation/abi'; import { useFormik } from 'formik'; import * as Yup from 'yup'; -import { CONTRACT_ADDRESS_PARAM_NAMES, rpcClient } from '../../config.js'; +import { CONTRACT_ADDRESS_PARAM_NAMES, pxe } from '../../config.js'; import { callContractFunction, deployContract, viewContractFunction } from '../../scripts/index.js'; import { convertArgs } from '../../scripts/util.js'; import styles from './contract_function_form.module.scss'; @@ -80,20 +80,13 @@ async function handleFunctionCall( // for now, dont let user change the salt. requires some change to the form generation if we want to let user choose one // since everything is currently based on parsing the contractABI, and the salt parameter is not present there const salt = Fr.random(); - return await deployContract(wallet, contractAbi, typedArgs, salt, rpcClient); + return await deployContract(wallet, contractAbi, typedArgs, salt, pxe); } if (functionAbi.functionType === 'unconstrained') { - return await viewContractFunction(contractAddress!, contractAbi, functionName, typedArgs, rpcClient, wallet); + return await viewContractFunction(contractAddress!, contractAbi, functionName, typedArgs, pxe, wallet); } else { - const txnReceipt = await callContractFunction( - contractAddress!, - contractAbi, - functionName, - typedArgs, - rpcClient, - wallet, - ); + const txnReceipt = await callContractFunction(contractAddress!, contractAbi, functionName, typedArgs, pxe, wallet); return `Transaction ${txnReceipt.status} on block number ${txnReceipt.blockNumber}`; } } diff --git a/yarn-project/boxes/blank-react/src/config.ts b/yarn-project/boxes/blank-react/src/config.ts index 2c406a9302b..bf8bbb85b3b 100644 --- a/yarn-project/boxes/blank-react/src/config.ts +++ b/yarn-project/boxes/blank-react/src/config.ts @@ -1,6 +1,6 @@ -import { BlankContractAbi } from './artifacts/blank.js'; import { PXE, createPXEClient } from '@aztec/aztec.js'; import { ContractAbi } from '@aztec/foundation/abi'; +import { BlankContractAbi } from './artifacts/blank.js'; // update this if using a different contract @@ -10,4 +10,3 @@ export const SANDBOX_URL: string = process.env.SANDBOX_URL || 'http://localhost: export const pxe: PXE = createPXEClient(SANDBOX_URL); export const CONTRACT_ADDRESS_PARAM_NAMES = ['address']; -export const FILTERED_FUNCTION_NAMES = []; diff --git a/yarn-project/boxes/blank-react/src/contracts/src/interface.nr b/yarn-project/boxes/blank-react/src/contracts/src/interface.nr deleted file mode 100644 index 5e15a7765cc..00000000000 --- a/yarn-project/boxes/blank-react/src/contracts/src/interface.nr +++ /dev/null @@ -1,51 +0,0 @@ -/* Autogenerated file, do not edit! */ - -use dep::std; -use dep::aztec::context::{ PrivateContext, PublicContext }; -use dep::aztec::constants_gen::RETURN_VALUES_LENGTH; - - - -// Interface for calling Blank functions from a private context -struct BlankPrivateContextInterface { - address: Field, -} - -impl BlankPrivateContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - - fn getPublicKey( - self, - context: &mut PrivateContext, - address: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = address; - - context.call_private_function(self.address, 0x88f0753b, serialized_args) - } - -} - - - - -// Interface for calling Blank functions from a public context -struct BlankPublicContextInterface { - address: Field, -} - -impl BlankPublicContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - -} - - diff --git a/yarn-project/boxes/blank/.eslintrc.cjs b/yarn-project/boxes/blank/.eslintrc.cjs index 726df7b92fa..f52d3385f98 100644 --- a/yarn-project/boxes/blank/.eslintrc.cjs +++ b/yarn-project/boxes/blank/.eslintrc.cjs @@ -1,6 +1,9 @@ module.exports = { root: true, env: { browser: true, es2020: true }, + parserOptions: { + project: './tsconfig.json', + }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', @@ -14,14 +17,13 @@ module.exports = { node: true, }, }, - ignorePatterns: ['dist', '.eslintrc.cjs'], + ignorePatterns: ['dest', 'webpack.config.js', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', plugins: [], overrides: [ { files: ['*.ts', '*.tsx'], parserOptions: { - // hacky workaround for CI not having the same tsconfig setup project: true, }, }, diff --git a/yarn-project/boxes/blank/package.json b/yarn-project/boxes/blank/package.json index 56b5b914832..08d6e006d07 100644 --- a/yarn-project/boxes/blank/package.json +++ b/yarn-project/boxes/blank/package.json @@ -6,7 +6,7 @@ "main": "./dest/index.js", "scripts": { "build": "yarn clean && tsc -b && webpack", - "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v aztec", + "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v NOIR_VERSION", "install:sandbox": "docker pull aztecprotocol/aztec-sandbox:latest", "clean": "rm -rf ./dest .tsbuildinfo", "start": "serve -p 3000 ./dest", diff --git a/yarn-project/boxes/blank/src/contracts/src/interface.nr b/yarn-project/boxes/blank/src/contracts/src/interface.nr deleted file mode 100644 index 5e15a7765cc..00000000000 --- a/yarn-project/boxes/blank/src/contracts/src/interface.nr +++ /dev/null @@ -1,51 +0,0 @@ -/* Autogenerated file, do not edit! */ - -use dep::std; -use dep::aztec::context::{ PrivateContext, PublicContext }; -use dep::aztec::constants_gen::RETURN_VALUES_LENGTH; - - - -// Interface for calling Blank functions from a private context -struct BlankPrivateContextInterface { - address: Field, -} - -impl BlankPrivateContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - - fn getPublicKey( - self, - context: &mut PrivateContext, - address: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 1]; - serialized_args[0] = address; - - context.call_private_function(self.address, 0x88f0753b, serialized_args) - } - -} - - - - -// Interface for calling Blank functions from a public context -struct BlankPublicContextInterface { - address: Field, -} - -impl BlankPublicContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - -} - - diff --git a/yarn-project/boxes/blank/src/index.ts b/yarn-project/boxes/blank/src/index.ts index 67f3b7bbc10..6d35b8190fc 100644 --- a/yarn-project/boxes/blank/src/index.ts +++ b/yarn-project/boxes/blank/src/index.ts @@ -1,11 +1,11 @@ import { AccountWallet, AztecAddress, - PXE, CompleteAddress, Contract, DeployMethod, Fr, + PXE, TxReceipt, createPXEClient, getSandboxAccountsWallets, @@ -18,27 +18,25 @@ export const contractAbi: ContractAbi = BlankContractAbi; export const SANDBOX_URL: string = process.env.SANDBOX_URL || 'http://localhost:8080'; export const pxe: PXE = createPXEClient(SANDBOX_URL); -export const CONTRACT_ADDRESS_PARAM_NAMES = ['owner', 'contract_address', 'recipient']; -export const FILTERED_FUNCTION_NAMES = []; - -export const DEFAULT_PUBLIC_ADDRESS: string = '0x25048e8c1b7dea68053d597ac2d920637c99523651edfb123d0632da785970d0'; - let contractAddress: string = ''; // interaction with the buttons, but conditional check so node env can also import from this file if (typeof document !== 'undefined') { document.getElementById('deploy')?.addEventListener('click', async () => { contractAddress = await handleDeployClick(); + // eslint-disable-next-line no-console console.log('Deploy Succeeded, contract deployed at', contractAddress); }); document.getElementById('interact')?.addEventListener('click', async () => { const interactionResult = await handleInteractClick(contractAddress); + // eslint-disable-next-line no-console console.log('Interaction transaction succeeded', interactionResult); }); } export async function handleDeployClick(): Promise { + // eslint-disable-next-line no-console console.log('Deploying Contract'); const [wallet, ..._rest] = await getSandboxAccountsWallets(pxe); @@ -52,6 +50,8 @@ export async function handleInteractClick(contractAddress: string) { const callArgs = { address: wallet.getCompleteAddress().address }; const getPkAbi = getFunctionAbi(BlankContractAbi, 'getPublicKey'); const typedArgs = convertArgs(getPkAbi, callArgs); + + // eslint-disable-next-line no-console console.log('Interacting with Contract'); return await callContractFunction( @@ -81,7 +81,10 @@ export async function callContractFunction( // selectedWallet is how we specify the "sender" of the transaction const selectedWallet = await getWallet(wallet, pxe); - // TODO: switch to the generated typescript class? + // Note: when you start implementing the contract with more methods, it may be useful + // to use the typescript class for your contract generated by the `yarn compile` command, + // which provides an object with methods corresponding to the noir contract functions + // that are named and typed and can be called directly. const contract = await Contract.at(address, abi, selectedWallet); return contract.methods[functionName](...typedArgs) diff --git a/yarn-project/boxes/private-token/.eslintrc.cjs b/yarn-project/boxes/private-token/.eslintrc.cjs index 93359038995..1d5617c5bbb 100644 --- a/yarn-project/boxes/private-token/.eslintrc.cjs +++ b/yarn-project/boxes/private-token/.eslintrc.cjs @@ -1,6 +1,9 @@ module.exports = { root: true, env: { browser: true, es2020: true }, + parserOptions: { + project: './tsconfig.json', + }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', @@ -15,7 +18,7 @@ module.exports = { node: true, }, }, - ignorePatterns: ['dist', '.eslintrc.cjs'], + ignorePatterns: ['dest', 'webpack.config.js', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], overrides: [ diff --git a/yarn-project/boxes/private-token/package.json b/yarn-project/boxes/private-token/package.json index c80f4a39ab5..8631f25b2c7 100644 --- a/yarn-project/boxes/private-token/package.json +++ b/yarn-project/boxes/private-token/package.json @@ -6,7 +6,7 @@ "main": "./dest/index.js", "scripts": { "build": "yarn clean && tsc -b && webpack", - "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v aztec", + "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v NOIR_VERSION", "install:sandbox": "docker pull aztecprotocol/aztec-sandbox:latest", "clean": "rm -rf ./dest .tsbuildinfo", "start": "serve -p 3000 ./dest", diff --git a/yarn-project/boxes/private-token/src/contracts/src/interface.nr b/yarn-project/boxes/private-token/src/contracts/src/interface.nr deleted file mode 100644 index 0f59f541a24..00000000000 --- a/yarn-project/boxes/private-token/src/contracts/src/interface.nr +++ /dev/null @@ -1,67 +0,0 @@ -/* Autogenerated file, do not edit! */ - -use dep::std; -use dep::aztec::context::{ PrivateContext, PublicContext }; -use dep::aztec::constants_gen::RETURN_VALUES_LENGTH; - - - -// Interface for calling PrivateToken functions from a private context -struct PrivateTokenPrivateContextInterface { - address: Field, -} - -impl PrivateTokenPrivateContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - - fn mint( - self, - context: &mut PrivateContext, - amount: Field, - owner: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = owner; - - context.call_private_function(self.address, 0x1535439c, serialized_args) - } - - - fn transfer( - self, - context: &mut PrivateContext, - amount: Field, - recipient: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 2]; - serialized_args[0] = amount; - serialized_args[1] = recipient; - - context.call_private_function(self.address, 0xc0888d22, serialized_args) - } - -} - - - - -// Interface for calling PrivateToken functions from a public context -struct PrivateTokenPublicContextInterface { - address: Field, -} - -impl PrivateTokenPublicContextInterface { - fn at(address: Field) -> Self { - Self { - address, - } - } - -} - - diff --git a/yarn-project/cli/src/unbox.ts b/yarn-project/cli/src/unbox.ts index 192f10bdcf9..ec9415e79ce 100644 --- a/yarn-project/cli/src/unbox.ts +++ b/yarn-project/cli/src/unbox.ts @@ -40,7 +40,7 @@ async function isDirectoryNonEmpty(directoryPath: string): Promise { * @param localOutputPath - local path to copy to */ async function copyFolderFromGithub(data: JSZip, repositoryFolderPath: string, localOutputPath: string, log: LogFn) { - log(`Downloading from github: ${repositoryFolderPath}`); + log(`Downloading folder from github: ${repositoryFolderPath}`); const repositoryDirectories = Object.values(data.files).filter(file => { return file.dir && file.name.startsWith(repositoryFolderPath); }); @@ -51,11 +51,11 @@ async function copyFolderFromGithub(data: JSZip, repositoryFolderPath: string, l await fs.mkdir(targetPath, { recursive: true }); } - const starterFiles = Object.values(data.files).filter(file => { + const folderFiles = Object.values(data.files).filter(file => { return !file.dir && file.name.startsWith(repositoryFolderPath); }); - for (const file of starterFiles) { + for (const file of folderFiles) { const relativePath = file.name.replace(repositoryFolderPath, ''); const targetPath = `${localOutputPath}/${relativePath}`; const content = await file.async('nodebuffer'); @@ -63,6 +63,27 @@ async function copyFolderFromGithub(data: JSZip, repositoryFolderPath: string, l } } +/** + * @param data - in memory unzipped clone of a github repo + * @param repositoryFile - path of the file to copy from github repo + * @param localOutputPath - local path to copy the file to + */ +async function copyFileFromGithub(data: JSZip, repositoryFile: string, localOutputPath: string, log: LogFn) { + log(`Downloading file from github: ${repositoryFile}`); + + const file = data.files[repositoryFile]; + + if (!file || file.dir) { + throw new Error(`File not found or it's a directory: ${repositoryFile}`); + } + + const filename = path.basename(repositoryFile); + const targetPath = `${localOutputPath}/${filename}`; + + const content = await file.async('nodebuffer'); + await fs.writeFile(targetPath, content); +} + /** * Not flexible at at all, but quick fix to download a noir smart contract from our * monorepo on github. this will copy over the `yarn-projects/boxes/{contract_name}` folder @@ -98,12 +119,19 @@ async function downloadContractAndBoxFromGithub( const boxPath = `${repoDirectoryPrefix}/${BOXES_PATH}/${contractName}`; await copyFolderFromGithub(data, boxPath, outputPath, log); + // the expected noir version is contained in + // aztec-packages/yarn-project/noir-compiler/src/noir-version.json + // copy it in and use to update the package.json script to install that version of noir + const noirVersionPath = `${repoDirectoryPrefix}/yarn-project/noir-compiler/src/noir-version.json`; + await copyFileFromGithub(data, noirVersionPath, outputPath, log); + const contractTargetDirectory = path.join(outputPath, 'src', 'contracts'); const boxContainsNoirSource = await isDirectoryNonEmpty(contractTargetDirectory); if (boxContainsNoirSource) { return; } else { // we used to support downloading from the noir contracts monorepo but now force box to contain source code + // This should never happen, because of the check we do initially on the box name. throw Error(`Box ${contractName} does not contain noir source code.`); } } @@ -200,6 +228,13 @@ async function updatePackageJsonVersions(packageVersion: string, outputPath: str } } } + // read the `noir-version.json`, grab the expected noir version, and patch the noir install script + const noirVersionPath = path.join(outputPath, 'noir-version.json'); + const noirVersionContent = await fs.readFile(noirVersionPath, 'utf-8'); + const noirVersionJSON = JSON.parse(noirVersionContent); + const noirTag = noirVersionJSON.tag; + packageData.scripts['install:noir'] = packageData.scripts['install:noir'].replace('NOIR_VERSION', `${noirTag}`); + log(`Updated Noir version to: ${noirTag}`); // modify the version of the sandbox to pull - it's set to "latest" version in the monorepo, // but we need to replace with the same tagVersion as the cli and the other aztec npm packages @@ -262,7 +297,7 @@ export async function unboxContract( packageVersion: string, log: LogFn, ) { - const contractNames = ['private-token', 'blank']; + const contractNames = ['private-token', 'blank', 'blank-react']; if (!contractNames.includes(contractName)) { log( @@ -276,11 +311,9 @@ export async function unboxContract( const tag = `${GITHUB_TAG_PREFIX}-v${packageVersion}`; // downloads the selected contract's relevant folder in @aztec/boxes/{contract_name} - // and the noir source code from `noir-contracts` into `${outputDirectoryName}/src/contracts` - // if not present in the box await downloadContractAndBoxFromGithub(tag, contractName, outputPath, log); // make adjustments for packaging to work as a standalone, as opposed to part of yarn workspace - // as in the monorepo source files + // as in the monorepo source files. replace things like "workspace^" with the actual version number await updatePackagingConfigurations(packageVersion, tag, outputPath, log); log(''); @@ -288,5 +321,7 @@ export async function unboxContract( log('To get started, simply run the following commands:'); log(` cd ${outputDirectoryName}`); log(' yarn'); + log(' yarn start:sandbox'); + log('And in another terminal in the same directory,'); log(' yarn start:dev'); }