diff --git a/yarn-project/boxes/blank/.eslintrc.cjs b/yarn-project/boxes/blank/.eslintrc.cjs new file mode 100644 index 00000000000..726df7b92fa --- /dev/null +++ b/yarn-project/boxes/blank/.eslintrc.cjs @@ -0,0 +1,59 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + 'prettier', + ], + settings: { + 'import/resolver': { + typescript: true, + node: true, + }, + }, + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: [], + overrides: [ + { + files: ['*.ts', '*.tsx'], + parserOptions: { + // hacky workaround for CI not having the same tsconfig setup + project: true, + }, + }, + ], + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-floating-promises': 2, + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + 'require-await': 2, + 'no-console': 'warn', + 'no-constant-condition': 'off', + camelcase: 2, + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['client-dest'], + message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", + }, + { + group: ['dest'], + message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', + }, + ], + }, + ], + 'import/no-unresolved': 'error', + 'import/no-extraneous-dependencies': 'error', + }, +}; diff --git a/yarn-project/boxes/blank/.gitignore b/yarn-project/boxes/blank/.gitignore new file mode 100644 index 00000000000..fa69c44ea89 --- /dev/null +++ b/yarn-project/boxes/blank/.gitignore @@ -0,0 +1,22 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dest + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/yarn-project/boxes/blank/.prettierrc.json b/yarn-project/boxes/blank/.prettierrc.json new file mode 100644 index 00000000000..7c3bbec6848 --- /dev/null +++ b/yarn-project/boxes/blank/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "arrowParens": "avoid" +} diff --git a/yarn-project/boxes/blank/README.md b/yarn-project/boxes/blank/README.md new file mode 100644 index 00000000000..0547a149ec4 --- /dev/null +++ b/yarn-project/boxes/blank/README.md @@ -0,0 +1,76 @@ +This is a minimal [Aztec](https://aztec.network/) Noir smart contract and frontend bootstrapped with [`aztec-cli unbox`](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/cli). It is recommended you use the `aztec-cli unbox blank` command so that the repository is copied with needed modifications from the monorepo subpackage. + +## Setup + +Dependencies can be installed from the root of the package: + +```bash +yarn +yarn install:noir +yarn install:sandbox +``` + +This sandbox requires [Docker](https://www.docker.com/) to be installed _and running_ locally. In the event the image needs updating, you can run `yarn install:sandbox` (see [sandbox docs](https://aztec-docs-dev.netlify.app/dev_docs/getting_started/sandbox) for more information.) + +In addition to the usual javascript dependencies, this project requires `nargo` (package manager) and `noir` (a Domain Specific Language for SNARK proving systems) in addition to `@aztec/aztec-cli`. The former are installed within `yarn install:noir` + +## Getting started + +After `yarn` has run,`yarn start:sandbox` in one terminal will launch a local instance of the Aztec sandbox via Docker Compose and `yarn start:dev` will launch a frontend app for deploying and interacting with an empty Aztec smart contract. + +At this point, [http://localhost:5173](http://localhost:5173) should provide a minimal smart contract frontend. + +This folder should have the following directory structure: + +``` +|— README.md +|— package.json +|— src + index.html + index.ts + |— contracts + |— src + | The Noir smart contract source files are here. + |— main.nr - the cloned noir contract, your starting point + |- interface.nr - autogenerated from main.nr when you compile + |— Nargo.toml [Noir build file, includes Aztec smart contract dependencies] + |— artifacts + | These are both generated from `contracts/` by the compile command + |— blank_contract.json + |— blank.ts + |— tests + | A simple end2end test deploying and testing the minimal contract on a local sandbox + | using the front end helper methods in index.ts + | The test requires the sandbox and anvil to be running (yarn start:sandbox). + |- blank.contract.test.ts +``` + +Most relevant to you is likely `src/contracts/main.nr` (and the build config `src/contracts/Nargo.toml`). This contains the example blank contract logic that the frontend interacts with and is a good place to start writing Noir. + +The `src/artifacts` folder can be re-generated from the command line + +```bash +yarn compile +``` + +This will generate a [Contract ABI](src/artifacts/test_contract.json) and TypeScript class for the [Aztec smart contract](src/contracts/main.nr), which the frontend uses to generate the UI. + +Note: the `compile` command seems to generate a Typescript file which needs a single change - + +``` +import TestContractAbiJson from 'text_contract.json' assert { type: 'json' }; +// need to update the relative import to +import TestContractAbiJson from './test_contract.json' assert { type: 'json' }; +``` + +After compiling, you can re-deploy the upated noir smart contract from the web UI. The function interaction forms are generated from parsing the ContractABI, so they should update automatically after you recompile. + +## Learn More + +To learn more about Noir Smart Contract development, take a look at the following resources: + +- [Awesome Noir](https://github.com/noir-lang/awesome-noir) - learn about the Noir programming language. + +## Deploy on Aztec3 + +Coming Soon :) diff --git a/yarn-project/boxes/blank/package.json b/yarn-project/boxes/blank/package.json new file mode 100644 index 00000000000..7a5ee34df24 --- /dev/null +++ b/yarn-project/boxes/blank/package.json @@ -0,0 +1,71 @@ +{ + "name": "blank-contract", + "private": true, + "version": "0.1.0", + "type": "module", + "main": "./dest/index.js", + "scripts": { + "build": "yarn clean && webpack", + "install:noir": "curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash noirup -v aztec", + "install:sandbox": "docker pull aztecprotocol/aztec-sandbox:latest", + "clean": "rm -rf ./dest .tsbuildinfo", + "start": "serve -p 3000 ./dest", + "start:dev": "webpack serve --mode=development", + "start:sandbox": "SANDBOX_VERSION=latest /bin/bash -c \"$(curl -fsSL 'https://sandbox.aztec.network')\" ", + "formatting": "prettier --check ./src && eslint ./src", + "formatting:fix": "prettier -w ./src", + "compile": "aztec-cli compile src/contracts --outdir ../artifacts --typescript ../artifacts", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand", + "test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test\" \"anvil\"" + }, + "jest": { + "preset": "ts-jest'", + "testEnvironment": "jsdom" + }, + "dependencies": { + "@aztec/aztec-ui": "^0.1.14", + "@aztec/aztec.js": "workspace:^", + "@aztec/circuits.js": "workspace:^", + "@aztec/cli": "workspace:^", + "@aztec/foundation": "workspace:^", + "serve": "^14.2.1" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "copy-webpack-plugin": "^11.0.0", + "eslint": "^8.45.0", + "eslint-import-resolver-typescript": "^3.5.5", + "eslint-plugin-import": "^2.27.5", + "jest": "^29.6.4", + "prettier": "^3.0.3", + "resolve-typescript-plugin": "^2.0.1", + "stream-browserify": "^3.0.0", + "ts-jest": "^29.1.1", + "ts-loader": "^9.4.4", + "ts-node": "^10.9.1", + "tty-browserify": "^0.0.1", + "typescript": "^5.0.4", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "files": [ + "dest", + "src", + "!*.test.*" + ], + "types": "./dest/index.d.ts" +} diff --git a/yarn-project/boxes/blank/src/artifacts/blank.ts b/yarn-project/boxes/blank/src/artifacts/blank.ts new file mode 100644 index 00000000000..ce41cd8e217 --- /dev/null +++ b/yarn-project/boxes/blank/src/artifacts/blank.ts @@ -0,0 +1,80 @@ +/* Autogenerated file, do not edit! */ + +/* eslint-disable */ +import { + AztecAddress, + CompleteAddress, + ContractBase, + ContractFunctionInteraction, + ContractMethod, + DeployMethod, + FieldLike, + Wallet, +} from '@aztec/aztec.js'; +import { ContractAbi } from '@aztec/foundation/abi'; +import { Point } from '@aztec/foundation/fields'; +import { AztecRPC, PublicKey } from '@aztec/types'; + +import BlankContractAbiJson from './blank_contract.json' assert { type: 'json' }; + +export const BlankContractAbi = BlankContractAbiJson as ContractAbi; + +/** + * Type-safe interface for contract Blank; + */ +export class BlankContract extends ContractBase { + private constructor( + /** The deployed contract's complete address. */ + completeAddress: CompleteAddress, + /** The wallet. */ + wallet: Wallet, + ) { + super(completeAddress, BlankContractAbi, wallet); + } + + /** + * Creates a contract instance. + * @param address - The deployed contract's address. + * @param wallet - The wallet to use when interacting with the contract. + * @returns A promise that resolves to a new Contract instance. + */ + public static async at( + /** The deployed contract's address. */ + address: AztecAddress, + /** The wallet. */ + wallet: Wallet, + ) { + const extendedContractData = await wallet.getExtendedContractData(address); + if (extendedContractData === undefined) { + throw new Error('Contract ' + address.toString() + ' is not deployed'); + } + return new BlankContract(extendedContractData.getCompleteAddress(), wallet); + } + + /** + * Creates a tx to deploy a new instance of this contract. + */ + public static deploy(rpc: AztecRPC) { + return new DeployMethod(Point.ZERO, rpc, BlankContractAbi, Array.from(arguments).slice(1)); + } + + /** + * Creates a tx to deploy a new instance of this contract using the specified public key to derive the address. + */ + public static deployWithPublicKey(rpc: AztecRPC, publicKey: PublicKey) { + return new DeployMethod(publicKey, rpc, BlankContractAbi, Array.from(arguments).slice(2)); + } + + /** + * Returns this contract's ABI. + */ + public static get abi(): ContractAbi { + return BlankContractAbi; + } + + /** Type-safe wrappers for the public methods exposed by the contract. */ + public methods!: { + /** getPublicKey(address: field) */ + getPublicKey: ((address: FieldLike) => ContractFunctionInteraction) & Pick; + }; +} diff --git a/yarn-project/boxes/blank/src/artifacts/blank_contract.json b/yarn-project/boxes/blank/src/artifacts/blank_contract.json new file mode 100644 index 00000000000..8ef0a353dff --- /dev/null +++ b/yarn-project/boxes/blank/src/artifacts/blank_contract.json @@ -0,0 +1,51 @@ +{ + "name": "Blank", + "functions": [ + { + "name": "constructor", + "functionType": "secret", + "isInternal": false, + "parameters": [], + "returnTypes": [], + "bytecode": "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", + "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" + }, + { + "name": "getPublicKey", + "functionType": "secret", + "isInternal": false, + "parameters": [ + { + "name": "address", + "type": { + "kind": "field" + }, + "visibility": "private" + } + ], + "returnTypes": [], + "bytecode": "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", + "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" + } + ], + "debug": { + "debugSymbols": [ + "eJyrVsrJT04syczPK1ayqq6tBQAz9wY7", + "eJzN1s1qwkAUhuF7mXUomfOTzORWShehKggSS5NdyL1rJVNFp46LcvhWMXDm8GYWD87ucPzsp/1xGF03O3bd++zGr374eRun/ntyXV257bA5P5fK7faHrev8Uj1MeYpNWCfPv+N1mjk3zqGOaZxDpNvxj8oJTInClDQwJS1MSYApiTAlvsZJ8TgphJOC46zHgdbjSOtxqPU41nocbD2OtoSjLeFoSzjaEo62hKMt4WhLONoSjraEoy3haMs42jKOtoyjLeNoyzjaMo62bKltbCmNS63hPsVS20KKpbaFFEttn6eIpbaFFEttCymW2hZSLLUtpFhqW0ix1LaQgqOt4GgrONoKjraKo63iaKs42mpWW43p71ZD9DSHiddJVv2d1HjZneXzn3ZnPXx9t4R03cpyuztzha2so9TG6/XpJSNroX1G1sHXM1Q0ZbRyf9P8lv1IorSdND6eyRYVzmQJLZzJWvf3mWU5AXXkyVM=" + ], + "fileMap": { + "33": { + "source": "use crate::constants_gen::{\n RETURN_VALUES_LENGTH,\n MAX_READ_REQUESTS_PER_CALL,\n MAX_NEW_COMMITMENTS_PER_CALL,\n MAX_NEW_NULLIFIERS_PER_CALL,\n MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,\n MAX_NEW_L2_TO_L1_MSGS_PER_CALL,\n NUM_FIELDS_PER_SHA256,\n MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,\n MAX_PUBLIC_DATA_READS_PER_CALL,\n GENERATOR_INDEX__FUNCTION_ARGS,\n HISTORIC_BLOCK_DATA_LENGTH,\n CONTRACT_DEPLOYMENT_DATA_LENGTH,\n CALL_CONTEXT_LENGTH,\n PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH,\n PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH,\n CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH,\n CONTRACT_STORAGE_READ_LENGTH,\n PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH,\n PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH,\n GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS,\n GENERATOR_INDEX__FUNCTION_DATA,\n GENERATOR_INDEX__PUBLIC_DATA_READ,\n GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST,\n GENERATOR_INDEX__CALL_CONTEXT,\n GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS,\n GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA,\n};\n\nuse crate::oracle::debug_log;\nuse crate::types::vec::BoundedVec;\nuse crate::types::point::Point;\n\nstruct PrivateGlobalVariables {\n chain_id: Field,\n version: Field,\n}\n\nimpl PrivateGlobalVariables {\n fn serialize(self) -> [Field; 2] {\n [self.chain_id, self.version]\n }\n}\n\nstruct PublicGlobalVariables {\n chain_id: Field,\n version: Field,\n block_number: Field,\n timestamp: Field,\n}\n\nimpl PublicGlobalVariables {\n fn serialize(self) -> [Field; 4] {\n [self.chain_id, self.version, self.block_number, self.timestamp]\n }\n}\n\nstruct ContractDeploymentData {\n deployer_public_key: Point,\n constructor_vk_hash : Field,\n function_tree_root : Field,\n contract_address_salt : Field,\n portal_contract_address : Field,\n}\n\nimpl ContractDeploymentData {\n fn serialize(self) -> [Field; CONTRACT_DEPLOYMENT_DATA_LENGTH] {\n [\n self.deployer_public_key.x,\n self.deployer_public_key.y,\n self.constructor_vk_hash,\n self.function_tree_root,\n self.contract_address_salt,\n self.portal_contract_address,\n ]\n }\n\n fn hash(self) -> Field {\n dep::std::hash::pedersen_with_separator(self.serialize(), GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA)[0]\n }\n}\n\n// PrivateContextInputs are expected to be provided to each private function\nstruct PrivateContextInputs {\n call_context : CallContext,\n block_data: HistoricBlockData,\n\n contract_deployment_data: ContractDeploymentData,\n\n private_global_variables: PrivateGlobalVariables,\n}\n\n// PublicContextInputs are expected to be provided to each public function\nstruct PublicContextInputs {\n call_context: CallContext,\n block_data: HistoricBlockData,\n\n public_global_variables: PublicGlobalVariables,\n}\n\nstruct CallContext {\n msg_sender : Field,\n storage_contract_address : Field,\n portal_contract_address : Field,\n\n is_delegate_call : bool,\n is_static_call : bool,\n is_contract_deployment: bool,\n}\n\nimpl CallContext {\n fn serialize(self) -> [Field; CALL_CONTEXT_LENGTH] {\n [\n self.msg_sender,\n self.storage_contract_address,\n self.portal_contract_address,\n self.is_delegate_call as Field,\n self.is_static_call as Field,\n self.is_contract_deployment as Field,\n ]\n }\n\n fn hash(self) -> Field {\n dep::std::hash::pedersen_with_separator(self.serialize(), GENERATOR_INDEX__CALL_CONTEXT)[0]\n }\n}\n\nstruct HistoricBlockData {\n private_data_tree_root : Field,\n nullifier_tree_root : Field,\n contract_tree_root : Field,\n l1_to_l2_messages_tree_root : Field,\n blocks_tree_root: Field,\n public_data_tree_root: Field,\n global_variables_hash: Field,\n}\n\nimpl HistoricBlockData {\n // NOTE: this order must match the order in `private_circuit_public_inputs.hpp`\n fn serialize(self) -> [Field; HISTORIC_BLOCK_DATA_LENGTH] {\n [\n self.private_data_tree_root,\n self.nullifier_tree_root,\n self.contract_tree_root,\n self.l1_to_l2_messages_tree_root,\n self.blocks_tree_root,\n self.public_data_tree_root,\n self.global_variables_hash,\n ]\n }\n\n fn empty() -> Self {\n Self { private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, public_data_tree_root: 0, global_variables_hash: 0 }\n }\n}\n\nstruct FunctionData {\n function_selector: Field,\n is_internal: bool,\n is_private: bool,\n is_constructor: bool,\n}\n\nimpl FunctionData {\n fn hash(self) -> Field {\n dep::std::hash::pedersen_with_separator([\n self.function_selector,\n self.is_internal as Field,\n self.is_private as Field,\n self.is_constructor as Field,\n ], GENERATOR_INDEX__FUNCTION_DATA)[0]\n }\n}\n\nstruct PrivateCircuitPublicInputs {\n call_context: CallContext,\n args_hash: Field,\n return_values: [Field; RETURN_VALUES_LENGTH],\n read_requests: [Field; crate::abi::MAX_READ_REQUESTS_PER_CALL],\n new_commitments: [Field; MAX_NEW_COMMITMENTS_PER_CALL],\n new_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_CALL],\n nullified_commitments: [Field; MAX_NEW_NULLIFIERS_PER_CALL],\n private_call_stack: [Field; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL],\n public_call_stack: [Field; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL],\n new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_CALL],\n // Explore introducing a new type like uint256 (similar to Point), so it's more explicit that\n // we're talking about a single number backed by two field elements.\n encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256],\n unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256],\n encrypted_log_preimages_length: Field,\n unencrypted_log_preimages_length: Field,\n block_data: HistoricBlockData,\n contract_deployment_data: ContractDeploymentData,\n chain_id: Field,\n version: Field,\n}\n\nimpl PrivateCircuitPublicInputs {\n fn hash(self) -> Field {\n let mut fields: BoundedVec = BoundedVec::new(0); \n fields.push(self.call_context.hash());\n fields.push(self.args_hash);\n fields.push_array(self.return_values);\n fields.push_array(self.read_requests);\n fields.push_array(self.new_commitments);\n fields.push_array(self.new_nullifiers);\n fields.push_array(self.nullified_commitments);\n fields.push_array(self.private_call_stack);\n fields.push_array(self.public_call_stack);\n fields.push_array(self.new_l2_to_l1_msgs);\n fields.push_array(self.encrypted_logs_hash);\n fields.push_array(self.unencrypted_logs_hash);\n fields.push(self.encrypted_log_preimages_length);\n fields.push(self.unencrypted_log_preimages_length);\n fields.push_array(self.block_data.serialize());\n fields.push(self.contract_deployment_data.hash());\n fields.push(self.chain_id);\n fields.push(self.version);\n\n dep::std::hash::pedersen_with_separator(fields.storage, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS)[0]\n }\n\n fn serialize(self) -> [Field; PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH] {\n let mut fields: BoundedVec = BoundedVec::new(0); \n fields.push_array(self.call_context.serialize());\n fields.push(self.args_hash);\n fields.push_array(self.return_values);\n fields.push_array(self.read_requests);\n fields.push_array(self.new_commitments);\n fields.push_array(self.new_nullifiers);\n fields.push_array(self.private_call_stack);\n fields.push_array(self.public_call_stack);\n fields.push_array(self.new_l2_to_l1_msgs);\n fields.push_array(self.encrypted_logs_hash);\n fields.push_array(self.unencrypted_logs_hash);\n fields.push(self.encrypted_log_preimages_length);\n fields.push(self.unencrypted_log_preimages_length);\n fields.push_array(self.block_data.serialize());\n fields.push_array(self.contract_deployment_data.serialize());\n fields.push(self.chain_id);\n fields.push(self.version);\n fields.storage\n }\n}\n\nstruct ContractStorageRead {\n storage_slot: Field,\n value: Field,\n}\n\nimpl ContractStorageRead {\n fn serialize(self) -> [Field; CONTRACT_STORAGE_READ_LENGTH] {\n [self.storage_slot, self.value]\n }\n\n fn hash(self) -> Field {\n dep::std::hash::pedersen_with_separator(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_READ)[0]\n }\n\n fn empty() -> Self {\n Self { storage_slot: 0, value: 0 }\n }\n}\n\nstruct ContractStorageUpdateRequest {\n storage_slot: Field,\n old_value: Field,\n new_value: Field,\n}\n\nimpl ContractStorageUpdateRequest {\n fn serialize(self) -> [Field; CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH] {\n [self.storage_slot, self.old_value, self.new_value]\n }\n\n fn hash(self) -> Field {\n dep::std::hash::pedersen_with_separator(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST)[0]\n }\n\n fn empty() -> Self {\n Self { storage_slot: 0, old_value: 0, new_value: 0 }\n }\n}\n\n\nstruct PublicCircuitPublicInputs {\n call_context: CallContext,\n args_hash: Field,\n return_values: [Field; RETURN_VALUES_LENGTH],\n contract_storage_update_requests: [ContractStorageUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL],\n contract_storage_read: [ContractStorageRead; MAX_PUBLIC_DATA_READS_PER_CALL],\n public_call_stack: [Field; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL],\n new_commitments: [Field; MAX_NEW_COMMITMENTS_PER_CALL],\n new_nullifiers: [Field; crate::abi::MAX_NEW_NULLIFIERS_PER_CALL],\n new_l2_to_l1_msgs: [Field; crate::abi::MAX_NEW_L2_TO_L1_MSGS_PER_CALL],\n unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256],\n unencrypted_log_preimages_length: Field,\n block_data: HistoricBlockData,\n prover_address: Field,\n\n // TODO: include globals in here and check them elsewhere\n // https://github.com/AztecProtocol/aztec-packages/issues/1567\n}\n\nimpl PublicCircuitPublicInputs {\n \n fn hash(self) -> Field {\n let mut inputs: BoundedVec = BoundedVec::new(0);\n inputs.push(self.call_context.hash());\n inputs.push(self.args_hash);\n inputs.push_array(self.return_values);\n for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL {\n inputs.push(self.contract_storage_update_requests[i].hash());\n }\n for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL {\n inputs.push(self.contract_storage_read[i].hash());\n }\n inputs.push_array(self.public_call_stack);\n inputs.push_array(self.new_commitments);\n inputs.push_array(self.new_nullifiers);\n inputs.push_array(self.new_l2_to_l1_msgs);\n\n // We do not include block_data since it's not in the cpp hash\n\n inputs.push_array(self.unencrypted_logs_hash);\n inputs.push(self.unencrypted_log_preimages_length);\n inputs.push_array(self.block_data.serialize()); // see https://github.com/AztecProtocol/aztec-packages/issues/1473\n inputs.push(self.prover_address);\n\n dep::std::hash::pedersen_with_separator(inputs.storage, GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS)[0]\n }\n\n fn serialize(self) -> [Field; PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH] {\n let mut fields: BoundedVec = BoundedVec::new(0); \n fields.push_array(self.call_context.serialize()); \n fields.push(self.args_hash);\n fields.push_array(self.return_values);\n for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL {\n fields.push_array(self.contract_storage_update_requests[i].serialize());\n }\n for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL {\n fields.push_array(self.contract_storage_read[i].serialize());\n }\n fields.push_array(self.public_call_stack);\n fields.push_array(self.new_commitments);\n fields.push_array(self.new_nullifiers);\n fields.push_array(self.new_l2_to_l1_msgs);\n fields.push_array(self.unencrypted_logs_hash);\n fields.push(self.unencrypted_log_preimages_length);\n fields.push_array(self.block_data.serialize());\n fields.push(self.prover_address);\n fields.storage\n }\n}\n\nstruct Hasher {\n fields: [Field],\n}\n\nimpl Hasher {\n fn new()-> Self {\n Self { fields: [] }\n }\n\n fn add(&mut self, field: Field) {\n self.fields = self.fields.push_back(field);\n }\n\n fn add_multiple(&mut self, fields: [Field; N]) {\n for i in 0..N {\n self.fields = self.fields.push_back(fields[i]);\n }\n }\n\n fn hash(self) -> Field {\n hash_args(self.fields)\n }\n}\n\nglobal ARGS_HASH_CHUNK_LENGTH: u32 = 32;\nglobal ARGS_HASH_CHUNK_COUNT: u32 = 16;\n\nfn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];\n for i in 0..ARGS_HASH_CHUNK_COUNT {\n let mut chunk_hash = 0;\n let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH;\n if start_chunk_index < (args.len() as u32) {\n let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH];\n for j in 0..ARGS_HASH_CHUNK_LENGTH {\n let item_index = i * ARGS_HASH_CHUNK_LENGTH + j;\n if item_index < (args.len() as u32) {\n chunk_args[j] = args[item_index];\n }\n }\n chunk_hash = dep::std::hash::pedersen_with_separator(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS)[0];\n }\n chunks_hashes[i] = chunk_hash;\n }\n dep::std::hash::pedersen_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)[0]\n }\n}\n", + "path": "/Users/danlee/code/aztec-packages-2/yarn-project/aztec-nr/aztec/src/abi" + }, + "35": { + "source": "use dep::std::hash;\nuse crate::constants_gen::GENERATOR_INDEX__CONTRACT_ADDRESS;\n\nfn compute_address(pub_key_x: Field, pub_key_y: Field, partial_address: Field) -> Field {\n hash::pedersen_with_separator([pub_key_x, pub_key_y, partial_address], GENERATOR_INDEX__CONTRACT_ADDRESS)[0]\n}", + "path": "/Users/danlee/code/aztec-packages-2/yarn-project/aztec-nr/aztec/src/address" + }, + "59": { + "source": "use crate::types::point::Point;\nuse crate::address::compute_address;\n\n#[oracle(getPublicKey)]\nfn get_public_key_oracle(_address: Field) -> [Field; 3] {}\n\nunconstrained fn get_public_key_internal(address: Field) -> [Field; 3] {\n get_public_key_oracle(address)\n}\n\nfn get_public_key(address: Field) -> Point {\n let result = get_public_key_internal(address);\n let pub_key_x = result[0];\n let pub_key_y = result[1];\n let partial_address = result[2];\n \n let calculated_address = compute_address(pub_key_x, pub_key_y, partial_address);\n assert(calculated_address == address);\n \n Point::new(pub_key_x, pub_key_y)\n}\n", + "path": "/Users/danlee/code/aztec-packages-2/yarn-project/aztec-nr/aztec/src/oracle/get_public_key" + } + } + } +} diff --git a/yarn-project/boxes/blank/src/contracts/Nargo.toml b/yarn-project/boxes/blank/src/contracts/Nargo.toml new file mode 100644 index 00000000000..9cddcab43ee --- /dev/null +++ b/yarn-project/boxes/blank/src/contracts/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "blank" +authors = [""] +compiler_version = "0.1" +type = "contract" + +[dependencies] +aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/aztec-nr/aztec" } diff --git a/yarn-project/boxes/blank/src/contracts/src/interface.nr b/yarn-project/boxes/blank/src/contracts/src/interface.nr new file mode 100644 index 00000000000..56314a40a7f --- /dev/null +++ b/yarn-project/boxes/blank/src/contracts/src/interface.nr @@ -0,0 +1,51 @@ +/* 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 serialised_args = [0; 1]; + serialised_args[0] = address; + + context.call_private_function(self.address, 0x88f0753b, serialised_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/contracts/src/main.nr b/yarn-project/boxes/blank/src/contracts/src/main.nr new file mode 100644 index 00000000000..e72dca13135 --- /dev/null +++ b/yarn-project/boxes/blank/src/contracts/src/main.nr @@ -0,0 +1,20 @@ +contract Blank { + use dep::aztec::{ + abi, + oracle::{ + get_public_key::get_public_key, + }, + }; + + #[aztec(private)] + fn constructor() {} + + #[aztec(private)] + fn getPublicKey( + address: Field, + ) -> [Field; 2]{ + let pub_key = get_public_key(address); + + [pub_key.x, pub_key.y] + } +} diff --git a/yarn-project/boxes/blank/src/index.html b/yarn-project/boxes/blank/src/index.html new file mode 100644 index 00000000000..b5a876be4e8 --- /dev/null +++ b/yarn-project/boxes/blank/src/index.html @@ -0,0 +1,16 @@ + + + + + + + Minimal Noir Contract Webpack + + + + + + + + + \ No newline at end of file diff --git a/yarn-project/boxes/blank/src/index.ts b/yarn-project/boxes/blank/src/index.ts new file mode 100644 index 00000000000..18134a9ada4 --- /dev/null +++ b/yarn-project/boxes/blank/src/index.ts @@ -0,0 +1,144 @@ +import { + AccountWallet, + AztecAddress, + AztecRPC, + CompleteAddress, + Contract, + DeployMethod, + Fr, + createAztecRpcClient, + getSandboxAccountsWallets, +} from '@aztec/aztec.js'; +import { ContractAbi, FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; +import { BlankContractAbi } from './artifacts/blank.js'; +export const contractAbi: ContractAbi = BlankContractAbi; + +export const SANDBOX_URL: string = process.env.SANDBOX_URL || 'http://localhost:8080'; +export const rpcClient: AztecRPC = createAztecRpcClient(SANDBOX_URL); + +export const CONTRACT_ADDRESS_PARAM_NAMES = ['owner', 'contract_address', 'recipient']; +export const FILTERED_FUNCTION_NAMES = []; + +export const DEFAULT_PUBLIC_ADDRESS: string = '0x25048e8c1b7dea68053d597ac2d920637c99523651edfb123d0632da785970d0'; + +// interaction with the button + +let contractAddress: string = ''; +document.getElementById('deploy')?.addEventListener('click', async () => { + console.log('Deploying Contract'); + const [wallet, ..._rest] = await getSandboxAccountsWallets(rpcClient); + + const contractAztecAddress = await deployContract( + wallet.getCompleteAddress(), + contractAbi, + [], + Fr.random(), + rpcClient, + ); + contractAddress = contractAztecAddress.toString(); + console.log('Deploy Succeeded, contract deployed at', contractAddress); +}); + +document.getElementById('interact')?.addEventListener('click', async () => { + const [wallet, ..._rest] = await getSandboxAccountsWallets(rpcClient); + const callArgs = { address: wallet.getCompleteAddress().address }; + const getPkAbi = getFunctionAbi(BlankContractAbi, 'getPublicKey'); + const typedArgs = convertArgs(getPkAbi, callArgs); + console.log('Interacting with Contract'); + + const call = await callContractFunction( + AztecAddress.fromString(contractAddress), + contractAbi, + 'getPublicKey', + typedArgs, + rpcClient, + wallet.getCompleteAddress(), + ); + + console.log('Interaction transaction succeeded', call); +}); + +export const getFunctionAbi = (contractAbi: any, functionName: string) => { + const functionAbi = contractAbi.functions.find((f: FunctionAbi) => f.name === functionName); + if (!functionAbi) throw new Error(`Function ${functionName} not found in abi`); + return functionAbi; +}; + +export async function callContractFunction( + address: AztecAddress, + abi: ContractAbi, + functionName: string, + typedArgs: any[], // for the exposed functions, this is an array of field elements Fr[] + rpc: AztecRPC, + wallet: CompleteAddress, +) { + // selectedWallet is how we specify the "sender" of the transaction + const selectedWallet = await getWallet(wallet, rpc); + + // TODO: switch to the generated typescript class? + const contract = await Contract.at(address, abi, selectedWallet); + + const returnVal = await contract.methods[functionName](...typedArgs) + .send() + .wait(); + + if (returnVal.error) { + throw new Error(returnVal.error); + } + + return `Transaction (${returnVal.txHash}) ${returnVal.status} on block ${ + returnVal.blockNumber + } (hash ${returnVal.blockHash?.toString('hex')})!`; +} +/** + * terminology is confusing, but the `account` points to a smart contract's public key information + * while the "wallet" has the account's private key and is used to sign transactions + * we need the "wallet" to actually submit transactions using the "account" identity + * @param account + * @param rpc + * @returns + */ +export async function getWallet(account: CompleteAddress, rpc: AztecRPC): Promise { + const accountWallets: AccountWallet[] = await getSandboxAccountsWallets(rpc); + const selectedWallet: AccountWallet = accountWallets.find(w => w.getAddress().equals(account.address))!; + if (!selectedWallet) { + throw new Error(`Wallet for account ${account.address.toShortString()} not found in the RPC server.`); + } + return selectedWallet; +} + +export async function deployContract( + activeWallet: CompleteAddress, + contractAbi: ContractAbi, + typedArgs: Fr[], // encode prior to passing in + salt: Fr, + client: AztecRPC, +): Promise { + const tx = new DeployMethod(activeWallet.publicKey, client, contractAbi, typedArgs).send({ + contractAddressSalt: salt, + }); + await tx.wait(); + const receipt = await tx.getReceipt(); + if (receipt.contractAddress) { + return receipt.contractAddress; + } else { + throw new Error(`Contract not deployed (${receipt.toJSON()})`); + } +} + +export function convertArgs(functionAbi: FunctionAbi, args: any): Fr[] { + const untypedArgs = functionAbi.parameters.map(param => { + switch (param.type.kind) { + case 'field': + // hack: addresses are stored as string in the form to avoid bigint compatibility issues with formik + // convert those back to bigints before turning into Fr + return BigInt(args[param.name]); + default: + // they are all fields in the privatetoken contract, need more testing on other types + return args[param.name]; + } + }); + + const typedArgs = encodeArguments(functionAbi, untypedArgs); + return typedArgs; +} diff --git a/yarn-project/boxes/blank/src/tests/blank.contract.test.ts b/yarn-project/boxes/blank/src/tests/blank.contract.test.ts new file mode 100644 index 00000000000..4917153d4ae --- /dev/null +++ b/yarn-project/boxes/blank/src/tests/blank.contract.test.ts @@ -0,0 +1,70 @@ +import { + AccountWallet, + AztecAddress, + AztecRPC, + CompleteAddress, + Contract, + Fr, + Wallet, + createAztecRpcClient, + waitForSandbox, +} from '@aztec/aztec.js'; +import { createDebugLogger } from '@aztec/foundation/log'; +import { BlankContract } from '../artifacts/blank.js'; +import { callContractFunction, deployContract, getWallet, rpcClient } from '../index.js'; +const logger = createDebugLogger('aztec:blank-box-test'); + +// assumes sandbox is running locally, which this script does not trigger +// as well as anvil. anvil can be started with yarn test:integration +const setupSandbox = async () => { + const { SANDBOX_URL = 'http://localhost:8080' } = process.env; + const aztecRpc = createAztecRpcClient(SANDBOX_URL); + await waitForSandbox(aztecRpc); + return aztecRpc; +}; + +async function deployZKContract(owner: CompleteAddress, wallet: Wallet, rpcClient: AztecRPC) { + logger('Deploying Blank contract...'); + const contractAddress = await deployContract(owner, BlankContract.abi, [], Fr.random(), rpcClient); + + logger(`L2 contract deployed at ${contractAddress}`); + const contract = await BlankContract.at(contractAddress, wallet); + return contract; +} + +async function call(contractAddress: AztecAddress, testTokenContract: Contract, address: CompleteAddress) { + return await callContractFunction( + contractAddress, + testTokenContract.abi, + 'getPublicKey', + [address.address.toField()], + rpcClient, + address, + ); +} + +describe('ZK Contract Tests', () => { + let wallet: AccountWallet; + let owner: CompleteAddress; + let _account2: CompleteAddress; + let _account3: CompleteAddress; + let contract: Contract; + let contractAddress: AztecAddress; + let rpcClient: AztecRPC; + + beforeAll(async () => { + rpcClient = await setupSandbox(); + const accounts = await rpcClient.getRegisteredAccounts(); + [owner, _account2, _account3] = accounts; + + wallet = await getWallet(owner, rpcClient); + + contract = await deployZKContract(owner, wallet, rpcClient); + contractAddress = contract.address; + }, 60000); + + test('call succeeds after deploy', async () => { + const callTx = call(contractAddress, contract, owner); + await callTx; + }, 40000); +}); diff --git a/yarn-project/boxes/blank/tsconfig.dest.json b/yarn-project/boxes/blank/tsconfig.dest.json new file mode 100644 index 00000000000..6c11c57e0eb --- /dev/null +++ b/yarn-project/boxes/blank/tsconfig.dest.json @@ -0,0 +1,10 @@ +{ + "extends": ".", + "references": [ + { "path": "../../aztec.js" }, + { "path": "../../cli" }, + { "path": "../../foundation" }, + { "path": "../../types" } + ], + "exclude": ["src/**/*.test.ts"] +} diff --git a/yarn-project/boxes/blank/tsconfig.json b/yarn-project/boxes/blank/tsconfig.json new file mode 100644 index 00000000000..cc958d6c6f1 --- /dev/null +++ b/yarn-project/boxes/blank/tsconfig.json @@ -0,0 +1,46 @@ +{ + "compilerOptions": { + "rootDir": "src", + "outDir": "dest", + "tsBuildInfoFile": ".tsbuildinfo", + "target": "es2020", + "lib": [ + "esnext", + "dom", + "DOM.Iterable" + ], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "declaration": true, + "allowSyntheticDefaultImports": true, + "allowJs": true, + "esModuleInterop": true, + "downlevelIteration": true, + "inlineSourceMap": true, + "declarationMap": true, + "importHelpers": true, + "resolveJsonModule": true, + "composite": true, + "skipLibCheck": true, + "jsx": "react-jsx" + }, + "include": [ + "src", + "src/**/*.json" + ], + "references": [ + { + "path": "../../aztec.js" + }, + { + "path": "../../circuits.js" + }, + { + "path": "../../cli" + }, + { + "path": "../../foundation" + } + ] +} diff --git a/yarn-project/boxes/blank/webpack.config.js b/yarn-project/boxes/blank/webpack.config.js new file mode 100644 index 00000000000..642f8be612c --- /dev/null +++ b/yarn-project/boxes/blank/webpack.config.js @@ -0,0 +1,88 @@ +import CopyWebpackPlugin from 'copy-webpack-plugin'; +import { createRequire } from 'module'; +import { dirname, resolve } from 'path'; +import ResolveTypeScriptPlugin from 'resolve-typescript-plugin'; +import { fileURLToPath } from 'url'; +import webpack from 'webpack'; + +const require = createRequire(import.meta.url); + +export default (_, argv) => ({ + target: 'web', + mode: 'production', + devtool: false, + entry: { + main: './src/index.ts', + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: [ + { + loader: 'ts-loader', + options: { + configFile: 'tsconfig.dest.json', + }, + }, + ], + }, + ], + }, + output: { + path: resolve(dirname(fileURLToPath(import.meta.url)), './dest'), + filename: 'index.js', + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(argv.mode || 'production'), + }, + }), + new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), + new CopyWebpackPlugin({ + patterns: [ + { + from: `${dirname(require.resolve(`@aztec/circuits.js`)).replace( + /\/dest$/, + '', + )}/resources/aztec3-circuits.wasm`, + to: 'aztec3-circuits.wasm', + }, + { + from: './src/index.html', + to: 'index.html', + }, + ], + }), + ], + resolve: { + plugins: [new ResolveTypeScriptPlugin()], + alias: { + // All node specific code, wherever it's located, should be imported as below. + // Provides a clean and simple way to always strip out the node code for the web build. + './node/index.js': false, + }, + fallback: { + crypto: false, + os: false, + fs: false, + path: false, + url: false, + worker_threads: false, + events: require.resolve('events/'), + buffer: require.resolve('buffer/'), + util: require.resolve('util/'), + stream: require.resolve('stream-browserify'), + string_decoder: require.resolve('string_decoder/'), + tty: require.resolve('tty-browserify'), + }, + }, + devServer: { + port: 5173, + historyApiFallback: true, + client: { + overlay: false, + }, + }, +}); diff --git a/yarn-project/cli/src/unbox.ts b/yarn-project/cli/src/unbox.ts index 23c8d3695c0..7adef2931f8 100644 --- a/yarn-project/cli/src/unbox.ts +++ b/yarn-project/cli/src/unbox.ts @@ -17,18 +17,8 @@ import * as path from 'path'; const GITHUB_OWNER = 'AztecProtocol'; const GITHUB_REPO = 'aztec-packages'; const GITHUB_TAG_PREFIX = 'aztec-packages'; -const NOIR_CONTRACTS_PATH = 'yarn-project/noir-contracts/src/contracts'; const BOXES_PATH = 'yarn-project/boxes'; -/** - * Converts a contract name in "upper camel case" to a folder name in snake case or kebab case. - * @param contractName - The contract name. - * @returns The folder name. - * */ -function contractNameToFolder(contractName: string, separator = '-'): string { - return contractName.replace(/[\w]([A-Z])/g, m => `${m[0]}${separator}${m[1]}`).toLowerCase(); -} - /** * If the box contains the noir contract source code, we don't need to download it from github. * Otherwise, we download the contract source code from the `noir-contracts` and `noir-libs` subpackages. @@ -92,8 +82,7 @@ async function downloadContractAndBoxFromGithub( // small string conversion, in the ABI the contract name looks like PrivateToken // but in the repostory it looks like private_token - const kebabCaseContractName = contractNameToFolder(contractName, '-'); - log(`Downloading @aztex/boxes/${kebabCaseContractName} to ${outputPath}...`); + log(`Downloading @aztex/boxes/${contractName} to ${outputPath}...`); // Step 1: Fetch the monorepo ZIP from GitHub, matching the CLI version const url = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/archive/refs/tags/${tag}.zip`; const response = await fetch(url); @@ -103,40 +92,19 @@ async function downloadContractAndBoxFromGithub( const data = await zip.loadAsync(buffer); // Step 2: copy the '@aztec/boxes/{contract-name}' subpackage to the output directory - // this is currently only implemented for PrivateToken under 'boxes/private-token/' + // this is currently only implemented for `blank` and `private-token` under 'boxes/{box-name}/' const repoDirectoryPrefix = `${GITHUB_REPO}-${tag}`; - const boxPath = `${repoDirectoryPrefix}/${BOXES_PATH}/${kebabCaseContractName}`; + const boxPath = `${repoDirectoryPrefix}/${BOXES_PATH}/${contractName}`; await copyFolderFromGithub(data, boxPath, outputPath, log); const contractTargetDirectory = path.join(outputPath, 'src', 'contracts'); const boxContainsNoirSource = await isDirectoryNonEmpty(contractTargetDirectory); if (boxContainsNoirSource) { return; - } - - // this remaining logic only kicks in if the box doesn't already have a src/contracts folder - // in which case we optimistically grab the noir source files from the - // noir-contracts and noir-libs subpackages and pray that the versions are compatible - log('Copying noir contracts...'); - - // source noir files for the contract are in this folder - const snakeCaseContractName = contractNameToFolder(contractName, '_'); - const contractDirectoryPath = `${repoDirectoryPrefix}/${NOIR_CONTRACTS_PATH}/${snakeCaseContractName}_contract`; - // copy the noir contracts to the output directory under subdir /src/contracts/ - const contractFiles = Object.values(data.files).filter(file => { - return !file.dir && file.name.startsWith(contractDirectoryPath); - }); - - // Nargo.toml file needs to be in the root of the contracts directory, - // and noir files in the src/ subdirectory - await fs.mkdir(path.join(contractTargetDirectory, 'src'), { recursive: true }); - for (const file of contractFiles) { - const filename = file.name.replace(`${contractDirectoryPath}/`, ''); - const targetPath = path.join(contractTargetDirectory, filename); - const content = await file.async('nodebuffer'); - await fs.writeFile(targetPath, content); - log(` ✓ ${filename}`); + } else { + // we used to support downloading from the noir contracts monorepo but now force box to contain source code + throw Error(`Box ${contractName} does not contain noir source code.`); } } /** @@ -294,13 +262,13 @@ export async function unboxContract( packageVersion: string, log: LogFn, ) { - const contractNames = ['PrivateToken']; + const contractNames = ['private-token', 'blank']; if (!contractNames.includes(contractName)) { log( `The noir contract named "${contractName}" was not found in "@aztec/boxes" package. Valid options are: ${contractNames.join('\n\t')} - We recommend "PrivateToken" as a default.`, + We recommend "private-token" as a default.`, ); return; } diff --git a/yarn-project/package.json b/yarn-project/package.json index af3ab10b2a7..0c19a8527bb 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -21,7 +21,6 @@ "aztec-rpc", "aztec-sandbox", "aztec.js", - "boxes", "canary", "circuits.js", "cli", @@ -36,6 +35,7 @@ "l1-artifacts", "p2p", "p2p-bootstrap", + "boxes/blank", "boxes/private-token", "prover-client", "rollup-provider", diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 31b0b5239e8..487462b6f69 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -26,6 +26,7 @@ COPY aztec.js/package.json aztec.js/package.json COPY aztec.js/package.local.json aztec.js/package.local.json COPY canary/package.json canary/package.json COPY boxes/private-token/package.json boxes/private-token/package.json +COPY boxes/blank/package.json boxes/blank/package.json COPY docs/package.json docs/package.json COPY end-to-end/package.json end-to-end/package.json COPY ethereum/package.json ethereum/package.json diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index c6c912ba76f..e897b12cbf0 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -6846,6 +6846,37 @@ __metadata: languageName: node linkType: hard +"blank-contract@workspace:boxes/blank": + version: 0.0.0-use.local + resolution: "blank-contract@workspace:boxes/blank" + dependencies: + "@aztec/aztec-ui": ^0.1.14 + "@aztec/aztec.js": "workspace:^" + "@aztec/circuits.js": "workspace:^" + "@aztec/cli": "workspace:^" + "@aztec/foundation": "workspace:^" + "@typescript-eslint/eslint-plugin": ^6.0.0 + "@typescript-eslint/parser": ^6.0.0 + copy-webpack-plugin: ^11.0.0 + eslint: ^8.45.0 + eslint-import-resolver-typescript: ^3.5.5 + eslint-plugin-import: ^2.27.5 + jest: ^29.6.4 + prettier: ^3.0.3 + resolve-typescript-plugin: ^2.0.1 + serve: ^14.2.1 + stream-browserify: ^3.0.0 + ts-jest: ^29.1.1 + ts-loader: ^9.4.4 + ts-node: ^10.9.1 + tty-browserify: ^0.0.1 + typescript: ^5.0.4 + webpack: ^5.88.2 + webpack-cli: ^5.1.4 + webpack-dev-server: ^4.15.1 + languageName: unknown + linkType: soft + "bn.js@npm:4.11.8": version: 4.11.8 resolution: "bn.js@npm:4.11.8" @@ -17802,7 +17833,7 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^29.1.0": +"ts-jest@npm:^29.1.0, ts-jest@npm:^29.1.1": version: 29.1.1 resolution: "ts-jest@npm:29.1.1" dependencies: