diff --git a/yarn-project/boxes/private-token/package.json b/yarn-project/boxes/private-token/package.json index 730dcde145d..8dcf5c1afd8 100644 --- a/yarn-project/boxes/private-token/package.json +++ b/yarn-project/boxes/private-token/package.json @@ -65,10 +65,12 @@ "postcss-loader": "^7.3.3", "prettier": "^3.0.3", "resolve-typescript-plugin": "^2.0.1", + "stream-browserify": "^3.0.0", "style-loader": "^3.3.3", "ts-jest": "^29.1.0", "ts-loader": "^9.4.4", "ts-node": "^10.9.1", + "tty-browserify": "^0.0.1", "typescript": "^5.0.4", "util": "^0.12.5", "webpack": "^5.88.2", diff --git a/yarn-project/boxes/private-token/src/app/home.tsx b/yarn-project/boxes/private-token/src/app/home.tsx index 5eab48a1308..8f02be49e2e 100644 --- a/yarn-project/boxes/private-token/src/app/home.tsx +++ b/yarn-project/boxes/private-token/src/app/home.tsx @@ -1,5 +1,6 @@ import { CompleteAddress } from '@aztec/aztec.js'; import { useState } from 'react'; +import { SANDBOX_URL } from '../config.js'; import { Banner, Spinner } from './components/index.js'; import { WalletDropdown } from './components/wallet_dropdown.js'; import { Contract } from './contract.js'; @@ -48,13 +49,21 @@ export function Home() { )} - {!isLoadingWallet && !!selectedWallet && ( + {!isLoadingWallet && (
- {!!selectWalletError && `Failed to load accounts: ${selectWalletError}`} - {!selectWalletError && setIsContractDeployed(true)}/>} + {!!selectWalletError && ( + <> + {`Failed to load accounts. Error: ${selectWalletError}`} +
+ {`Make sure the Aztec Sandbox is running at: ${SANDBOX_URL}`} + + )} + {!selectWalletError && !selectedWallet && `No accounts.`} + {!selectWalletError && !!selectedWallet && ( + setIsContractDeployed(true)} /> + )}
)} - {!isLoadingWallet && !selectedWallet && `${selectWalletError} ${selectedWallet}`} diff --git a/yarn-project/boxes/private-token/src/config.ts b/yarn-project/boxes/private-token/src/config.ts index 264052da3a4..6d6e7ffcf2c 100644 --- a/yarn-project/boxes/private-token/src/config.ts +++ b/yarn-project/boxes/private-token/src/config.ts @@ -4,7 +4,7 @@ import { PrivateTokenContractAbi } from './artifacts/PrivateToken.js'; // update export const contractAbi: ContractAbi = PrivateTokenContractAbi; -const SANDBOX_URL: string = process.env.SANDBOX_URL || 'http://localhost:8080'; +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']; diff --git a/yarn-project/cli/src/unbox.ts b/yarn-project/cli/src/unbox.ts index 4202b080db6..d14911a0406 100644 --- a/yarn-project/cli/src/unbox.ts +++ b/yarn-project/cli/src/unbox.ts @@ -20,12 +20,12 @@ 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. + * 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): string { - return contractName.replace(/[\w]([A-Z])/g, m => m[0] + '_' + m[1]).toLowerCase(); +function contractNameToFolder(contractName: string, separator = '-'): string { + return contractName.replace(/[\w]([A-Z])/g, m => `${m[0]}${separator}${m[1]}`).toLowerCase(); } /** @@ -33,8 +33,13 @@ function contractNameToFolder(contractName: string): string { * Otherwise, we download the contract source code from the `noir-contracts` and `noir-libs` subpackages. */ async function isDirectoryNonEmpty(directoryPath: string): Promise { - const files = await fs.readdir(directoryPath); - return files.length > 0; + try { + const files = await fs.readdir(directoryPath); + return files.length > 0; + } catch (e) { + // Directory does not exist. + return false; + } } /** @@ -44,7 +49,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 from github: ${repositoryFolderPath}`); const repositoryDirectories = Object.values(data.files).filter(file => { return file.dir && file.name.startsWith(repositoryFolderPath); }); @@ -83,13 +88,14 @@ async function downloadContractAndBoxFromGithub( outputPath: string, log: LogFn, ): Promise { + const tagName = `aztec-packages-v${tagVersion}`; // small string conversion, in the ABI the contract name looks like PrivateToken // but in the repostory it looks like private_token - const snakeCaseContractName = contractNameToFolder(contractName); - log(`Downloaded '@aztex/boxes/${snakeCaseContractName}' to ${outputPath}`); + const kebabCaseContractName = contractNameToFolder(contractName, '-'); + log(`Downloading @aztex/boxes/${kebabCaseContractName} 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/aztec-packages-v${tagVersion}.zip`; + const url = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/archive/refs/tags/${tagName}.zip`; const response = await fetch(url); const buffer = await response.arrayBuffer(); @@ -98,39 +104,39 @@ async function downloadContractAndBoxFromGithub( // Step 2: copy the '@aztec/boxes/{contract-name}' subpackage to the output directory // this is currently only implemented for PrivateToken under 'boxes/private-token/' - const repoDirectoryPrefix = `${GITHUB_REPO}-v${tagVersion}/`; + const repoDirectoryPrefix = `${GITHUB_REPO}-${tagName}`; - const boxPath = `${repoDirectoryPrefix}${BOXES_PATH}/${snakeCaseContractName}`; + const boxPath = `${repoDirectoryPrefix}/${BOXES_PATH}/${kebabCaseContractName}`; await copyFolderFromGithub(data, boxPath, outputPath, log); - const boxContainsNoirSource = await isDirectoryNonEmpty(`${outputPath}/src/contracts`); + 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 contractFolder = `${NOIR_CONTRACTS_PATH}/${snakeCaseContractName}_contract`; + 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 contractDirectoryPath = `${repoDirectoryPrefix}${contractFolder}/`; - const contractFiles = Object.values(data.files).filter(file => { return !file.dir && file.name.startsWith(contractDirectoryPath); }); - const contractTargetDirectory = path.join(outputPath, 'src', 'contracts'); - await fs.mkdir(contractTargetDirectory, { recursive: true }); // 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 targetPath = path.join(contractTargetDirectory, file.name.replace(contractDirectoryPath, '')); - log(`Copying ${file.name} to ${targetPath}`); + const filename = file.name.replace(`${contractDirectoryPath}/`, ''); + const targetPath = path.join(contractTargetDirectory, filename); const content = await file.async('nodebuffer'); await fs.writeFile(targetPath, content); - log(`Copied ${file.name} to ${targetPath}`); + log(` ✓ ${filename}`); } } /** @@ -143,7 +149,8 @@ async function downloadContractAndBoxFromGithub( */ async function updatePackagingConfigurations(packageVersion: string, outputPath: string, log: LogFn): Promise { await updatePackageJsonVersions(packageVersion, outputPath, log); - await updateTsConfig(outputPath, log); + await updateTsConfig('tsconfig.json', outputPath, log); + await updateTsConfig('tsconfig.dest.json', outputPath, log); await updateNargoToml(packageVersion, outputPath, log); } @@ -160,7 +167,7 @@ async function updateNargoToml(packageVersion: string, outputPath: string, log: const updatedLines = lines.map(line => line.replace(/tag="master"/g, `tag="v${packageVersion}"`)); const updatedContent = updatedLines.join('\n'); await fs.writeFile(nargoTomlPath, updatedContent); - log(`Updated Nargo.toml to point to local copy of noir-libs`); + log(`Updated Nargo.toml to point to local copy of noir-libs.`); } /** @@ -169,9 +176,9 @@ async function updateNargoToml(packageVersion: string, outputPath: string, log: * so we remove the entries to install the the workspace packages from npm. * @param outputPath - directory we are unboxing to */ -async function updateTsConfig(outputPath: string, log: LogFn) { +async function updateTsConfig(filename: string, outputPath: string, log: LogFn) { try { - const tsconfigJsonPath = path.join(outputPath, 'tsconfig.json'); + const tsconfigJsonPath = path.join(outputPath, filename); const data = await fs.readFile(tsconfigJsonPath, 'utf8'); const config = JSON.parse(data); @@ -180,9 +187,9 @@ async function updateTsConfig(outputPath: string, log: LogFn) { const updatedData = JSON.stringify(config, null, 2); await fs.writeFile(tsconfigJsonPath, updatedData, 'utf8'); - log('tsconfig.json has been updated'); + log(`Updated ${filename}.`); } catch (error) { - log('Error updating tsconfig.json:', error); + log(`Error updating ${filename}.`); throw error; } } @@ -234,7 +241,7 @@ async function updatePackageJsonVersions(packageVersion: string, outputPath: str const updatedContent = JSON.stringify(packageData, null, 2); await fs.writeFile(packageJsonPath, updatedContent); - log(`Updated package.json versions to ${packageVersion}`); + log(`Updated package.json versions to: ${packageVersion}`); } /** diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 375e0596fac..aadefe3e600 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -12516,11 +12516,13 @@ __metadata: react-dom: ^18.2.0 resolve-typescript-plugin: ^2.0.1 serve: ^14.2.1 + stream-browserify: ^3.0.0 style-loader: ^3.3.3 tailwindcss: ^3.3.3 ts-jest: ^29.1.0 ts-loader: ^9.4.4 ts-node: ^10.9.1 + tty-browserify: ^0.0.1 typescript: ^5.0.4 util: ^0.12.5 webpack: ^5.88.2