From 75549f090170c237a3d707f9027f33ed1d2cef61 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 23 Mar 2023 00:23:49 +0000 Subject: [PATCH 1/3] Add ContractDeployer. --- yarn-project/aztec.js/.eslintrc.cjs | 15 ++ yarn-project/aztec.js/package.json | 2 + .../aztec.js/src/abi_coder/hex_string.ts | 3 + yarn-project/aztec.js/src/abi_coder/index.ts | 24 +++ .../aztec.js/src/abi_coder/keccak256.ts | 7 + .../aztec.js/src/aztec_rpc/circuit_js.ts | 191 ++++++++++++++++++ yarn-project/aztec.js/src/aztec_rpc/index.ts | 33 +++ .../src/contract/constructor_interaction.ts | 53 +++++ .../src/contract/contract_function.ts | 14 ++ yarn-project/aztec.js/src/contract/index.ts | 2 + .../src/contract/send_method_interaction.ts | 73 +++++++ yarn-project/aztec.js/src/contract/sent_tx.ts | 22 ++ .../contract_deployer.test.ts | 125 ++++++++++++ .../contract_deployer/contract_deployer.ts | 14 ++ .../aztec.js/src/contract_deployer/index.ts | 1 + yarn-project/aztec.js/src/foundation/index.ts | 69 +++++++ yarn-project/aztec.js/src/index.test.ts | 7 - yarn-project/aztec.js/src/index.ts | 6 +- yarn-project/aztec.js/src/noir_js/index.ts | 131 ++++++++++++ yarn-project/yarn.lock | 4 +- 20 files changed, 784 insertions(+), 12 deletions(-) create mode 100644 yarn-project/aztec.js/src/abi_coder/hex_string.ts create mode 100644 yarn-project/aztec.js/src/abi_coder/index.ts create mode 100644 yarn-project/aztec.js/src/abi_coder/keccak256.ts create mode 100644 yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts create mode 100644 yarn-project/aztec.js/src/aztec_rpc/index.ts create mode 100644 yarn-project/aztec.js/src/contract/constructor_interaction.ts create mode 100644 yarn-project/aztec.js/src/contract/contract_function.ts create mode 100644 yarn-project/aztec.js/src/contract/index.ts create mode 100644 yarn-project/aztec.js/src/contract/send_method_interaction.ts create mode 100644 yarn-project/aztec.js/src/contract/sent_tx.ts create mode 100644 yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts create mode 100644 yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts create mode 100644 yarn-project/aztec.js/src/contract_deployer/index.ts create mode 100644 yarn-project/aztec.js/src/foundation/index.ts delete mode 100644 yarn-project/aztec.js/src/index.test.ts create mode 100644 yarn-project/aztec.js/src/noir_js/index.ts diff --git a/yarn-project/aztec.js/.eslintrc.cjs b/yarn-project/aztec.js/.eslintrc.cjs index 9cf806b1500f..333ff38eab81 100644 --- a/yarn-project/aztec.js/.eslintrc.cjs +++ b/yarn-project/aztec.js/.eslintrc.cjs @@ -3,4 +3,19 @@ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@aztec/eslint-config'], parserOptions: { tsconfigRootDir: __dirname }, + rules: { + 'tsdoc/syntax': 'off', + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-description': 'off', + 'jsdoc/require-description-complete-sentence': 'off', + 'jsdoc/require-hyphen-before-param-description': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-param-name': 'off', + 'jsdoc/require-property': 'off', + 'jsdoc/require-property-description': 'off', + 'jsdoc/require-property-name': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-returns-description': 'off', + }, }; diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 988056465c37..88e6b75298d7 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -29,6 +29,7 @@ "rootDir": "./src" }, "dependencies": { + "sha3": "^2.1.4", "tslib": "^2.4.0" }, "devDependencies": { @@ -38,6 +39,7 @@ "@types/jest": "^29.4.0", "@types/node": "^18.7.23", "jest": "^28.1.3", + "jest-mock-extended": "^3.0.3", "ts-jest": "^28.0.7", "ts-node": "^10.9.1", "typescript": "^4.9.5" diff --git a/yarn-project/aztec.js/src/abi_coder/hex_string.ts b/yarn-project/aztec.js/src/abi_coder/hex_string.ts new file mode 100644 index 000000000000..fd6eb9ebe385 --- /dev/null +++ b/yarn-project/aztec.js/src/abi_coder/hex_string.ts @@ -0,0 +1,3 @@ +export function hexToBuffer(h: string) { + return Buffer.from((h.length % 2 ? '0' : '') + h.replace(/^0x/, ''), 'hex'); +} diff --git a/yarn-project/aztec.js/src/abi_coder/index.ts b/yarn-project/aztec.js/src/abi_coder/index.ts new file mode 100644 index 000000000000..b425716b52e8 --- /dev/null +++ b/yarn-project/aztec.js/src/abi_coder/index.ts @@ -0,0 +1,24 @@ +import { ABIParameter } from '../noir_js/index.js'; +import { keccak256 } from './keccak256.js'; + +export * from './hex_string.js'; + +function pack(parameter: ABIParameter, value: any) { + return Buffer.alloc(32); +} + +export function generateFunctionSignature(name: string, parameters: ABIParameter[]) { + return `${name}(${parameters.map(p => p.type.kind).join(',')})`; +} + +export function encodeFunctionSignature(signature: string) { + return keccak256(Buffer.from(signature)).slice(0, 4); +} + +export function encodeParameters(parameters: ABIParameter[], args: any[]) { + if (parameters.length !== args.length) { + throw new Error(`Incorrect number of args. Expect ${parameters.length}. Got ${args.length}.`); + } + + return parameters.map((p, i) => pack(p, args[i])); +} diff --git a/yarn-project/aztec.js/src/abi_coder/keccak256.ts b/yarn-project/aztec.js/src/abi_coder/keccak256.ts new file mode 100644 index 000000000000..b03ac89ead4a --- /dev/null +++ b/yarn-project/aztec.js/src/abi_coder/keccak256.ts @@ -0,0 +1,7 @@ +import { Keccak } from 'sha3'; + +export function keccak256(input: Buffer | string) { + const inputBuf = typeof input === 'string' ? Buffer.from(input) : input; + const hash = new Keccak(256); + return hash.update(inputBuf).digest(); +} diff --git a/yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts b/yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts new file mode 100644 index 000000000000..15e236c3e18f --- /dev/null +++ b/yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts @@ -0,0 +1,191 @@ +import { randomBytes } from '../foundation/index.js'; + +/** + * A named type. + */ +export interface ABIVariable { + /** + * The name of the variable. + */ + name: string; + /** + * The type of the variable. + */ + type: ABIType; +} + +/** + * A function parameter. + */ +export interface ABIParameter extends ABIVariable { + /** + * Whether the parameter is unpacked. + */ + unpacked: boolean; +} + +/** + * A basic type. + */ +export interface BasicType { + /** + * The kind of the type. + */ + kind: T; +} + +/** + * A variable type. + */ +export type ABIType = BasicType<'field'> | BasicType<'boolean'> | IntegerType | ArrayType | StringType | StructType; + +/** + * An integer type. + */ +export interface IntegerType extends BasicType<'integer'> { + /** + * The sign of the integer. + */ + sign: string; + /** + * The width of the integer in bits. + */ + width: number; +} + +/** + * An array type. + */ +export interface ArrayType extends BasicType<'array'> { + /** + * The length of the array. + */ + length: number; + /** + * The type of the array elements. + */ + type: ABIType; +} + +/** + * A string type. + */ +export interface StringType extends BasicType<'string'> { + /** + * The length of the string. + */ + length: number; +} + +/** + * A struct type. + */ +export interface StructType extends BasicType<'struct'> { + /** + * The fields of the struct. + */ + fields: ABIVariable[]; +} + +/** + * The ABI entry of a function. + */ +export interface FunctionAbi { + /** + * The name of the function. + */ + name: string; + /** + * Whether the function is a constructor. + */ + isConstructor: boolean; + /** + * Whether the function is secret. + */ + isSecret: boolean; + /** + * Function parameters. + */ + parameters: ABIParameter[]; + /** + * The types of the return values. + */ + returnTypes: ABIType[]; + /** + * The ACIR bytecode of the function. + */ + bytecode: string; + /** + * The verification key of the function. + */ + verificationKey: string; +} + +export class Fr { + public static ZERO = new Fr(Buffer.alloc(32)); + + public static random() { + return new Fr(randomBytes(32)); + } + + constructor(public readonly buffer: Buffer) {} +} + +export class EthAddress { + public static ZERO = new EthAddress(Buffer.alloc(20)); + + public static random() { + return new EthAddress(randomBytes(20)); + } + + constructor(public readonly buffer: Buffer) {} +} + +export class AztecAddress { + public static ZERO = new AztecAddress(Buffer.alloc(32)); + + public static random() { + return new AztecAddress(randomBytes(32)); + } + + constructor(public readonly buffer: Buffer) {} +} + +export class Signature {} + +export class TxHash {} + +export interface FunctionData { + functionEncoding: number; + isPrivate: boolean; + isContructor: boolean; +} + +export interface ContractDeploymentData { + contractDataHash: Fr; + functionTreeRoot: Fr; + constructorHash: Fr; + contractAddressSalt: Fr; + portalContractAddress: Fr; +} + +export interface TxContext { + isFeePaymentTx: boolean; + isRebatePaymentTx: boolean; + isContractDeploymentTx: boolean; + contractDeploymentData: ContractDeploymentData; +} + +export interface TxRequest { + from: AztecAddress; + to?: AztecAddress; + functionData: FunctionData; + args: Fr[]; + txContext: TxContext; + nonce: Fr; + chainId: Fr; +} + +export interface Tx { + proofData: Buffer; +} diff --git a/yarn-project/aztec.js/src/aztec_rpc/index.ts b/yarn-project/aztec.js/src/aztec_rpc/index.ts new file mode 100644 index 000000000000..ca9ed561ce44 --- /dev/null +++ b/yarn-project/aztec.js/src/aztec_rpc/index.ts @@ -0,0 +1,33 @@ +import { AztecAddress, EthAddress, Fr, Signature, Tx, TxHash, TxRequest } from './circuit_js.js'; + +export * from './circuit_js.js'; + +export interface TxReceipt { + txHash: TxHash; + // txIndex: number; + blockHash: Buffer; + blockNumber: number; + from: AztecAddress; + to?: AztecAddress; + contractAddress?: AztecAddress; + status: boolean; +} + +export interface AztecRPCClient { + addAccount(): Promise; + getAccounts(): Promise; + getCode(contract: AztecAddress): Promise; + createDeploymentTxRequest( + bytecode: Buffer, + args: Fr[], + portalContract: EthAddress, + contractAddressSalt: Fr, + from: AztecAddress, + ): Promise; + createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; + signTxRequest(txRequest: TxRequest): Promise; + createTx(txRequest: TxRequest, signature: Signature): Promise; + sendTx(tx: Tx): Promise; + // callTx(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; + getTxReceipt(txHash: TxHash): Promise; +} diff --git a/yarn-project/aztec.js/src/contract/constructor_interaction.ts b/yarn-project/aztec.js/src/contract/constructor_interaction.ts new file mode 100644 index 000000000000..7bb87b70ee19 --- /dev/null +++ b/yarn-project/aztec.js/src/contract/constructor_interaction.ts @@ -0,0 +1,53 @@ +import { hexToBuffer } from '../abi_coder/index.js'; +import { AztecAddress, AztecRPCClient, EthAddress, Fr } from '../aztec_rpc/index.js'; +import { ContractAbi } from '../noir_js/index.js'; +import { ContractFunction } from './contract_function.js'; +import { SendMethodOptions, SendMethodInteraction } from './send_method_interaction.js'; + +export interface ConstructorOptions extends SendMethodOptions { + contractAddressSalt?: Fr; +} + +/** + * Extends the SendMethodInteraction to create TxRequest for constructors (deployments). + */ +export class ConstructorInteraction extends SendMethodInteraction { + constructor( + arc: AztecRPCClient, + private abi: ContractAbi, + private portalContract: EthAddress, + args: any[], + defaultOptions: ConstructorOptions = {}, + ) { + const constructorAbi = abi.functions.find(f => f.name === 'constructor'); + if (!constructorAbi) { + throw new Error('Cannot find constructor in the ABI.'); + } + + super(arc, EthAddress.ZERO, new ContractFunction(constructorAbi), args, defaultOptions); + } + + public async request(options: ConstructorOptions = {}) { + const { contractAddressSalt, from } = { ...this.defaultOptions, ...options }; + this.txRequest = await this.arc.createDeploymentTxRequest( + hexToBuffer(this.abi.bytecode), + this.entry.encodeParameters(this.args).map(p => new Fr(p)), + this.portalContract, + contractAddressSalt || Fr.random(), + from || AztecAddress.ZERO, + ); + return this.txRequest; + } + + public sign(options: ConstructorOptions = {}) { + return super.sign(options); + } + + public create(options: ConstructorOptions = {}) { + return super.create(options); + } + + public send(options: ConstructorOptions = {}) { + return super.send(options); + } +} diff --git a/yarn-project/aztec.js/src/contract/contract_function.ts b/yarn-project/aztec.js/src/contract/contract_function.ts new file mode 100644 index 000000000000..1b8ca701402b --- /dev/null +++ b/yarn-project/aztec.js/src/contract/contract_function.ts @@ -0,0 +1,14 @@ +import { encodeFunctionSignature, encodeParameters, generateFunctionSignature } from '../abi_coder/index.js'; +import { FunctionAbi } from '../noir_js/index.js'; + +export class ContractFunction { + constructor(private abi: FunctionAbi) {} + + public encodeABI() { + return encodeFunctionSignature(generateFunctionSignature(this.abi.name, this.abi.parameters)); + } + + public encodeParameters(args: any[]) { + return encodeParameters(this.abi.parameters, args); + } +} diff --git a/yarn-project/aztec.js/src/contract/index.ts b/yarn-project/aztec.js/src/contract/index.ts new file mode 100644 index 000000000000..4785219e0f78 --- /dev/null +++ b/yarn-project/aztec.js/src/contract/index.ts @@ -0,0 +1,2 @@ +export * from './constructor_interaction.js'; +export * from './send_method_interaction.js'; diff --git a/yarn-project/aztec.js/src/contract/send_method_interaction.ts b/yarn-project/aztec.js/src/contract/send_method_interaction.ts new file mode 100644 index 000000000000..6fd2366fd94b --- /dev/null +++ b/yarn-project/aztec.js/src/contract/send_method_interaction.ts @@ -0,0 +1,73 @@ +import { AztecAddress, AztecRPCClient, Fr, Signature, Tx, TxHash, TxRequest } from '../aztec_rpc/index.js'; +import { ContractFunction } from './contract_function.js'; +import { SentTx } from './sent_tx.js'; + +export interface SendMethodOptions { + from?: AztecAddress; + nonce?: Fr; +} + +/** + * This is the class that is returned when calling e.g. `contract.methods.myMethod(arg0, arg1)`. + * It contains available interactions one can call on a `send` method. + */ +export class SendMethodInteraction { + protected txRequest?: TxRequest; + private signature?: Signature; + private tx?: Tx; + + constructor( + protected arc: AztecRPCClient, + protected contractAddress: AztecAddress, + protected entry: ContractFunction, + protected args: any[], + protected defaultOptions: SendMethodOptions = {}, + ) {} + + public async request(options: SendMethodOptions = {}) { + const { from } = { ...this.defaultOptions, ...options }; + this.txRequest = await this.arc.createTxRequest( + this.entry.encodeABI(), + this.entry.encodeParameters(this.args).map(p => new Fr(p)), + this.contractAddress, + from || AztecAddress.ZERO, + ); + return this.txRequest; + } + + public async sign(options: SendMethodOptions = {}) { + if (!this.txRequest) { + await this.request(options); + } + + this.signature = await this.arc.signTxRequest(this.txRequest!); + return this.signature; + } + + public async create(options: SendMethodOptions = {}) { + if (!this.signature) { + await this.sign(options); + } + + this.tx = await this.arc.createTx(this.txRequest!, this.signature!); + return this.tx; + } + + public send(options: SendMethodOptions = {}) { + let promise: Promise; + if (this.tx) { + promise = this.arc.sendTx(this.tx); + } else { + promise = (async () => { + await this.create(options); + return this.arc.sendTx(this.tx!); + })(); + } + + return new SentTx(this.arc, promise); + } + + public encodeABI() { + return this.entry.encodeABI(); + } +} diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts new file mode 100644 index 000000000000..8771eb86dab1 --- /dev/null +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -0,0 +1,22 @@ +import { AztecRPCClient, TxHash, TxReceipt } from '../aztec_rpc/index.js'; +import { retryUntil } from '../foundation/index.js'; + +export class SentTx { + private receipt?: TxReceipt; + + constructor(private arc: AztecRPCClient, private txHashPromise: Promise) {} + + public async getTxHash() { + return await this.txHashPromise; + } + + public async getReceipt(timeout = 0, interval = 1) { + if (this.receipt) { + return this.receipt; + } + + const txHash = await this.getTxHash(); + this.receipt = await retryUntil(() => this.arc.getTxReceipt(txHash), 'getReceipt', timeout, interval); + return this.receipt; + } +} diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts new file mode 100644 index 000000000000..ec67f5929ddc --- /dev/null +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts @@ -0,0 +1,125 @@ +import { mock } from 'jest-mock-extended'; +import { + AztecAddress, + AztecRPCClient, + EthAddress, + Fr, + Signature, + Tx, + TxHash, + TxReceipt, + TxRequest, +} from '../aztec_rpc/index.js'; +import { ContractAbi } from '../noir_js/index.js'; +import { ContractDeployer } from './contract_deployer.js'; + +describe('Contract Deployer', () => { + let arc: ReturnType>; + + const bytecodeBuf = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]); + const abi: ContractAbi = { + functions: [ + { + name: 'constructor', + isSecret: true, + parameters: [], + returnTypes: [], + verificationKey: '0x98765432', + }, + ], + bytecode: `0x${bytecodeBuf.toString('hex')}`, + }; + + const portalContract = EthAddress.random(); + const contractAddressSalt = Fr.random(); + const account = AztecAddress.random(); + + const mockTxRequest = { type: 'TxRequest' } as any as TxRequest; + const mockSignature = { type: 'Signature' } as any as Signature; + const mockTx = { type: 'Tx' } as any as Tx; + const mockTxHash = { type: 'TxHash' } as any as TxHash; + const mockTxReceipt = { type: 'TxReceipt' } as any as TxReceipt; + + beforeEach(() => { + arc = mock(); + arc.createDeploymentTxRequest.mockResolvedValue(mockTxRequest); + arc.createTxRequest.mockResolvedValue(mockTxRequest); + arc.signTxRequest.mockResolvedValue(mockSignature); + arc.createTx.mockResolvedValue(mockTx); + arc.sendTx.mockResolvedValue(mockTxHash); + arc.getTxReceipt.mockResolvedValue(mockTxReceipt); + }); + + it('should request, sign, craete and send a contract deployment tx', async () => { + const deployer = new ContractDeployer(abi, arc); + const sentTx = deployer.deploy(portalContract).send({ + contractAddressSalt, + from: account, + }); + const txHash = await sentTx.getTxHash(); + const receipt = await sentTx.getReceipt(); + + expect(txHash).toBe(mockTxHash); + expect(receipt).toBe(mockTxReceipt); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledTimes(1); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( + bytecodeBuf, + [], + portalContract, + contractAddressSalt, + account, + ); + expect(arc.createTxRequest).toHaveBeenCalledTimes(0); + expect(arc.signTxRequest).toHaveBeenCalledTimes(1); + expect(arc.signTxRequest).toHaveBeenCalledWith(mockTxRequest); + expect(arc.createTx).toHaveBeenCalledTimes(1); + expect(arc.createTx).toHaveBeenCalledWith(mockTxRequest, mockSignature); + expect(arc.sendTx).toHaveBeenCalledTimes(1); + expect(arc.sendTx).toHaveBeenCalledWith(mockTx); + }); + + it('should be able to deploy a contract step by step', async () => { + const deployer = new ContractDeployer(abi, arc); + const deployment = deployer.deploy(portalContract); + const txRequest = await deployment.request({ + contractAddressSalt, + from: account, + }); + const signature = await deployment.sign(); + const tx = await deployment.create(); + const receipt = await deployment.send().getReceipt(); + + expect(txRequest).toBe(mockTxRequest); + expect(signature).toBe(mockSignature); + expect(tx).toBe(mockTx); + expect(receipt).toBe(mockTxReceipt); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledTimes(1); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( + bytecodeBuf, + [], + portalContract, + contractAddressSalt, + account, + ); + expect(arc.createTxRequest).toHaveBeenCalledTimes(0); + expect(arc.signTxRequest).toHaveBeenCalledTimes(1); + expect(arc.createTx).toHaveBeenCalledTimes(1); + expect(arc.sendTx).toHaveBeenCalledTimes(1); + }); + + it('should assign zeros or generate random values for undefined options', async () => { + const deployer = new ContractDeployer(abi, arc); + const deployment = deployer.deploy(); + await deployment.request(); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( + bytecodeBuf, + [], + EthAddress.ZERO, // portalContract + expect.anything(), // contractAddressSalt + AztecAddress.ZERO, // account + ); + const defaultContractAddressSalt = arc.createDeploymentTxRequest.mock.calls[0][3]; + expect(defaultContractAddressSalt).not.toEqual(contractAddressSalt); + expect(defaultContractAddressSalt).not.toEqual(Fr.ZERO); + }); +}); diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts new file mode 100644 index 000000000000..f0912dbc147a --- /dev/null +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts @@ -0,0 +1,14 @@ +import { AztecRPCClient, EthAddress } from '../aztec_rpc/index.js'; +import { ConstructorInteraction, ConstructorOptions } from '../contract/index.js'; +import { ContractAbi } from '../noir_js/index.js'; + +/** + * A class for deploying contract. + */ +export class ContractDeployer { + constructor(private abi: ContractAbi, private arc: AztecRPCClient, private defaultOptions: ConstructorOptions = {}) {} + + public deploy(portalContract = EthAddress.ZERO, ...args: any[]) { + return new ConstructorInteraction(this.arc, this.abi, portalContract, args, this.defaultOptions); + } +} diff --git a/yarn-project/aztec.js/src/contract_deployer/index.ts b/yarn-project/aztec.js/src/contract_deployer/index.ts new file mode 100644 index 000000000000..587eeb108ce7 --- /dev/null +++ b/yarn-project/aztec.js/src/contract_deployer/index.ts @@ -0,0 +1 @@ +export * from './contract_deployer.js'; diff --git a/yarn-project/aztec.js/src/foundation/index.ts b/yarn-project/aztec.js/src/foundation/index.ts new file mode 100644 index 000000000000..6fe59e071b0a --- /dev/null +++ b/yarn-project/aztec.js/src/foundation/index.ts @@ -0,0 +1,69 @@ +import nodeCrypto from 'crypto'; + +export const randomBytes = (len: number) => { + return nodeCrypto.randomBytes(len) as Buffer; +}; + +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export class Timer { + private start: number; + + constructor() { + this.start = new Date().getTime(); + } + + public ms() { + return new Date().getTime() - this.start; + } + + public s() { + return (new Date().getTime() - this.start) / 1000; + } +} + +export function* backoffGenerator() { + const v = [1, 1, 1, 2, 4, 8, 16, 32, 64]; + let i = 0; + while (true) { + yield v[Math.min(i++, v.length - 1)]; + } +} + +export async function retry(fn: () => Promise, name = 'Operation', backoff = backoffGenerator()) { + while (true) { + try { + return await fn(); + } catch (err: any) { + const s = backoff.next().value; + if (s === undefined) { + throw err; + } + console.log(`${name} failed. Will retry in ${s}s...`); + console.log(err); + await sleep(s * 1000); + continue; + } + } +} + +// Call `fn` repeatedly until it returns true or timeout. +// Both `interval` and `timeout` are seconds. +// Will never timeout if the value is 0. +export async function retryUntil(fn: () => Promise, name = '', timeout = 0, interval = 1) { + const timer = new Timer(); + while (true) { + const result = await fn(); + if (result) { + return result; + } + + await sleep(interval * 1000); + + if (timeout && timer.s() > timeout) { + throw new Error(name ? `Timeout awaiting ${name}` : 'Timeout'); + } + } +} diff --git a/yarn-project/aztec.js/src/index.test.ts b/yarn-project/aztec.js/src/index.test.ts deleted file mode 100644 index ce33cfbe10c7..000000000000 --- a/yarn-project/aztec.js/src/index.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Aztec } from './index.js'; - -describe('Aztec', () => { - it('Initialise Aztec', () => { - expect(() => new Aztec()).not.toThrow(); - }); -}); diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index dec50f231ab5..a89ab1e1cccc 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -1,4 +1,2 @@ -/** - * A placeholder for Aztec js. - */ -export class Aztec {} +export * from './contract/index.js'; +export * from './contract_deployer/index.js'; diff --git a/yarn-project/aztec.js/src/noir_js/index.ts b/yarn-project/aztec.js/src/noir_js/index.ts new file mode 100644 index 000000000000..b6b76d879cc8 --- /dev/null +++ b/yarn-project/aztec.js/src/noir_js/index.ts @@ -0,0 +1,131 @@ +/** + * A named type. + */ +export interface ABIVariable { + /** + * The name of the variable. + */ + name: string; + /** + * The type of the variable. + */ + type: ABIType; +} + +/** + * A function parameter. + */ +export interface ABIParameter extends ABIVariable { + /** + * Whether the parameter is unpacked. + */ + unpacked: boolean; +} + +/** + * A basic type. + */ +export interface BasicType { + /** + * The kind of the type. + */ + kind: T; +} + +/** + * A variable type. + */ +export type ABIType = BasicType<'field'> | BasicType<'boolean'> | IntegerType | ArrayType | StringType | StructType; + +/** + * An integer type. + */ +export interface IntegerType extends BasicType<'integer'> { + /** + * The sign of the integer. + */ + sign: string; + /** + * The width of the integer in bits. + */ + width: number; +} + +/** + * An array type. + */ +export interface ArrayType extends BasicType<'array'> { + /** + * The length of the array. + */ + length: number; + /** + * The type of the array elements. + */ + type: ABIType; +} + +/** + * A string type. + */ +export interface StringType extends BasicType<'string'> { + /** + * The length of the string. + */ + length: number; +} + +/** + * A struct type. + */ +export interface StructType extends BasicType<'struct'> { + /** + * The fields of the struct. + */ + fields: ABIVariable[]; +} + +/** + * The ABI entry of a function. + */ +export interface FunctionAbi { + /** + * The name of the function. + */ + name: string; + /** + * Whether the function is a constructor. + */ + // isConstructor: boolean; + /** + * Whether the function is secret. + */ + isSecret: boolean; + /** + * Function parameters. + */ + parameters: ABIParameter[]; + /** + * The types of the return values. + */ + returnTypes: ABIType[]; + /** + * The ACIR bytecode of the function. + */ + // bytecode: string; + /** + * The verification key of the function. + */ + verificationKey: string; +} + +export interface ContractAbi { + /** + * The functions of the contract. + */ + functions: FunctionAbi[]; + /** + * The ACIR bytecode of the contract. + */ + bytecode: string; +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 7e1ba2c84230..49b61ff7f1ae 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -88,6 +88,8 @@ __metadata: "@types/jest": ^29.4.0 "@types/node": ^18.7.23 jest: ^28.1.3 + jest-mock-extended: ^3.0.3 + sha3: ^2.1.4 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -4427,7 +4429,7 @@ __metadata: languageName: node linkType: hard -"jest-mock-extended@npm:^3.0.1": +"jest-mock-extended@npm:^3.0.1, jest-mock-extended@npm:^3.0.3": version: 3.0.3 resolution: "jest-mock-extended@npm:3.0.3" dependencies: From b8b1cc51251fcd31de480cdb2cfd668a1650a527 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 23 Mar 2023 09:45:17 +0000 Subject: [PATCH 2/3] Add aztec-rpc, remove wallet. --- README.md | 2 +- bootstrap.sh | 2 +- build_manifest.json | 14 ++++---- build_manifest.sh | 2 +- yarn-project/aztec-rpc/.eslintrc.cjs | 21 +++++++++++ yarn-project/{wallet => aztec-rpc}/Dockerfile | 8 ++--- yarn-project/aztec-rpc/README.md | 1 + .../{wallet => aztec-rpc}/package.json | 2 +- .../src/circuits.ts} | 2 +- yarn-project/aztec-rpc/src/foundation.ts | 5 +++ .../src/aztec_rpc => aztec-rpc/src}/index.ts | 4 +-- .../{wallet => aztec-rpc}/tsconfig.dest.json | 0 .../{wallet => aztec-rpc}/tsconfig.json | 0 yarn-project/aztec.js/package.json | 1 + yarn-project/aztec.js/src/abi_coder/index.ts | 2 +- .../src/contract/contract_function.ts | 2 +- yarn-project/aztec.js/src/contract/index.ts | 5 +-- ...d_method_interaction.ts => send_method.ts} | 4 +-- yarn-project/aztec.js/src/contract/sent_tx.ts | 4 +-- .../constructor_method.ts} | 9 +++-- .../contract_deployer.test.ts | 4 +-- .../contract_deployer/contract_deployer.ts | 8 ++--- .../{foundation/index.ts => foundation.ts} | 6 ---- yarn-project/aztec.js/src/index.ts | 1 + .../src/{noir_js/index.ts => noir.ts} | 0 yarn-project/package.json | 4 +-- yarn-project/typedoc.json | 4 +-- yarn-project/wallet/.eslintrc.cjs | 6 ---- yarn-project/wallet/README.md | 1 - yarn-project/wallet/src/index.ts | 4 --- yarn-project/yarn-project-base/Dockerfile | 2 +- yarn-project/yarn.lock | 35 ++++++++++--------- 32 files changed, 89 insertions(+), 76 deletions(-) create mode 100644 yarn-project/aztec-rpc/.eslintrc.cjs rename yarn-project/{wallet => aztec-rpc}/Dockerfile (60%) create mode 100644 yarn-project/aztec-rpc/README.md rename yarn-project/{wallet => aztec-rpc}/package.json (97%) rename yarn-project/{aztec.js/src/aztec_rpc/circuit_js.ts => aztec-rpc/src/circuits.ts} (98%) create mode 100644 yarn-project/aztec-rpc/src/foundation.ts rename yarn-project/{aztec.js/src/aztec_rpc => aztec-rpc/src}/index.ts (94%) rename yarn-project/{wallet => aztec-rpc}/tsconfig.dest.json (100%) rename yarn-project/{wallet => aztec-rpc}/tsconfig.json (100%) rename yarn-project/aztec.js/src/contract/{send_method_interaction.ts => send_method.ts} (95%) rename yarn-project/aztec.js/src/{contract/constructor_interaction.ts => contract_deployer/constructor_method.ts} (79%) rename yarn-project/aztec.js/src/{foundation/index.ts => foundation.ts} (91%) rename yarn-project/aztec.js/src/{noir_js/index.ts => noir.ts} (100%) delete mode 100644 yarn-project/wallet/.eslintrc.cjs delete mode 100644 yarn-project/wallet/README.md delete mode 100644 yarn-project/wallet/src/index.ts diff --git a/README.md b/README.md index 4b17b0aa5981..9dcda3e8e498 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ The Aztec 3 system consists of the following sub projects. - `acir-simulator` - `archiver` - `aztec-cli` +- `aztec-rpc` - `aztec.js` - `ethereum.js` - `kernel-simulator` @@ -13,4 +14,3 @@ The Aztec 3 system consists of the following sub projects. - `prover-client` - `public-client` - `sequencer-client` -- `wallet` diff --git a/bootstrap.sh b/bootstrap.sh index e127219de253..5c0706b494a8 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -45,6 +45,7 @@ PROJECTS=( # "circuits:./bootstrap.sh db_cli rollup_cli" # "yarn-project/acir-simulator:yarn build" # "yarn-project/aztec-cli:yarn build" + "yarn-project/aztec-rpc:yarn build" "yarn-project/aztec.js:yarn build" "yarn-project/archiver:yarn build" # "yarn-project/ethereum.js:yarn build" @@ -54,7 +55,6 @@ PROJECTS=( # "yarn-project/prover-client:yarn build" # "yarn-project/public-client:yarn build" # "yarn-project/sequencer-client:yarn build" - # "yarn-project/wallet:yarn build" ) for E in "${PROJECTS[@]}"; do diff --git a/build_manifest.json b/build_manifest.json index 019b9da2db25..bb31ff6ca13c 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -59,6 +59,13 @@ "rebuildPatterns": ["^yarn-project/aztec-cli/"], "dependencies": ["yarn-project-base"] }, + "aztec-rpc": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/aztec-rpc", + "dockerfile": "aztec-rpc/Dockerfile", + "rebuildPatterns": ["^yarn-project/aztec-rpc/"], + "dependencies": ["yarn-project-base"] + }, "aztec.js": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec.js", @@ -128,12 +135,5 @@ "dockerfile": "sequencer-client/Dockerfile", "rebuildPatterns": ["^yarn-project/sequencer-client/"], "dependencies": ["yarn-project-base"] - }, - "wallet": { - "buildDir": "yarn-project", - "projectDir": "yarn-project/wallet", - "dockerfile": "wallet/Dockerfile", - "rebuildPatterns": ["^yarn-project/wallet/"], - "dependencies": ["yarn-project-base"] } } diff --git a/build_manifest.sh b/build_manifest.sh index a376b9a2a47e..1ed6ed6d72cf 100755 --- a/build_manifest.sh +++ b/build_manifest.sh @@ -14,6 +14,7 @@ PROJECTS=( # acir-simulator:yarn-project # archiver:yarn-project # aztec-cli:yarn-project + # aztec-rpc:yarn-project # aztec.js:yarn-project # end-to-end:yarn-project # ethereum.js:yarn-project @@ -23,5 +24,4 @@ PROJECTS=( # prover-client:yarn-project # public-client:yarn-project # sequencer-client:yarn-project - # wallet:yarn-project ) diff --git a/yarn-project/aztec-rpc/.eslintrc.cjs b/yarn-project/aztec-rpc/.eslintrc.cjs new file mode 100644 index 000000000000..333ff38eab81 --- /dev/null +++ b/yarn-project/aztec-rpc/.eslintrc.cjs @@ -0,0 +1,21 @@ +require('@rushstack/eslint-patch/modern-module-resolution'); + +module.exports = { + extends: ['@aztec/eslint-config'], + parserOptions: { tsconfigRootDir: __dirname }, + rules: { + 'tsdoc/syntax': 'off', + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-description': 'off', + 'jsdoc/require-description-complete-sentence': 'off', + 'jsdoc/require-hyphen-before-param-description': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-param-name': 'off', + 'jsdoc/require-property': 'off', + 'jsdoc/require-property-description': 'off', + 'jsdoc/require-property-name': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-returns-description': 'off', + }, +}; diff --git a/yarn-project/wallet/Dockerfile b/yarn-project/aztec-rpc/Dockerfile similarity index 60% rename from yarn-project/wallet/Dockerfile rename to yarn-project/aztec-rpc/Dockerfile index 11131ce67564..12c4ff17ca80 100644 --- a/yarn-project/wallet/Dockerfile +++ b/yarn-project/aztec-rpc/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder -COPY wallet wallet -WORKDIR /usr/src/yarn-project/wallet +COPY aztec-rpc aztec-rpc +WORKDIR /usr/src/yarn-project/aztec-rpc RUN yarn build && yarn formatting && yarn test # Prune dev dependencies. See comment in base image. @@ -9,6 +9,6 @@ RUN yarn cache clean RUN yarn workspaces focus --production > /dev/null FROM node:18-alpine -COPY --from=builder /usr/src/yarn-project/wallet /usr/src/yarn-project/wallet -WORKDIR /usr/src/yarn-project/wallet +COPY --from=builder /usr/src/yarn-project/aztec-rpc /usr/src/yarn-project/aztec-rpc +WORKDIR /usr/src/yarn-project/aztec-rpc ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/aztec-rpc/README.md b/yarn-project/aztec-rpc/README.md new file mode 100644 index 000000000000..b1e338ba6945 --- /dev/null +++ b/yarn-project/aztec-rpc/README.md @@ -0,0 +1 @@ +# Aztec RPC Server & Client diff --git a/yarn-project/wallet/package.json b/yarn-project/aztec-rpc/package.json similarity index 97% rename from yarn-project/wallet/package.json rename to yarn-project/aztec-rpc/package.json index 0c99e9b856a8..692df8a5d5cb 100644 --- a/yarn-project/wallet/package.json +++ b/yarn-project/aztec-rpc/package.json @@ -1,5 +1,5 @@ { - "name": "@aztec/wallet", + "name": "@aztec/aztec-rpc", "version": "0.0.0", "type": "module", "exports": "./dest/index.js", diff --git a/yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts b/yarn-project/aztec-rpc/src/circuits.ts similarity index 98% rename from yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts rename to yarn-project/aztec-rpc/src/circuits.ts index 15e236c3e18f..e39eb3b9b376 100644 --- a/yarn-project/aztec.js/src/aztec_rpc/circuit_js.ts +++ b/yarn-project/aztec-rpc/src/circuits.ts @@ -1,4 +1,4 @@ -import { randomBytes } from '../foundation/index.js'; +import { randomBytes } from './foundation.js'; /** * A named type. diff --git a/yarn-project/aztec-rpc/src/foundation.ts b/yarn-project/aztec-rpc/src/foundation.ts new file mode 100644 index 000000000000..40f4a8c0bad6 --- /dev/null +++ b/yarn-project/aztec-rpc/src/foundation.ts @@ -0,0 +1,5 @@ +import nodeCrypto from 'crypto'; + +export const randomBytes = (len: number) => { + return nodeCrypto.randomBytes(len) as Buffer; +}; diff --git a/yarn-project/aztec.js/src/aztec_rpc/index.ts b/yarn-project/aztec-rpc/src/index.ts similarity index 94% rename from yarn-project/aztec.js/src/aztec_rpc/index.ts rename to yarn-project/aztec-rpc/src/index.ts index ca9ed561ce44..b7f1c68883ae 100644 --- a/yarn-project/aztec.js/src/aztec_rpc/index.ts +++ b/yarn-project/aztec-rpc/src/index.ts @@ -1,6 +1,6 @@ -import { AztecAddress, EthAddress, Fr, Signature, Tx, TxHash, TxRequest } from './circuit_js.js'; +import { AztecAddress, EthAddress, Fr, Signature, Tx, TxHash, TxRequest } from './circuits.js'; -export * from './circuit_js.js'; +export * from './circuits.js'; export interface TxReceipt { txHash: TxHash; diff --git a/yarn-project/wallet/tsconfig.dest.json b/yarn-project/aztec-rpc/tsconfig.dest.json similarity index 100% rename from yarn-project/wallet/tsconfig.dest.json rename to yarn-project/aztec-rpc/tsconfig.dest.json diff --git a/yarn-project/wallet/tsconfig.json b/yarn-project/aztec-rpc/tsconfig.json similarity index 100% rename from yarn-project/wallet/tsconfig.json rename to yarn-project/aztec-rpc/tsconfig.json diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 88e6b75298d7..7eff00fb239e 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -29,6 +29,7 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/aztec-rpc": "workspace:^", "sha3": "^2.1.4", "tslib": "^2.4.0" }, diff --git a/yarn-project/aztec.js/src/abi_coder/index.ts b/yarn-project/aztec.js/src/abi_coder/index.ts index b425716b52e8..2dcea348efde 100644 --- a/yarn-project/aztec.js/src/abi_coder/index.ts +++ b/yarn-project/aztec.js/src/abi_coder/index.ts @@ -1,4 +1,4 @@ -import { ABIParameter } from '../noir_js/index.js'; +import { ABIParameter } from '../noir.js'; import { keccak256 } from './keccak256.js'; export * from './hex_string.js'; diff --git a/yarn-project/aztec.js/src/contract/contract_function.ts b/yarn-project/aztec.js/src/contract/contract_function.ts index 1b8ca701402b..19d211f4f148 100644 --- a/yarn-project/aztec.js/src/contract/contract_function.ts +++ b/yarn-project/aztec.js/src/contract/contract_function.ts @@ -1,5 +1,5 @@ import { encodeFunctionSignature, encodeParameters, generateFunctionSignature } from '../abi_coder/index.js'; -import { FunctionAbi } from '../noir_js/index.js'; +import { FunctionAbi } from '../noir.js'; export class ContractFunction { constructor(private abi: FunctionAbi) {} diff --git a/yarn-project/aztec.js/src/contract/index.ts b/yarn-project/aztec.js/src/contract/index.ts index 4785219e0f78..c434ae962571 100644 --- a/yarn-project/aztec.js/src/contract/index.ts +++ b/yarn-project/aztec.js/src/contract/index.ts @@ -1,2 +1,3 @@ -export * from './constructor_interaction.js'; -export * from './send_method_interaction.js'; +export * from './contract_function.js'; +export * from './send_method.js'; +export * from './sent_tx.js'; diff --git a/yarn-project/aztec.js/src/contract/send_method_interaction.ts b/yarn-project/aztec.js/src/contract/send_method.ts similarity index 95% rename from yarn-project/aztec.js/src/contract/send_method_interaction.ts rename to yarn-project/aztec.js/src/contract/send_method.ts index 6fd2366fd94b..c3e094552dee 100644 --- a/yarn-project/aztec.js/src/contract/send_method_interaction.ts +++ b/yarn-project/aztec.js/src/contract/send_method.ts @@ -1,4 +1,4 @@ -import { AztecAddress, AztecRPCClient, Fr, Signature, Tx, TxHash, TxRequest } from '../aztec_rpc/index.js'; +import { AztecAddress, AztecRPCClient, Fr, Signature, Tx, TxHash, TxRequest } from '@aztec/aztec-rpc'; import { ContractFunction } from './contract_function.js'; import { SentTx } from './sent_tx.js'; @@ -11,7 +11,7 @@ export interface SendMethodOptions { * This is the class that is returned when calling e.g. `contract.methods.myMethod(arg0, arg1)`. * It contains available interactions one can call on a `send` method. */ -export class SendMethodInteraction { +export class SendMethod { protected txRequest?: TxRequest; private signature?: Signature; private tx?: Tx; diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts index 8771eb86dab1..ad1dbce0bea8 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -1,5 +1,5 @@ -import { AztecRPCClient, TxHash, TxReceipt } from '../aztec_rpc/index.js'; -import { retryUntil } from '../foundation/index.js'; +import { AztecRPCClient, TxHash, TxReceipt } from '@aztec/aztec-rpc'; +import { retryUntil } from '../foundation.js'; export class SentTx { private receipt?: TxReceipt; diff --git a/yarn-project/aztec.js/src/contract/constructor_interaction.ts b/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts similarity index 79% rename from yarn-project/aztec.js/src/contract/constructor_interaction.ts rename to yarn-project/aztec.js/src/contract_deployer/constructor_method.ts index 7bb87b70ee19..811cf95acf7a 100644 --- a/yarn-project/aztec.js/src/contract/constructor_interaction.ts +++ b/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts @@ -1,8 +1,7 @@ +import { AztecAddress, AztecRPCClient, EthAddress, Fr } from '@aztec/aztec-rpc'; import { hexToBuffer } from '../abi_coder/index.js'; -import { AztecAddress, AztecRPCClient, EthAddress, Fr } from '../aztec_rpc/index.js'; -import { ContractAbi } from '../noir_js/index.js'; -import { ContractFunction } from './contract_function.js'; -import { SendMethodOptions, SendMethodInteraction } from './send_method_interaction.js'; +import { ContractFunction, SendMethod, SendMethodOptions } from '../contract/index.js'; +import { ContractAbi } from '../noir.js'; export interface ConstructorOptions extends SendMethodOptions { contractAddressSalt?: Fr; @@ -11,7 +10,7 @@ export interface ConstructorOptions extends SendMethodOptions { /** * Extends the SendMethodInteraction to create TxRequest for constructors (deployments). */ -export class ConstructorInteraction extends SendMethodInteraction { +export class ConstructorMethod extends SendMethod { constructor( arc: AztecRPCClient, private abi: ContractAbi, diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts index ec67f5929ddc..89bb977c00de 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts @@ -9,8 +9,8 @@ import { TxHash, TxReceipt, TxRequest, -} from '../aztec_rpc/index.js'; -import { ContractAbi } from '../noir_js/index.js'; +} from '@aztec/aztec-rpc'; +import { ContractAbi } from '../noir.js'; import { ContractDeployer } from './contract_deployer.js'; describe('Contract Deployer', () => { diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts index f0912dbc147a..2b2c5522e8f5 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts @@ -1,6 +1,6 @@ -import { AztecRPCClient, EthAddress } from '../aztec_rpc/index.js'; -import { ConstructorInteraction, ConstructorOptions } from '../contract/index.js'; -import { ContractAbi } from '../noir_js/index.js'; +import { AztecRPCClient, EthAddress } from '@aztec/aztec-rpc'; +import { ContractAbi } from '../noir.js'; +import { ConstructorMethod, ConstructorOptions } from './constructor_method.js'; /** * A class for deploying contract. @@ -9,6 +9,6 @@ export class ContractDeployer { constructor(private abi: ContractAbi, private arc: AztecRPCClient, private defaultOptions: ConstructorOptions = {}) {} public deploy(portalContract = EthAddress.ZERO, ...args: any[]) { - return new ConstructorInteraction(this.arc, this.abi, portalContract, args, this.defaultOptions); + return new ConstructorMethod(this.arc, this.abi, portalContract, args, this.defaultOptions); } } diff --git a/yarn-project/aztec.js/src/foundation/index.ts b/yarn-project/aztec.js/src/foundation.ts similarity index 91% rename from yarn-project/aztec.js/src/foundation/index.ts rename to yarn-project/aztec.js/src/foundation.ts index 6fe59e071b0a..b9b48b88eeb1 100644 --- a/yarn-project/aztec.js/src/foundation/index.ts +++ b/yarn-project/aztec.js/src/foundation.ts @@ -1,9 +1,3 @@ -import nodeCrypto from 'crypto'; - -export const randomBytes = (len: number) => { - return nodeCrypto.randomBytes(len) as Buffer; -}; - export function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index a89ab1e1cccc..3034c9da3631 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -1,2 +1,3 @@ +export * from '@aztec/aztec-rpc'; export * from './contract/index.js'; export * from './contract_deployer/index.js'; diff --git a/yarn-project/aztec.js/src/noir_js/index.ts b/yarn-project/aztec.js/src/noir.ts similarity index 100% rename from yarn-project/aztec.js/src/noir_js/index.ts rename to yarn-project/aztec.js/src/noir.ts diff --git a/yarn-project/package.json b/yarn-project/package.json index 5b68d11e9601..0e8d4f3d2be0 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -10,6 +10,7 @@ "acir-simulator", "archiver", "aztec-cli", + "aztec-rpc", "aztec.js", "docs", "end-to-end", @@ -23,8 +24,7 @@ "prettier-config", "prover-client", "public-client", - "sequencer-client", - "wallet" + "sequencer-client" ], "prettier": "./prettier-config", "devDependencies": { diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index caf8497b4a8f..1bdaa3857199 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -5,6 +5,7 @@ "acir-simulator", "archiver", "aztec-cli", + "aztec-rpc", "aztec.js", "ethereum.js", "kernel-simulator", @@ -13,7 +14,6 @@ "p2p", "prover-client", "public-client", - "sequencer-client", - "wallet" + "sequencer-client" ] } diff --git a/yarn-project/wallet/.eslintrc.cjs b/yarn-project/wallet/.eslintrc.cjs deleted file mode 100644 index 9cf806b1500f..000000000000 --- a/yarn-project/wallet/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/yarn-project/wallet/README.md b/yarn-project/wallet/README.md deleted file mode 100644 index 456644fc5565..000000000000 --- a/yarn-project/wallet/README.md +++ /dev/null @@ -1 +0,0 @@ -# Wallet diff --git a/yarn-project/wallet/src/index.ts b/yarn-project/wallet/src/index.ts deleted file mode 100644 index 95d6e81d27f4..000000000000 --- a/yarn-project/wallet/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A placeholder for the Wallet. - */ -export class Wallet {} diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 5ccdf96f7f1a..baab92c1206c 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -14,6 +14,7 @@ WORKDIR /usr/src/yarn-project COPY acir-simulator/package.json acir-simulator/package.json COPY archiver/package.json archiver/package.json COPY aztec-cli/package.json aztec-cli/package.json +COPY aztec-rpc/package.json aztec-rpc/package.json COPY aztec.js/package.json aztec.js/package.json COPY docs/package.json docs/package.json COPY end-to-end/package.json end-to-end/package.json @@ -26,7 +27,6 @@ COPY p2p/package.json p2p/package.json COPY prover-client/package.json prover-client/package.json COPY public-client/package.json public-client/package.json COPY sequencer-client/package.json sequencer-client/package.json -COPY wallet/package.json wallet/package.json # All workspaces use the linting config, so always include it. COPY eslint-config eslint-config COPY prettier-config prettier-config diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 49b61ff7f1ae..0f4b1884c4f5 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -78,10 +78,28 @@ __metadata: languageName: unknown linkType: soft +"@aztec/aztec-rpc@workspace:^, @aztec/aztec-rpc@workspace:aztec-rpc": + version: 0.0.0-use.local + resolution: "@aztec/aztec-rpc@workspace:aztec-rpc" + dependencies: + "@aztec/eslint-config": "workspace:^" + "@jest/globals": ^29.4.3 + "@rushstack/eslint-patch": ^1.1.4 + "@types/jest": ^29.4.0 + "@types/node": ^18.7.23 + jest: ^28.1.3 + ts-jest: ^28.0.7 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^4.9.5 + languageName: unknown + linkType: soft + "@aztec/aztec.js@workspace:^, @aztec/aztec.js@workspace:aztec.js": version: 0.0.0-use.local resolution: "@aztec/aztec.js@workspace:aztec.js" dependencies: + "@aztec/aztec-rpc": "workspace:^" "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 @@ -322,23 +340,6 @@ __metadata: languageName: unknown linkType: soft -"@aztec/wallet@workspace:wallet": - version: 0.0.0-use.local - resolution: "@aztec/wallet@workspace:wallet" - dependencies: - "@aztec/eslint-config": "workspace:^" - "@jest/globals": ^29.4.3 - "@rushstack/eslint-patch": ^1.1.4 - "@types/jest": ^29.4.0 - "@types/node": ^18.7.23 - jest: ^28.1.3 - ts-jest: ^28.0.7 - ts-node: ^10.9.1 - tslib: ^2.4.0 - typescript: ^4.9.5 - languageName: unknown - linkType: soft - "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.18.6": version: 7.18.6 resolution: "@babel/code-frame@npm:7.18.6" From fb93de8e63340d816803bfdc620d43ca978e11e5 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 23 Mar 2023 15:25:52 +0000 Subject: [PATCH 3/3] Initial Aztec RPC Server. --- yarn-project/aztec-rpc/src/abi_coder/index.ts | 11 + .../src/account_state/account_state.ts | 11 + .../aztec-rpc/src/account_state/index.ts | 1 + yarn-project/aztec-rpc/src/acir_simulator.ts | 9 + yarn-project/aztec-rpc/src/aztec_node.ts | 29 +++ .../src/aztec_rpc_client/aztec_rpc_client.ts | 23 ++ .../aztec-rpc/src/aztec_rpc_client/index.ts | 1 + .../src/aztec_rpc_server/aztec_rpc_server.ts | 155 ++++++++++++ .../create_aztec_rpc_server.ts | 33 +++ .../aztec-rpc/src/aztec_rpc_server/index.ts | 2 + yarn-project/aztec-rpc/src/circuits.ts | 233 +++++++----------- .../src/contract_data_source/contract_dao.ts | 29 +++ .../contract_data_source.ts | 9 + .../src/contract_data_source/index.ts | 3 + .../memory_contract_data_source.ts | 22 ++ .../aztec-rpc/src/database/database.ts | 7 + yarn-project/aztec-rpc/src/database/index.ts | 3 + .../aztec-rpc/src/database/memory_db.ts | 12 + yarn-project/aztec-rpc/src/database/tx_dao.ts | 14 ++ yarn-project/aztec-rpc/src/foundation.ts | 7 + yarn-project/aztec-rpc/src/index.ts | 38 +-- yarn-project/aztec-rpc/src/key_store/index.ts | 3 + .../aztec-rpc/src/key_store/key_pair.ts | 34 +++ .../aztec-rpc/src/key_store/key_store.ts | 8 + .../aztec-rpc/src/key_store/test_key_store.ts | 34 +++ .../{aztec.js => aztec-rpc}/src/noir.ts | 10 +- .../aztec-rpc/src/proof_generator/index.ts | 1 + .../src/proof_generator/proof_generator.ts | 10 + .../aztec-rpc/src/synchroniser/index.ts | 1 + .../src/synchroniser/synchroniser.ts | 14 ++ yarn-project/aztec-rpc/src/tx/index.ts | 1 + yarn-project/aztec-rpc/src/tx/tx_receipt.ts | 14 ++ yarn-project/aztec.js/src/abi_coder/index.ts | 11 +- .../aztec.js/src/abi_coder/keccak256.ts | 7 - .../src/contract/contract_function.ts | 6 +- .../contract_deployer/constructor_method.ts | 8 +- .../contract_deployer.test.ts | 23 +- .../contract_deployer/contract_deployer.ts | 3 +- yarn-project/aztec.js/src/index.ts | 4 +- 39 files changed, 610 insertions(+), 234 deletions(-) create mode 100644 yarn-project/aztec-rpc/src/abi_coder/index.ts create mode 100644 yarn-project/aztec-rpc/src/account_state/account_state.ts create mode 100644 yarn-project/aztec-rpc/src/account_state/index.ts create mode 100644 yarn-project/aztec-rpc/src/acir_simulator.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_node.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_rpc_client/index.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts create mode 100644 yarn-project/aztec-rpc/src/aztec_rpc_server/index.ts create mode 100644 yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts create mode 100644 yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts create mode 100644 yarn-project/aztec-rpc/src/contract_data_source/index.ts create mode 100644 yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts create mode 100644 yarn-project/aztec-rpc/src/database/database.ts create mode 100644 yarn-project/aztec-rpc/src/database/index.ts create mode 100644 yarn-project/aztec-rpc/src/database/memory_db.ts create mode 100644 yarn-project/aztec-rpc/src/database/tx_dao.ts create mode 100644 yarn-project/aztec-rpc/src/key_store/index.ts create mode 100644 yarn-project/aztec-rpc/src/key_store/key_pair.ts create mode 100644 yarn-project/aztec-rpc/src/key_store/key_store.ts create mode 100644 yarn-project/aztec-rpc/src/key_store/test_key_store.ts rename yarn-project/{aztec.js => aztec-rpc}/src/noir.ts (92%) create mode 100644 yarn-project/aztec-rpc/src/proof_generator/index.ts create mode 100644 yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts create mode 100644 yarn-project/aztec-rpc/src/synchroniser/index.ts create mode 100644 yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts create mode 100644 yarn-project/aztec-rpc/src/tx/index.ts create mode 100644 yarn-project/aztec-rpc/src/tx/tx_receipt.ts delete mode 100644 yarn-project/aztec.js/src/abi_coder/keccak256.ts diff --git a/yarn-project/aztec-rpc/src/abi_coder/index.ts b/yarn-project/aztec-rpc/src/abi_coder/index.ts new file mode 100644 index 000000000000..0a37a288f75a --- /dev/null +++ b/yarn-project/aztec-rpc/src/abi_coder/index.ts @@ -0,0 +1,11 @@ +import { keccak256 } from '../foundation.js'; +import { ABIParameter } from '../noir.js'; + +export function generateFunctionSignature(name: string, parameters: ABIParameter[]) { + return name === 'constructor' ? name : `${name}(${parameters.map(p => p.type.kind).join(',')})`; +} + +export function generateFunctionSelector(name: string, parameters: ABIParameter[]) { + const signature = generateFunctionSignature(name, parameters); + return keccak256(Buffer.from(signature)).slice(0, 4); +} diff --git a/yarn-project/aztec-rpc/src/account_state/account_state.ts b/yarn-project/aztec-rpc/src/account_state/account_state.ts new file mode 100644 index 000000000000..7fbb7994c916 --- /dev/null +++ b/yarn-project/aztec-rpc/src/account_state/account_state.ts @@ -0,0 +1,11 @@ +import { TxHash } from '../aztec_node.js'; +import { AztecAddress } from '../circuits.js'; +import { Database } from '../database/index.js'; + +export class AccountState { + constructor(public readonly publicKey: AztecAddress, private db: Database) {} + + getTx(txHash: TxHash) { + return this.db.getTx(txHash); + } +} diff --git a/yarn-project/aztec-rpc/src/account_state/index.ts b/yarn-project/aztec-rpc/src/account_state/index.ts new file mode 100644 index 000000000000..fa1fec1b824e --- /dev/null +++ b/yarn-project/aztec-rpc/src/account_state/index.ts @@ -0,0 +1 @@ +export * from './account_state.js'; diff --git a/yarn-project/aztec-rpc/src/acir_simulator.ts b/yarn-project/aztec-rpc/src/acir_simulator.ts new file mode 100644 index 000000000000..c5c5c78fa50d --- /dev/null +++ b/yarn-project/aztec-rpc/src/acir_simulator.ts @@ -0,0 +1,9 @@ +// TODO use @aztce/acir-simulator + +import { PreviousKernelData, PrivateCallData, TxRequest } from './circuits.js'; + +export class AcirSimulator { + public simulate(txRequest: TxRequest) { + return Promise.resolve({ kernelData: new PreviousKernelData(), callData: new PrivateCallData() }); + } +} diff --git a/yarn-project/aztec-rpc/src/aztec_node.ts b/yarn-project/aztec-rpc/src/aztec_node.ts new file mode 100644 index 000000000000..760d1745b297 --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_node.ts @@ -0,0 +1,29 @@ +import { AccumulatedTxData } from './circuits.js'; + +export class TxHash { + public static SIZE = 32; + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: TxHash) { + return this.buffer.equals(rhs.buffer); + } +} + +export class Tx { + constructor(public readonly proofData: Buffer, public readonly data: AccumulatedTxData) {} + + get txHash() { + return new TxHash(Buffer.alloc(32)); + } +} + +export class AztecNode { + sendTx(tx: Tx) { + return Promise.resolve(tx.txHash); + } + + getBlocks() { + return Promise.resolve([]); + } +} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts new file mode 100644 index 000000000000..cb699a54fd90 --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts @@ -0,0 +1,23 @@ +import { Tx, TxHash } from '../aztec_node.js'; +import { AztecAddress, EthAddress, Fr, Signature, TxRequest } from '../circuits.js'; +import { ContractAbi } from '../noir.js'; +import { TxReceipt } from '../tx/index.js'; + +export interface AztecRPCClient { + addAccount(): Promise; + getAccounts(): Promise; + getCode(contract: AztecAddress, functionSelector?: Buffer): Promise; + createDeploymentTxRequest( + abi: ContractAbi, + args: Fr[], + portalContract: EthAddress, + contractAddressSalt: Fr, + from: AztecAddress, + ): Promise; + createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; + signTxRequest(txRequest: TxRequest): Promise; + createTx(txRequest: TxRequest, signature: Signature): Promise; + sendTx(tx: Tx): Promise; + // callTx(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; + getTxReceipt(txHash: TxHash): Promise; +} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_client/index.ts b/yarn-project/aztec-rpc/src/aztec_rpc_client/index.ts new file mode 100644 index 000000000000..d70b35ea79b1 --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_rpc_client/index.ts @@ -0,0 +1 @@ +export * from './aztec_rpc_client.js'; diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts new file mode 100644 index 000000000000..cc0027efdfc4 --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -0,0 +1,155 @@ +import { generateFunctionSelector } from '../abi_coder/index.js'; +import { AcirSimulator } from '../acir_simulator.js'; +import { AztecNode, Tx, TxHash } from '../aztec_node.js'; +import { AztecRPCClient } from '../aztec_rpc_client/index.js'; +import { + AztecAddress, + ContractDeploymentData, + EthAddress, + Fr, + generateContractAddress, + KernelPrivateInputs, + Signature, + TxContext, + TxRequest, +} from '../circuits.js'; +import { Database } from '../database/index.js'; +import { KeyStore } from '../key_store/index.js'; +import { ContractAbi } from '../noir.js'; +import { ProofGenerator } from '../proof_generator/index.js'; +import { Synchroniser } from '../synchroniser/index.js'; + +export class AztecRPCServer implements AztecRPCClient { + constructor( + private keyStore: KeyStore, + private synchroniser: Synchroniser, + private simulator: AcirSimulator, + private proofGenerator: ProofGenerator, + private node: AztecNode, + private db: Database, + ) {} + + public addAccount() { + return this.keyStore.addAccount(); + } + + public getAccounts() { + return this.keyStore.getAccounts(); + } + + public getCode(contract: AztecAddress, functionSelector?: Buffer) { + return this.db.getCode(contract, functionSelector || generateFunctionSelector('constructor', [])); + } + + public async createDeploymentTxRequest( + abi: ContractAbi, + args: Fr[], + portalContract: EthAddress, + contractAddressSalt: Fr, + from: AztecAddress, + ) { + const constructorAbi = abi.functions.find(f => f.name === 'constructor'); + if (!constructorAbi) { + throw new Error('Cannot find constructor in the ABI.'); + } + + const functionData = { + functionSelector: generateFunctionSelector(constructorAbi.name, constructorAbi.parameters), + isSecret: true, + isContructor: true, + }; + + const contractDataHash = Fr.ZERO; + const functionTreeRoot = Fr.ZERO; + const constructorHash = Fr.ZERO; + const contractDeploymentData = new ContractDeploymentData( + contractDataHash, + functionTreeRoot, + constructorHash, + contractAddressSalt, + portalContract, + ); + const txContext = new TxContext(false, false, false, contractDeploymentData); + + const contractAddress = generateContractAddress(from, contractAddressSalt, args); + await this.db.addContract(contractAddress, abi, false); + + return new TxRequest( + from, + AztecAddress.ZERO, // to + functionData, + args, + txContext, + Fr.random(), // nonce + Fr.ZERO, // chainId + ); + } + + public async createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress) { + const abi = await this.db.getContract(to); + if (!abi) { + throw new Error('Unknown contract.'); + } + + const functionAbi = abi.functions.find(f => f.selector.equals(functionSelector)); + if (!functionAbi) { + throw new Error('Unknown function.'); + } + + const functionData = { + functionSelector, + isSecret: functionAbi.isSecret, + isContructor: false, + }; + + const txContext = new TxContext(false, false, false, ContractDeploymentData.EMPTY); + + return new TxRequest( + from, + to, + functionData, + args, + txContext, + Fr.random(), // nonce + Fr.ZERO, // chainId + ); + } + + public signTxRequest(txRequest: TxRequest) { + return this.keyStore.signTxRequest(txRequest); + } + + public async createTx(txRequest: TxRequest, signature: Signature) { + const { kernelData, callData } = await this.simulator.simulate(txRequest); + const privateInputs = new KernelPrivateInputs(txRequest, signature, kernelData, callData); + const { proofData, accumulatedTxData } = await this.proofGenerator.createProof(privateInputs); + return new Tx(proofData, accumulatedTxData); + } + + public sendTx(tx: Tx) { + return this.node.sendTx(tx); + } + + public async getTxReceipt(txHash: TxHash) { + const tx = await this.db.getTx(txHash); + if (!tx) { + return; + } + + const account = this.synchroniser.getAccount(tx.from); + if (!account) { + throw new Error('Unauthorised account.'); + } + + return { + txHash: tx.txHash, + blockHash: tx.blockHash, + blockNumber: tx.blockNumber, + from: tx.from, + to: tx.to, + contractAddress: tx.contractAddress, + error: tx.error, + status: !tx.error, + }; + } +} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts new file mode 100644 index 000000000000..8c8a1228de84 --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts @@ -0,0 +1,33 @@ +import { AcirSimulator } from '../acir_simulator.js'; +import { AztecNode } from '../aztec_node.js'; +import { KernelCircuitProver } from '../circuits.js'; +import { MemoryDB } from '../database/index.js'; +import { KeyStore, TestKeyStore } from '../key_store/index.js'; +import { ProofGenerator } from '../proof_generator/index.js'; +import { Synchroniser } from '../synchroniser/index.js'; +import { AztecRPCServer } from './aztec_rpc_server.js'; + +export function createAztecRPCServer({ + keyStore, + node, + db, + synchroniser, + simulator, + proofGenerator, +}: { + keyStore?: KeyStore; + node?: AztecNode; + db?: MemoryDB; + synchroniser?: Synchroniser; + simulator?: AcirSimulator; + proofGenerator?: ProofGenerator; +} = {}) { + keyStore = keyStore || new TestKeyStore(); + node = node || new AztecNode(); + db = db || new MemoryDB(); + synchroniser = synchroniser || new Synchroniser(node, db); + simulator = simulator || new AcirSimulator(); + proofGenerator = proofGenerator || new ProofGenerator(new KernelCircuitProver()); + + return Promise.resolve(new AztecRPCServer(keyStore, synchroniser, simulator, proofGenerator, node, db)); +} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/index.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/index.ts new file mode 100644 index 000000000000..3af43b1a499e --- /dev/null +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/index.ts @@ -0,0 +1,2 @@ +export * from './aztec_rpc_server.js'; +export * from './create_aztec_rpc_server.js'; diff --git a/yarn-project/aztec-rpc/src/circuits.ts b/yarn-project/aztec-rpc/src/circuits.ts index e39eb3b9b376..3a387b84cd6e 100644 --- a/yarn-project/aztec-rpc/src/circuits.ts +++ b/yarn-project/aztec-rpc/src/circuits.ts @@ -1,126 +1,5 @@ import { randomBytes } from './foundation.js'; -/** - * A named type. - */ -export interface ABIVariable { - /** - * The name of the variable. - */ - name: string; - /** - * The type of the variable. - */ - type: ABIType; -} - -/** - * A function parameter. - */ -export interface ABIParameter extends ABIVariable { - /** - * Whether the parameter is unpacked. - */ - unpacked: boolean; -} - -/** - * A basic type. - */ -export interface BasicType { - /** - * The kind of the type. - */ - kind: T; -} - -/** - * A variable type. - */ -export type ABIType = BasicType<'field'> | BasicType<'boolean'> | IntegerType | ArrayType | StringType | StructType; - -/** - * An integer type. - */ -export interface IntegerType extends BasicType<'integer'> { - /** - * The sign of the integer. - */ - sign: string; - /** - * The width of the integer in bits. - */ - width: number; -} - -/** - * An array type. - */ -export interface ArrayType extends BasicType<'array'> { - /** - * The length of the array. - */ - length: number; - /** - * The type of the array elements. - */ - type: ABIType; -} - -/** - * A string type. - */ -export interface StringType extends BasicType<'string'> { - /** - * The length of the string. - */ - length: number; -} - -/** - * A struct type. - */ -export interface StructType extends BasicType<'struct'> { - /** - * The fields of the struct. - */ - fields: ABIVariable[]; -} - -/** - * The ABI entry of a function. - */ -export interface FunctionAbi { - /** - * The name of the function. - */ - name: string; - /** - * Whether the function is a constructor. - */ - isConstructor: boolean; - /** - * Whether the function is secret. - */ - isSecret: boolean; - /** - * Function parameters. - */ - parameters: ABIParameter[]; - /** - * The types of the return values. - */ - returnTypes: ABIType[]; - /** - * The ACIR bytecode of the function. - */ - bytecode: string; - /** - * The verification key of the function. - */ - verificationKey: string; -} - export class Fr { public static ZERO = new Fr(Buffer.alloc(32)); @@ -142,50 +21,108 @@ export class EthAddress { } export class AztecAddress { - public static ZERO = new AztecAddress(Buffer.alloc(32)); + public static SIZE = 64; + + public static ZERO = new AztecAddress(Buffer.alloc(AztecAddress.SIZE)); public static random() { - return new AztecAddress(randomBytes(32)); + return new AztecAddress(randomBytes(AztecAddress.SIZE)); } constructor(public readonly buffer: Buffer) {} + + public equals(rhs: AztecAddress) { + return this.buffer.equals(rhs.buffer); + } } -export class Signature {} +export class Signature { + public static SIZE = 64; -export class TxHash {} + public static random() { + return new EthAddress(randomBytes(Signature.SIZE)); + } + + constructor(public readonly buffer: Buffer) {} +} export interface FunctionData { - functionEncoding: number; - isPrivate: boolean; + functionSelector: Buffer; + isSecret: boolean; isContructor: boolean; } -export interface ContractDeploymentData { - contractDataHash: Fr; - functionTreeRoot: Fr; - constructorHash: Fr; - contractAddressSalt: Fr; - portalContractAddress: Fr; +export class ContractDeploymentData { + public static EMPTY = new ContractDeploymentData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); + + constructor( + public readonly contractDataHash: Fr, + public readonly functionTreeRoot: Fr, + public readonly constructorHash: Fr, + public readonly contractAddressSalt: Fr, + public readonly portalContractAddress: Fr, + ) {} +} + +export class TxContext { + constructor( + public readonly isFeePaymentTx: boolean, + public readonly isRebatePaymentTx: boolean, + public readonly isContractDeploymentTx: boolean, + public readonly contractDeploymentData: ContractDeploymentData, + ) {} +} + +export class TxRequest { + constructor( + public readonly from: AztecAddress, + public readonly to: AztecAddress, + public readonly functionData: FunctionData, + public readonly args: Fr[], + public readonly txContext: TxContext, + public readonly nonce: Fr, + public readonly chainId: Fr, + ) {} + + toBuffer() { + return Buffer.alloc(0); + } } -export interface TxContext { - isFeePaymentTx: boolean; - isRebatePaymentTx: boolean; - isContractDeploymentTx: boolean; - contractDeploymentData: ContractDeploymentData; +export class PreviousKernelData {} + +export class PrivateCallData {} + +export class AccumulatedTxData {} + +export class KernelPrivateInputs { + constructor( + public readonly txRequest: TxRequest, + public readonly signature: Signature, + public readonly previousKernelData: PreviousKernelData, + public readonly privateCallData: PrivateCallData, + ) {} +} + +export class KernelProofData { + public readonly accumulatedTxData: AccumulatedTxData; + + constructor(public readonly proofData: Buffer) { + this.accumulatedTxData = new AccumulatedTxData(); + } } -export interface TxRequest { - from: AztecAddress; - to?: AztecAddress; - functionData: FunctionData; - args: Fr[]; - txContext: TxContext; - nonce: Fr; - chainId: Fr; +export class KernelCircuitProver { + public createProof(inputs: KernelPrivateInputs) { + return Promise.resolve(new KernelProofData(Buffer.alloc(100))); + } } -export interface Tx { - proofData: Buffer; +export function generateContractAddress( + deployerAddress: AztecAddress, + salt: Fr, + args: Fr[], + // functionLeaves: Fr[], +) { + return AztecAddress.random(); } diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts new file mode 100644 index 000000000000..d15712687ae2 --- /dev/null +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts @@ -0,0 +1,29 @@ +import { generateFunctionSelector } from '../abi_coder/index.js'; +import { AztecAddress } from '../circuits.js'; +import { ContractAbi, FunctionAbi } from '../noir.js'; + +export interface ContractFunctionDao extends FunctionAbi { + selector: Buffer; +} + +export interface ContractDao extends ContractAbi { + address: AztecAddress; + functions: ContractFunctionDao[]; + deployed: boolean; +} + +export function functionAbiToFunctionDao(abi: FunctionAbi) { + const selector = generateFunctionSelector(abi.name, abi.parameters); + return { + ...abi, + selector, + }; +} + +export function contractAbiToContractDao(address: AztecAddress, abi: ContractAbi, deployed: boolean): ContractDao { + return { + address, + functions: abi.functions.map(functionAbiToFunctionDao), + deployed, + }; +} diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts new file mode 100644 index 000000000000..f086dc05cc7b --- /dev/null +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts @@ -0,0 +1,9 @@ +import { AztecAddress } from '../circuits.js'; +import { ContractAbi } from '../noir.js'; +import { ContractDao } from './contract_dao.js'; + +export interface ContractDataSource { + addContract(address: AztecAddress, abi: ContractAbi, deployed?: boolean): Promise; + getContract(address: AztecAddress): Promise; + getCode(contractAddress: AztecAddress, functionSelector: Buffer): Promise; +} diff --git a/yarn-project/aztec-rpc/src/contract_data_source/index.ts b/yarn-project/aztec-rpc/src/contract_data_source/index.ts new file mode 100644 index 000000000000..c1fad74451a6 --- /dev/null +++ b/yarn-project/aztec-rpc/src/contract_data_source/index.ts @@ -0,0 +1,3 @@ +export * from './contract_dao.js'; +export * from './contract_data_source.js'; +export * from './memory_contract_data_source.js'; diff --git a/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts new file mode 100644 index 000000000000..3f40eb39b771 --- /dev/null +++ b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts @@ -0,0 +1,22 @@ +import { AztecAddress } from '../circuits.js'; +import { ContractAbi } from '../noir.js'; +import { contractAbiToContractDao, ContractDao } from './contract_dao.js'; +import { ContractDataSource } from './contract_data_source.js'; + +export class MemoryContractDataSource implements ContractDataSource { + private contracts: ContractDao[] = []; + + public addContract(address: AztecAddress, abi: ContractAbi, deployed = false) { + this.contracts.push(contractAbiToContractDao(address, abi, deployed)); + return Promise.resolve(); + } + + public getContract(address: AztecAddress) { + return Promise.resolve(this.contracts.find(c => c.address.equals(address))); + } + + public async getCode(contractAddress: AztecAddress, functionSelector: Buffer) { + const contract = await this.getContract(contractAddress); + return contract?.functions.find(f => f.selector.equals(functionSelector))?.bytecode; + } +} diff --git a/yarn-project/aztec-rpc/src/database/database.ts b/yarn-project/aztec-rpc/src/database/database.ts new file mode 100644 index 000000000000..a0522bf61673 --- /dev/null +++ b/yarn-project/aztec-rpc/src/database/database.ts @@ -0,0 +1,7 @@ +import { TxHash } from '../aztec_node.js'; +import { ContractDataSource } from '../contract_data_source/index.js'; +import { TxDao } from './tx_dao.js'; + +export interface Database extends ContractDataSource { + getTx(txHash: TxHash): Promise; +} diff --git a/yarn-project/aztec-rpc/src/database/index.ts b/yarn-project/aztec-rpc/src/database/index.ts new file mode 100644 index 000000000000..695723d1a2e2 --- /dev/null +++ b/yarn-project/aztec-rpc/src/database/index.ts @@ -0,0 +1,3 @@ +export * from './database.js'; +export * from './memory_db.js'; +export * from './tx_dao.js'; diff --git a/yarn-project/aztec-rpc/src/database/memory_db.ts b/yarn-project/aztec-rpc/src/database/memory_db.ts new file mode 100644 index 000000000000..cda0907910a2 --- /dev/null +++ b/yarn-project/aztec-rpc/src/database/memory_db.ts @@ -0,0 +1,12 @@ +import { TxHash } from '../aztec_node.js'; +import { MemoryContractDataSource } from '../contract_data_source/index.js'; +import { Database } from './database.js'; +import { TxDao } from './tx_dao.js'; + +export class MemoryDB extends MemoryContractDataSource implements Database { + private txs: TxDao[] = []; + + public getTx(txHash: TxHash) { + return Promise.resolve(this.txs.find(tx => tx.txHash.equals(txHash))); + } +} diff --git a/yarn-project/aztec-rpc/src/database/tx_dao.ts b/yarn-project/aztec-rpc/src/database/tx_dao.ts new file mode 100644 index 000000000000..f8c3bbb93467 --- /dev/null +++ b/yarn-project/aztec-rpc/src/database/tx_dao.ts @@ -0,0 +1,14 @@ +import { TxHash } from '../aztec_node.js'; +import { AztecAddress } from '../circuits.js'; + +export class TxDao { + constructor( + public readonly txHash: TxHash, + public readonly blockHash: Buffer, + public readonly blockNumber: number, + public readonly from: AztecAddress, + public readonly to: AztecAddress | undefined, + public readonly contractAddress: AztecAddress | undefined, + public readonly error: string, + ) {} +} diff --git a/yarn-project/aztec-rpc/src/foundation.ts b/yarn-project/aztec-rpc/src/foundation.ts index 40f4a8c0bad6..aa664f0d46f3 100644 --- a/yarn-project/aztec-rpc/src/foundation.ts +++ b/yarn-project/aztec-rpc/src/foundation.ts @@ -1,5 +1,12 @@ import nodeCrypto from 'crypto'; +import { Keccak } from 'sha3'; export const randomBytes = (len: number) => { return nodeCrypto.randomBytes(len) as Buffer; }; + +export function keccak256(input: Buffer | string) { + const inputBuf = typeof input === 'string' ? Buffer.from(input) : input; + const hash = new Keccak(256); + return hash.update(inputBuf).digest(); +} diff --git a/yarn-project/aztec-rpc/src/index.ts b/yarn-project/aztec-rpc/src/index.ts index b7f1c68883ae..134755851ae3 100644 --- a/yarn-project/aztec-rpc/src/index.ts +++ b/yarn-project/aztec-rpc/src/index.ts @@ -1,33 +1,9 @@ -import { AztecAddress, EthAddress, Fr, Signature, Tx, TxHash, TxRequest } from './circuits.js'; +export * from './abi_coder/index.js'; +export * from './aztec_rpc_client/index.js'; +export * from './aztec_rpc_server/index.js'; +export * from './tx/index.js'; +// TODO - only export necessary stuffs +export * from './aztec_node.js'; export * from './circuits.js'; - -export interface TxReceipt { - txHash: TxHash; - // txIndex: number; - blockHash: Buffer; - blockNumber: number; - from: AztecAddress; - to?: AztecAddress; - contractAddress?: AztecAddress; - status: boolean; -} - -export interface AztecRPCClient { - addAccount(): Promise; - getAccounts(): Promise; - getCode(contract: AztecAddress): Promise; - createDeploymentTxRequest( - bytecode: Buffer, - args: Fr[], - portalContract: EthAddress, - contractAddressSalt: Fr, - from: AztecAddress, - ): Promise; - createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; - signTxRequest(txRequest: TxRequest): Promise; - createTx(txRequest: TxRequest, signature: Signature): Promise; - sendTx(tx: Tx): Promise; - // callTx(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress): Promise; - getTxReceipt(txHash: TxHash): Promise; -} +export * from './noir.js'; diff --git a/yarn-project/aztec-rpc/src/key_store/index.ts b/yarn-project/aztec-rpc/src/key_store/index.ts new file mode 100644 index 000000000000..6cf083f0a035 --- /dev/null +++ b/yarn-project/aztec-rpc/src/key_store/index.ts @@ -0,0 +1,3 @@ +// TODO - move to yarn-project/key-store +export * from './key_store.js'; +export * from './test_key_store.js'; diff --git a/yarn-project/aztec-rpc/src/key_store/key_pair.ts b/yarn-project/aztec-rpc/src/key_store/key_pair.ts new file mode 100644 index 000000000000..c0c7c9077a3b --- /dev/null +++ b/yarn-project/aztec-rpc/src/key_store/key_pair.ts @@ -0,0 +1,34 @@ +import { AztecAddress, Signature } from '../circuits.js'; +import { randomBytes } from '../foundation.js'; + +export interface KeyPair { + getPublicKey(): AztecAddress; + getPrivateKey(): Promise; + signMessage(message: Buffer): Promise; +} + +export class ConstantKeyPair implements KeyPair { + public static random() { + const privateKey = randomBytes(32); + const publicKey = AztecAddress.random(); + return new ConstantKeyPair(publicKey, privateKey); + } + + constructor(private publicKey: AztecAddress, private privateKey: Buffer) {} + + public getPublicKey() { + return this.publicKey; + } + + public getPrivateKey() { + return Promise.resolve(this.privateKey); + } + + public signMessage(message: Buffer) { + if (!message.length) { + throw new Error('Cannot sign over empty message.'); + } + + return Promise.resolve(Signature.random()); + } +} diff --git a/yarn-project/aztec-rpc/src/key_store/key_store.ts b/yarn-project/aztec-rpc/src/key_store/key_store.ts new file mode 100644 index 000000000000..e9fd0a684311 --- /dev/null +++ b/yarn-project/aztec-rpc/src/key_store/key_store.ts @@ -0,0 +1,8 @@ +import { AztecAddress, Signature, TxRequest } from '../circuits.js'; + +export interface KeyStore { + addAccount(): Promise; + getAccounts(): Promise; + getSigningPublicKeys(): Promise; + signTxRequest(txRequest: TxRequest): Promise; +} diff --git a/yarn-project/aztec-rpc/src/key_store/test_key_store.ts b/yarn-project/aztec-rpc/src/key_store/test_key_store.ts new file mode 100644 index 000000000000..a95423a7013d --- /dev/null +++ b/yarn-project/aztec-rpc/src/key_store/test_key_store.ts @@ -0,0 +1,34 @@ +import { TxRequest } from '../circuits.js'; +import { ConstantKeyPair, KeyPair } from './key_pair.js'; +import { KeyStore } from './key_store.js'; + +export class TestKeyStore implements KeyStore { + private accounts: KeyPair[] = []; + + constructor() { + this.accounts.push(ConstantKeyPair.random()); + } + + public addAccount() { + const keyPair = ConstantKeyPair.random(); + this.accounts.push(keyPair); + return Promise.resolve(keyPair.getPublicKey()); + } + + getAccounts() { + return Promise.resolve(this.accounts.map(a => a.getPublicKey())); + } + + getSigningPublicKeys() { + return this.getAccounts(); + } + + signTxRequest(txRequest: TxRequest) { + const account = this.accounts.find(a => a.getPublicKey().equals(txRequest.from)); + if (!account) { + throw new Error('Unknown account.'); + } + + return account.signMessage(txRequest.toBuffer()); + } +} diff --git a/yarn-project/aztec.js/src/noir.ts b/yarn-project/aztec-rpc/src/noir.ts similarity index 92% rename from yarn-project/aztec.js/src/noir.ts rename to yarn-project/aztec-rpc/src/noir.ts index b6b76d879cc8..bb91ea35b56b 100644 --- a/yarn-project/aztec.js/src/noir.ts +++ b/yarn-project/aztec-rpc/src/noir.ts @@ -93,10 +93,6 @@ export interface FunctionAbi { * The name of the function. */ name: string; - /** - * Whether the function is a constructor. - */ - // isConstructor: boolean; /** * Whether the function is secret. */ @@ -112,7 +108,7 @@ export interface FunctionAbi { /** * The ACIR bytecode of the function. */ - // bytecode: string; + bytecode: string; /** * The verification key of the function. */ @@ -124,8 +120,4 @@ export interface ContractAbi { * The functions of the contract. */ functions: FunctionAbi[]; - /** - * The ACIR bytecode of the contract. - */ - bytecode: string; } diff --git a/yarn-project/aztec-rpc/src/proof_generator/index.ts b/yarn-project/aztec-rpc/src/proof_generator/index.ts new file mode 100644 index 000000000000..0907f3cd0065 --- /dev/null +++ b/yarn-project/aztec-rpc/src/proof_generator/index.ts @@ -0,0 +1 @@ +export * from './proof_generator.js'; diff --git a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts new file mode 100644 index 000000000000..adddc5135f4e --- /dev/null +++ b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts @@ -0,0 +1,10 @@ +import { KernelCircuitProver, KernelPrivateInputs } from '../circuits.js'; + +export class ProofGenerator { + constructor(private prover: KernelCircuitProver) {} + + createProof(inputs: KernelPrivateInputs) { + // TODO - iterate + return this.prover.createProof(inputs); + } +} diff --git a/yarn-project/aztec-rpc/src/synchroniser/index.ts b/yarn-project/aztec-rpc/src/synchroniser/index.ts new file mode 100644 index 000000000000..bf023056508e --- /dev/null +++ b/yarn-project/aztec-rpc/src/synchroniser/index.ts @@ -0,0 +1 @@ +export * from './synchroniser.js'; diff --git a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts new file mode 100644 index 000000000000..7234f751574d --- /dev/null +++ b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts @@ -0,0 +1,14 @@ +import { AccountState } from '../account_state/index.js'; +import { AztecNode } from '../aztec_node.js'; +import { AztecAddress } from '../circuits.js'; +import { Database } from '../database/index.js'; + +export class Synchroniser { + private accountStates: AccountState[] = []; + + constructor(private node: AztecNode, private db: Database) {} + + getAccount(account: AztecAddress) { + return this.accountStates.find(as => as.publicKey.equals(account)); + } +} diff --git a/yarn-project/aztec-rpc/src/tx/index.ts b/yarn-project/aztec-rpc/src/tx/index.ts new file mode 100644 index 000000000000..0576563fb7f8 --- /dev/null +++ b/yarn-project/aztec-rpc/src/tx/index.ts @@ -0,0 +1 @@ +export * from './tx_receipt.js'; diff --git a/yarn-project/aztec-rpc/src/tx/tx_receipt.ts b/yarn-project/aztec-rpc/src/tx/tx_receipt.ts new file mode 100644 index 000000000000..e4671e59c51c --- /dev/null +++ b/yarn-project/aztec-rpc/src/tx/tx_receipt.ts @@ -0,0 +1,14 @@ +import { TxHash } from '../aztec_node.js'; +import { AztecAddress } from '../circuits.js'; + +export interface TxReceipt { + txHash: TxHash; + // txIndex: number; + blockHash: Buffer; + blockNumber: number; + from: AztecAddress; + to?: AztecAddress; + contractAddress?: AztecAddress; + error?: string; + status: boolean; +} diff --git a/yarn-project/aztec.js/src/abi_coder/index.ts b/yarn-project/aztec.js/src/abi_coder/index.ts index 2dcea348efde..8a6dacd1fa56 100644 --- a/yarn-project/aztec.js/src/abi_coder/index.ts +++ b/yarn-project/aztec.js/src/abi_coder/index.ts @@ -1,5 +1,4 @@ -import { ABIParameter } from '../noir.js'; -import { keccak256 } from './keccak256.js'; +import { ABIParameter } from '@aztec/aztec-rpc'; export * from './hex_string.js'; @@ -7,14 +6,6 @@ function pack(parameter: ABIParameter, value: any) { return Buffer.alloc(32); } -export function generateFunctionSignature(name: string, parameters: ABIParameter[]) { - return `${name}(${parameters.map(p => p.type.kind).join(',')})`; -} - -export function encodeFunctionSignature(signature: string) { - return keccak256(Buffer.from(signature)).slice(0, 4); -} - export function encodeParameters(parameters: ABIParameter[], args: any[]) { if (parameters.length !== args.length) { throw new Error(`Incorrect number of args. Expect ${parameters.length}. Got ${args.length}.`); diff --git a/yarn-project/aztec.js/src/abi_coder/keccak256.ts b/yarn-project/aztec.js/src/abi_coder/keccak256.ts deleted file mode 100644 index b03ac89ead4a..000000000000 --- a/yarn-project/aztec.js/src/abi_coder/keccak256.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Keccak } from 'sha3'; - -export function keccak256(input: Buffer | string) { - const inputBuf = typeof input === 'string' ? Buffer.from(input) : input; - const hash = new Keccak(256); - return hash.update(inputBuf).digest(); -} diff --git a/yarn-project/aztec.js/src/contract/contract_function.ts b/yarn-project/aztec.js/src/contract/contract_function.ts index 19d211f4f148..6305c3e3a731 100644 --- a/yarn-project/aztec.js/src/contract/contract_function.ts +++ b/yarn-project/aztec.js/src/contract/contract_function.ts @@ -1,11 +1,11 @@ -import { encodeFunctionSignature, encodeParameters, generateFunctionSignature } from '../abi_coder/index.js'; -import { FunctionAbi } from '../noir.js'; +import { FunctionAbi, generateFunctionSelector } from '@aztec/aztec-rpc'; +import { encodeParameters } from '../abi_coder/index.js'; export class ContractFunction { constructor(private abi: FunctionAbi) {} public encodeABI() { - return encodeFunctionSignature(generateFunctionSignature(this.abi.name, this.abi.parameters)); + return generateFunctionSelector(this.abi.name, this.abi.parameters); } public encodeParameters(args: any[]) { diff --git a/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts b/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts index 811cf95acf7a..ea21d42197a0 100644 --- a/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts +++ b/yarn-project/aztec.js/src/contract_deployer/constructor_method.ts @@ -1,7 +1,5 @@ -import { AztecAddress, AztecRPCClient, EthAddress, Fr } from '@aztec/aztec-rpc'; -import { hexToBuffer } from '../abi_coder/index.js'; +import { AztecAddress, AztecRPCClient, ContractAbi, EthAddress, Fr } from '@aztec/aztec-rpc'; import { ContractFunction, SendMethod, SendMethodOptions } from '../contract/index.js'; -import { ContractAbi } from '../noir.js'; export interface ConstructorOptions extends SendMethodOptions { contractAddressSalt?: Fr; @@ -23,13 +21,13 @@ export class ConstructorMethod extends SendMethod { throw new Error('Cannot find constructor in the ABI.'); } - super(arc, EthAddress.ZERO, new ContractFunction(constructorAbi), args, defaultOptions); + super(arc, AztecAddress.ZERO, new ContractFunction(constructorAbi), args, defaultOptions); } public async request(options: ConstructorOptions = {}) { const { contractAddressSalt, from } = { ...this.defaultOptions, ...options }; this.txRequest = await this.arc.createDeploymentTxRequest( - hexToBuffer(this.abi.bytecode), + this.abi, this.entry.encodeParameters(this.args).map(p => new Fr(p)), this.portalContract, contractAddressSalt || Fr.random(), diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts index 89bb977c00de..3e2b5f3aafeb 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts @@ -2,6 +2,7 @@ import { mock } from 'jest-mock-extended'; import { AztecAddress, AztecRPCClient, + ContractAbi, EthAddress, Fr, Signature, @@ -10,13 +11,11 @@ import { TxReceipt, TxRequest, } from '@aztec/aztec-rpc'; -import { ContractAbi } from '../noir.js'; import { ContractDeployer } from './contract_deployer.js'; describe('Contract Deployer', () => { let arc: ReturnType>; - const bytecodeBuf = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]); const abi: ContractAbi = { functions: [ { @@ -24,10 +23,10 @@ describe('Contract Deployer', () => { isSecret: true, parameters: [], returnTypes: [], + bytecode: '0x01234567', verificationKey: '0x98765432', }, ], - bytecode: `0x${bytecodeBuf.toString('hex')}`, }; const portalContract = EthAddress.random(); @@ -62,13 +61,7 @@ describe('Contract Deployer', () => { expect(txHash).toBe(mockTxHash); expect(receipt).toBe(mockTxReceipt); expect(arc.createDeploymentTxRequest).toHaveBeenCalledTimes(1); - expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( - bytecodeBuf, - [], - portalContract, - contractAddressSalt, - account, - ); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith(abi, [], portalContract, contractAddressSalt, account); expect(arc.createTxRequest).toHaveBeenCalledTimes(0); expect(arc.signTxRequest).toHaveBeenCalledTimes(1); expect(arc.signTxRequest).toHaveBeenCalledWith(mockTxRequest); @@ -94,13 +87,7 @@ describe('Contract Deployer', () => { expect(tx).toBe(mockTx); expect(receipt).toBe(mockTxReceipt); expect(arc.createDeploymentTxRequest).toHaveBeenCalledTimes(1); - expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( - bytecodeBuf, - [], - portalContract, - contractAddressSalt, - account, - ); + expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith(abi, [], portalContract, contractAddressSalt, account); expect(arc.createTxRequest).toHaveBeenCalledTimes(0); expect(arc.signTxRequest).toHaveBeenCalledTimes(1); expect(arc.createTx).toHaveBeenCalledTimes(1); @@ -112,7 +99,7 @@ describe('Contract Deployer', () => { const deployment = deployer.deploy(); await deployment.request(); expect(arc.createDeploymentTxRequest).toHaveBeenCalledWith( - bytecodeBuf, + abi, [], EthAddress.ZERO, // portalContract expect.anything(), // contractAddressSalt diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts index 2b2c5522e8f5..8f863bccccad 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts @@ -1,5 +1,4 @@ -import { AztecRPCClient, EthAddress } from '@aztec/aztec-rpc'; -import { ContractAbi } from '../noir.js'; +import { AztecRPCClient, ContractAbi, EthAddress } from '@aztec/aztec-rpc'; import { ConstructorMethod, ConstructorOptions } from './constructor_method.js'; /** diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 3034c9da3631..64f67ec0e271 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -1,3 +1,5 @@ -export * from '@aztec/aztec-rpc'; export * from './contract/index.js'; export * from './contract_deployer/index.js'; + +// TODO - only export necessary stuffs +export * from '@aztec/aztec-rpc';