diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 0595ca3a688..2de68f9d980 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -275,8 +275,8 @@ library Decoder { * newContractDataKernel2.ethAddress (padded to 32 bytes), ____ * encryptedLogsHashKernel1, | * encryptedLogsHashKernel2, |=> Computed below from logs' preimages. - * unencryptedLogsHashKernel1, | - * unencryptedLogsHashKernel2 ___| + * unencryptedLogsHashKernel1, | + * unencryptedLogsHashKernel2 ____| * ); * Note that we always read data, the l2Block (atm) must therefore include dummy or zero-notes for * Zero values. diff --git a/l1-contracts/src/periphery/ContractDeploymentEmitter.sol b/l1-contracts/src/periphery/ContractDeploymentEmitter.sol index f464be105ac..f2f791d7b45 100644 --- a/l1-contracts/src/periphery/ContractDeploymentEmitter.sol +++ b/l1-contracts/src/periphery/ContractDeploymentEmitter.sol @@ -19,15 +19,33 @@ contract ContractDeploymentEmitter is IContractDeploymentEmitter { * @param _aztecAddress - The address of the L2 counterparty * @param _portalAddress - The address of the L1 counterparty * @param _l2BlockHash - The hash of the L2 block that this is related to + * @param _partialAddress - The partial address of the deployed contract + * @param _pubKeyX - The x coordinate of the contract's public key + * @param _pubKeyY - The y coordinate of the contract's public key * @param _acir - The acir bytecode of the L2 contract + * @dev See the link bellow for more info on partial address and public key: + * https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys + * TODO: replace the link above with the link to deployed docs */ function emitContractDeployment( uint256 _l2BlockNum, bytes32 _aztecAddress, address _portalAddress, bytes32 _l2BlockHash, + bytes32 _partialAddress, + bytes32 _pubKeyX, + bytes32 _pubKeyY, bytes calldata _acir ) external override(IContractDeploymentEmitter) { - emit ContractDeployment(_l2BlockNum, _aztecAddress, _portalAddress, _l2BlockHash, _acir); + emit ContractDeployment( + _l2BlockNum, + _aztecAddress, + _portalAddress, + _l2BlockHash, + _partialAddress, + _pubKeyX, + _pubKeyY, + _acir + ); } } diff --git a/l1-contracts/src/periphery/interfaces/IContractDeploymentEmitter.sol b/l1-contracts/src/periphery/interfaces/IContractDeploymentEmitter.sol index 25ee6c13a28..f89142e58e9 100644 --- a/l1-contracts/src/periphery/interfaces/IContractDeploymentEmitter.sol +++ b/l1-contracts/src/periphery/interfaces/IContractDeploymentEmitter.sol @@ -15,13 +15,22 @@ interface IContractDeploymentEmitter { * @param aztecAddress - The address of the L2 counterparty * @param portalAddress - The address of the L1 counterparty * @param l2BlockHash - The hash of the L2 block that this is related to + * @param partialAddress - The partial address of the deployed contract + * @param pubKeyX - The x coordinate of the contract's public key + * @param pubKeyY - The y coordinate of the contract's public key * @param acir - The acir bytecode of the L2 contract + * @dev See the link bellow for more info on partial address and public key: + * https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys + * TODO: replace the link above with the link to deployed docs */ event ContractDeployment( uint256 indexed l2BlockNum, bytes32 indexed aztecAddress, address indexed portalAddress, bytes32 l2BlockHash, + bytes32 partialAddress, + bytes32 pubKeyX, + bytes32 pubKeyY, bytes acir ); @@ -30,6 +39,9 @@ interface IContractDeploymentEmitter { bytes32 _aztecAddress, address _portalAddress, bytes32 _l2BlockHash, + bytes32 _partialAddress, + bytes32 _pubKeyX, + bytes32 _pubKeyY, bytes calldata _acir ) external; } diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index fdfddff81f9..612223426a7 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -3,14 +3,7 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { sleep } from '@aztec/foundation/sleep'; import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; -import { - ContractData, - ContractDataAndBytecode, - EncodedContractFunction, - L2Block, - L2BlockL2Logs, - LogType, -} from '@aztec/types'; +import { ExtendedContractData, L2Block, L2BlockL2Logs, LogType } from '@aztec/types'; import { MockProxy, mock } from 'jest-mock-extended'; import { Chain, HttpTransport, Log, PublicClient, Transaction, encodeFunctionData, toHex } from 'viem'; @@ -155,21 +148,18 @@ function makeL2BlockProcessedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { * @returns An ContractDeployment event. */ function makeContractDeploymentEvent(l1BlockNum: bigint, l2Block: L2Block) { - // const contractData = ContractData.random(); - const aztecAddress = AztecAddress.random(); - const portalAddress = EthAddress.random(); - const contractData = new ContractDataAndBytecode(new ContractData(aztecAddress, portalAddress), [ - EncodedContractFunction.random(), - EncodedContractFunction.random(), - ]); - const acir = contractData.bytecode?.toString('hex'); + const extendedContractData = ExtendedContractData.random(); + const acir = extendedContractData.bytecode?.toString('hex'); return { blockNumber: l1BlockNum, args: { l2BlockNum: BigInt(l2Block.number), - aztecAddress: aztecAddress.toString(), - portalAddress: portalAddress.toString(), + aztecAddress: extendedContractData.contractData.contractAddress.toString(), + portalAddress: extendedContractData.contractData.portalContractAddress.toString(), l2BlockHash: `0x${l2Block.getCalldataHash().toString('hex')}`, + partialAddress: extendedContractData.partialAddress.toString(true), + pubKeyX: extendedContractData.publicKey.x.toString(true), + pubKeyY: extendedContractData.publicKey.y.toString(true), acir: '0x' + acir, }, transactionHash: `0x${l2Block.number}`, diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index e99856bafa2..6c88251805d 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -7,9 +7,9 @@ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { ContractData, - ContractDataAndBytecode, ContractDataSource, EncodedContractFunction, + ExtendedContractData, INITIAL_L2_BLOCK_NUM, L1ToL2Message, L1ToL2MessageSource, @@ -224,9 +224,9 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource // store contracts for which we have retrieved L2 blocks const lastKnownL2BlockNum = retrievedBlocks.retrievedData[retrievedBlocks.retrievedData.length - 1].number; retrievedContracts.retrievedData.forEach(async ([contracts, l2BlockNum], index) => { - this.log(`Retrieved contract data and bytecode for l2 block number: ${index}`); + this.log(`Retrieved extended contract data for l2 block number: ${index}`); if (l2BlockNum <= lastKnownL2BlockNum) { - await this.store.addContractDataAndBytecode(contracts, l2BlockNum); + await this.store.addExtendedContractData(contracts, l2BlockNum); } }); @@ -293,13 +293,12 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource } /** - * Lookup the L2 contract data for this contract. - * Contains the contract's public function bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The contract data. + * @returns The extended contract data or undefined if not found. */ - public getContractDataAndBytecode(contractAddress: AztecAddress): Promise { - return this.store.getContractDataAndBytecode(contractAddress); + getExtendedContractData(contractAddress: AztecAddress): Promise { + return this.store.getExtendedContractData(contractAddress); } /** @@ -307,8 +306,8 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource * @param blockNum - The block number to get all contract data from. * @returns All new contract data in the block (if found). */ - public getContractDataAndBytecodeInBlock(blockNum: number): Promise { - return this.store.getContractDataAndBytecodeInBlock(blockNum); + public getExtendedContractDataInBlock(blockNum: number): Promise { + return this.store.getExtendedContractDataInBlock(blockNum); } /** @@ -341,7 +340,7 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource contractAddress: AztecAddress, selector: FunctionSelector, ): Promise { - const contractData = await this.getContractDataAndBytecode(contractAddress); + const contractData = await this.getExtendedContractData(contractAddress); return contractData?.getPublicFunction(selector); } diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 7dcf50ca4f3..b64a973f677 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -2,7 +2,7 @@ import { Fr, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { ContractData, - ContractDataAndBytecode, + ExtendedContractData, INITIAL_L2_BLOCK_NUM, L1ToL2Message, L2Block, @@ -16,7 +16,7 @@ import { L1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_messag /** * Interface describing a data store to be used by the archiver to store all its relevant data - * (blocks, encrypted logs, aztec contract data and bytecode). + * (blocks, encrypted logs, aztec contract data extended contract data). */ export interface ArchiverDataStore { /** @@ -95,26 +95,26 @@ export interface ArchiverDataStore { getLogs(from: number, limit: number, logType: LogType): Promise; /** - * Store new Contract data and bytecode from an L2 block to the store's list. + * Add new extended contract data from an L2 block to the store's list. * @param data - List of contracts' data to be added. * @param blockNum - Number of the L2 block the contract data was deployed in. * @returns True if the operation is successful. */ - addContractDataAndBytecode(data: ContractDataAndBytecode[], blockNum: number): Promise; + addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise; /** - * Lookup the L2 contract data for a contract address. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The contract's public data. + * @returns The extended contract data or undefined if not found. */ - getContractDataAndBytecode(contractAddress: AztecAddress): Promise; + getExtendedContractData(contractAddress: AztecAddress): Promise; /** - * Lookup all contract data and bytecode in an L2 block. + * Lookup all extended contract data in an L2 block. * @param blockNum - The block number to get all contract data from. - * @returns All contract data and bytecode in the block (if found). + * @returns All extended contract data in the block (if found). */ - getContractDataAndBytecodeInBlock(blockNum: number): Promise; + getExtendedContractDataInBlock(blockNum: number): Promise; /** * Get basic info for an L2 contract. @@ -172,14 +172,14 @@ export class MemoryArchiverStore implements ArchiverDataStore { private unencryptedLogs: L2BlockL2Logs[] = []; /** - * A sparse array containing all the contract data and bytecode that have been fetched so far. + * A sparse array containing all the extended contract data that have been fetched so far. */ - private contractDataAndBytecodeByBlock: (ContractDataAndBytecode[] | undefined)[] = []; + private extendedContractDataByBlock: (ExtendedContractData[] | undefined)[] = []; /** - * A mapping of contract address to contract data and bytecode. + * A mapping of contract address to extended contract data. */ - private contractDataAndBytecode: Map = new Map(); + private extendedContractData: Map = new Map(); /** * Contains all the confirmed L1 to L2 messages (i.e. messages that were consumed in an L2 block) @@ -255,23 +255,23 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Store new Contract data and bytecode from an L2 block to the store's list. + * Store new extended contract data from an L2 block to the store's list. * @param data - List of contracts' data to be added. * @param blockNum - Number of the L2 block the contract data was deployed in. * @returns True if the operation is successful (always in this implementation). */ - public addContractDataAndBytecode(data: ContractDataAndBytecode[], blockNum: number): Promise { + public addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise { // Add to the contracts mapping for (const contractData of data) { const key = contractData.contractData.contractAddress.toString(); - this.contractDataAndBytecode.set(key, contractData); + this.extendedContractData.set(key, contractData); } // Add the index per block - if (this.contractDataAndBytecodeByBlock[blockNum]?.length) { - this.contractDataAndBytecodeByBlock[blockNum]?.push(...data); + if (this.extendedContractDataByBlock[blockNum]?.length) { + this.extendedContractDataByBlock[blockNum]?.push(...data); } else { - this.contractDataAndBytecodeByBlock[blockNum] = [...data]; + this.extendedContractDataByBlock[blockNum] = [...data]; } return Promise.resolve(true); } @@ -348,25 +348,25 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Lookup the L2 contract data for a contract address. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The contract's public data. + * @returns The extended contract data or undefined if not found. */ - public getContractDataAndBytecode(contractAddress: AztecAddress): Promise { - const result = this.contractDataAndBytecode.get(contractAddress.toString()); + getExtendedContractData(contractAddress: AztecAddress): Promise { + const result = this.extendedContractData.get(contractAddress.toString()); return Promise.resolve(result); } /** * Lookup all contract data in an L2 block. * @param blockNum - The block number to get all contract data from. - * @returns All contract data and bytecode in the block (if found). + * @returns All extended contract data in the block (if found). */ - public getContractDataAndBytecodeInBlock(blockNum: number): Promise { + public getExtendedContractDataInBlock(blockNum: number): Promise { if (blockNum > this.l2Blocks.length) { return Promise.resolve([]); } - return Promise.resolve(this.contractDataAndBytecodeByBlock[blockNum] || []); + return Promise.resolve(this.extendedContractDataByBlock[blockNum] || []); } /** diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index c7d27d6d085..c1005b55137 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -1,6 +1,6 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -import { ContractDataAndBytecode, L1ToL2Message, L2Block } from '@aztec/types'; +import { ExtendedContractData, L1ToL2Message, L2Block } from '@aztec/types'; import { PublicClient } from 'viem'; @@ -73,7 +73,7 @@ export async function retrieveBlocks( * @param currentBlockNumber - Latest available block number in the ETH node. * @param searchStartBlock - The block number to use for starting the search. * @param blockHashMapping - A mapping from block number to relevant block hash. - * @returns An array of ContractDataAndBytecode and their equivalent L2 Block number along with the next eth block to search from.. + * @returns An array of ExtendedContractData and their equivalent L2 Block number along with the next eth block to search from.. */ export async function retrieveNewContractData( publicClient: PublicClient, @@ -82,8 +82,8 @@ export async function retrieveNewContractData( currentBlockNumber: bigint, searchStartBlock: bigint, blockHashMapping: { [key: number]: Buffer | undefined }, -): Promise> { - let retrievedNewContracts: [ContractDataAndBytecode[], number][] = []; +): Promise> { + let retrievedNewContracts: [ExtendedContractData[], number][] = []; do { if (searchStartBlock > currentBlockNumber) { break; diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index df9ebcf5bc3..58f94109efc 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -1,12 +1,12 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { Fr } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { BufferReader, ContractData, - ContractDataAndBytecode, EncodedContractFunction, + ExtendedContractData, L1Actor, L1ToL2Message, L2Actor, @@ -163,13 +163,13 @@ export async function getContractDeploymentLogs( * Processes newly received ContractDeployment logs. * @param blockHashMapping - A mapping from block number to relevant block hash. * @param logs - ContractDeployment logs. - * @returns The set of retrieved contract data and bytecode items. + * @returns The set of retrieved extended contract data items. */ export function processContractDeploymentLogs( blockHashMapping: { [key: number]: Buffer | undefined }, logs: Log[], -): [ContractDataAndBytecode[], number][] { - const contractDataAndBytecode: [ContractDataAndBytecode[], number][] = []; +): [ExtendedContractData[], number][] { + const extendedContractData: [ExtendedContractData[], number][] = []; for (let i = 0; i < logs.length; i++) { const log = logs[i]; const l2BlockNum = Number(log.args.l2BlockNum); @@ -179,17 +179,25 @@ export function processContractDeploymentLogs( continue; } const publicFnsReader = BufferReader.asReader(Buffer.from(log.args.acir.slice(2), 'hex')); - const contractData = new ContractDataAndBytecode( + const partialAddress = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.partialAddress))); + const publicKey = new Point( + Fr.fromBuffer(Buffer.from(hexToBytes(log.args.pubKeyX))), + Fr.fromBuffer(Buffer.from(hexToBytes(log.args.pubKeyY))), + ); + + const contractData = new ExtendedContractData( new ContractData(AztecAddress.fromString(log.args.aztecAddress), EthAddress.fromString(log.args.portalAddress)), publicFnsReader.readVector(EncodedContractFunction), + partialAddress, + publicKey, ); - if (contractDataAndBytecode[i]) { - contractDataAndBytecode[i][0].push(contractData); + if (extendedContractData[i]) { + extendedContractData[i][0].push(contractData); } else { - contractDataAndBytecode[i] = [[contractData], l2BlockNum]; + extendedContractData[i] = [[contractData], l2BlockNum]; } } - return contractDataAndBytecode; + return extendedContractData; } /** diff --git a/yarn-project/aztec-cli/src/index.ts b/yarn-project/aztec-cli/src/index.ts index a72998d7c1a..d19200d8f61 100644 --- a/yarn-project/aztec-cli/src/index.ts +++ b/yarn-project/aztec-cli/src/index.ts @@ -222,7 +222,7 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { const client = await createCompatibleClient(options.rpcUrl, debugLogger); const address = AztecAddress.fromString(contractAddress); const contractDataWithOrWithoutBytecode = options.includeBytecode - ? await client.getContractDataAndBytecode(address) + ? await client.getExtendedContractData(address) : await client.getContractData(address); if (!contractDataWithOrWithoutBytecode) { diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts index 86faa5950c8..45de1625658 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts @@ -3,7 +3,7 @@ import { randomBytes } from '@aztec/foundation/crypto'; import { Pedersen } from '@aztec/merkle-tree'; import { ContractData, - ContractDataAndBytecode, + ExtendedContractData, L1ToL2Message, L2Block, L2BlockL2Logs, @@ -158,21 +158,21 @@ describe('HttpNode', () => { }); }); - describe('getContractDataAndBytecode', () => { + describe('getExtendedContractData', () => { it('should fetch and return contract public data', async () => { - const contractDataAndBytecode = ContractDataAndBytecode.random(); + const extendedContractData = ExtendedContractData.random(); const response = { - contractData: contractDataAndBytecode.toBuffer(), + contractData: extendedContractData.toBuffer(), }; setFetchMock(response); - const result = await httpNode.getContractDataAndBytecode(contractDataAndBytecode.contractData.contractAddress); + const result = await httpNode.getExtendedContractData(extendedContractData.contractData.contractAddress); expect(fetch).toHaveBeenCalledWith( - `${TEST_URL}contract-data-and-bytecode?address=${contractDataAndBytecode.contractData.contractAddress.toString()}`, + `${TEST_URL}contract-data-and-bytecode?address=${extendedContractData.contractData.contractAddress.toString()}`, ); - expect(result).toEqual(contractDataAndBytecode); + expect(result).toEqual(extendedContractData); }); it('should return undefined if contract data is not available', async () => { @@ -183,7 +183,7 @@ describe('HttpNode', () => { const randomAddress = AztecAddress.random(); - const result = await httpNode.getContractDataAndBytecode(randomAddress); + const result = await httpNode.getExtendedContractData(randomAddress); expect(fetch).toHaveBeenCalledWith(`${TEST_URL}contract-data-and-bytecode?address=${randomAddress.toString()}`); expect(result).toEqual(undefined); diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.ts b/yarn-project/aztec-node/src/aztec-node/http-node.ts index 363f15301a6..a102dc258b4 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.ts @@ -11,7 +11,7 @@ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { AztecNode, ContractData, - ContractDataAndBytecode, + ExtendedContractData, L1ToL2Message, L1ToL2MessageAndIndex, L2Block, @@ -120,12 +120,11 @@ export class HttpNode implements AztecNode { } /** - * Lookup the contract data for this contract. - * Contains the ethereum portal address and bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The complete contract data including portal address & bytecode (if we didn't throw an error). + * @returns The extended contract data or undefined if not found. */ - async getContractDataAndBytecode(contractAddress: AztecAddress): Promise { + async getExtendedContractData(contractAddress: AztecAddress): Promise { const url = new URL(`${this.baseUrl}/contract-data-and-bytecode`); url.searchParams.append('address', contractAddress.toString()); const response = await (await fetch(url.toString())).json(); @@ -133,7 +132,7 @@ export class HttpNode implements AztecNode { return undefined; } const contract = response.contractData as string; - return Promise.resolve(ContractDataAndBytecode.fromBuffer(Buffer.from(contract, 'hex'))); + return Promise.resolve(ExtendedContractData.fromBuffer(Buffer.from(contract, 'hex'))); } /** diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 09b03ab0d2f..cccec0aa8d8 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -15,8 +15,8 @@ import { SequencerClient } from '@aztec/sequencer-client'; import { AztecNode, ContractData, - ContractDataAndBytecode, ContractDataSource, + ExtendedContractData, L1ToL2MessageAndIndex, L1ToL2MessageSource, L2Block, @@ -171,13 +171,12 @@ export class AztecNodeService implements AztecNode { } /** - * Lookup the L2 contract data for this contract. - * Contains the ethereum portal address and bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The complete contract data including portal address & bytecode (if we didn't throw an error). + * @returns The extended contract data or undefined if not found. */ - public async getContractDataAndBytecode(contractAddress: AztecAddress): Promise { - return await this.contractDataSource.getContractDataAndBytecode(contractAddress); + async getExtendedContractData(contractAddress: AztecAddress): Promise { + return await this.contractDataSource.getExtendedContractData(contractAddress); } /** diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_http/aztec_rpc_http_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_http/aztec_rpc_http_server.ts index c3e8510e12a..509de59af8a 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_http/aztec_rpc_http_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_http/aztec_rpc_http_server.ts @@ -5,8 +5,7 @@ import { AztecRPC, CompleteAddress, ContractData, - ContractDataAndBytecode, - ContractDeploymentTx, + ExtendedContractData, L2BlockL2Logs, PrivateKey, Tx, @@ -33,14 +32,14 @@ export function getHttpRpcServer(aztecRpcServer: AztecRPC): JsonRpcServer { AztecAddress, TxExecutionRequest, ContractData, - ContractDataAndBytecode, + ExtendedContractData, TxHash, EthAddress, Point, PrivateKey, Fr, }, - { Tx, ContractDeploymentTx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs }, false, ['start', 'stop'], ); 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 index 73800bc8f41..bdb66131827 100644 --- 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 @@ -7,6 +7,7 @@ import { import { AztecAddress, CompleteAddress, + EthAddress, FunctionData, KernelCircuitPublicInputs, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -16,15 +17,15 @@ import { } from '@aztec/circuits.js'; import { encodeArguments } from '@aztec/foundation/abi'; import { padArrayEnd } from '@aztec/foundation/collection'; -import { Fr } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { AztecNode, AztecRPC, ContractDao, ContractData, - ContractDataAndBytecode, DeployedContract, + ExtendedContractData, FunctionCall, INITIAL_L2_BLOCK_NUM, KeyStore, @@ -148,17 +149,17 @@ export class AztecRPCServer implements AztecRPC { } public async addContracts(contracts: DeployedContract[]) { - const contractDaos = contracts.map(c => toContractDao(c.abi, c.address, c.portalContract)); + const contractDaos = contracts.map(c => toContractDao(c.abi, c.completeAddress, c.portalContract)); await Promise.all(contractDaos.map(c => this.db.addContract(c))); for (const contract of contractDaos) { const portalInfo = contract.portalContract && !contract.portalContract.isZero() ? ` with portal ${contract.portalContract}` : ''; - this.log.info(`Added contract ${contract.name} at ${contract.address}${portalInfo}`); + this.log.info(`Added contract ${contract.name} at ${contract.completeAddress.address}${portalInfo}`); } } public async getContracts(): Promise { - return (await this.db.getContracts()).map(c => c.address); + return (await this.db.getContracts()).map(c => c.completeAddress.address); } public async getPublicStorageAt(contract: AztecAddress, storageSlot: Fr) { @@ -239,8 +240,8 @@ export class AztecRPCServer implements AztecRPC { return await this.node.getBlockNumber(); } - public async getContractDataAndBytecode(contractAddress: AztecAddress): Promise { - return await this.node.getContractDataAndBytecode(contractAddress); + public async getExtendedContractData(contractAddress: AztecAddress): Promise { + return await this.node.getExtendedContractData(contractAddress); } public async getContractData(contractAddress: AztecAddress): Promise { @@ -396,18 +397,19 @@ export class AztecRPCServer implements AztecRPC { const unencryptedLogs = new TxL2Logs(collectUnencryptedLogs(executionResult)); const enqueuedPublicFunctions = collectEnqueuedPublicFunctionCalls(executionResult); + const contractData = new ContractData(newContract?.completeAddress.address ?? AztecAddress.ZERO, EthAddress.ZERO); + const extendedContractData = new ExtendedContractData( + contractData, + newContractPublicFunctions, + newContract?.completeAddress.partialAddress ?? Fr.ZERO, + newContract?.completeAddress.publicKey ?? Point.ZERO, + ); + // HACK(#1639): Manually patches the ordering of the public call stack // TODO(#757): Enforce proper ordering of enqueued public calls await this.patchPublicCallStackOrdering(publicInputs, enqueuedPublicFunctions); - return new Tx( - publicInputs, - proof, - encryptedLogs, - unencryptedLogs, - newContractPublicFunctions, - enqueuedPublicFunctions, - ); + return new Tx(publicInputs, proof, encryptedLogs, unencryptedLogs, enqueuedPublicFunctions, [extendedContractData]); } // HACK(#1639): this is a hack to fix ordering of public calls enqueued in the call stack. Since the private kernel diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/test/aztec_rpc_test_suite.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/test/aztec_rpc_test_suite.ts index 0747e1149ef..9571dfd7ce9 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/test/aztec_rpc_test_suite.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/test/aztec_rpc_test_suite.ts @@ -86,10 +86,10 @@ export const aztecRpcTestSuite = (testName: string, aztecRpcSetup: () => Promise }); it('successfully adds a contract', async () => { - const contracts: DeployedContract[] = [randomDeployedContract(), randomDeployedContract()]; + const contracts: DeployedContract[] = [await randomDeployedContract(), await randomDeployedContract()]; await rpc.addContracts(contracts); - const expectedContractAddresses = contracts.map(contract => contract.address); + const expectedContractAddresses = contracts.map(contract => contract.completeAddress.address); const contractAddresses = await rpc.getContracts(); // check if all the contracts were returned @@ -122,7 +122,7 @@ export const aztecRpcTestSuite = (testName: string, aztecRpcSetup: () => Promise ); }); - // Note: Not testing `getContractDataAndBytecode`, `getContractData` and `getUnencryptedLogs` here as these + // Note: Not testing `getExtendedContractData`, `getContractData` and `getUnencryptedLogs` here as these // functions only call AztecNode and these methods are frequently used by the e2e tests. it('successfully gets a block number', async () => { diff --git a/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts b/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts index ef05b49e3fb..f398edfe86b 100644 --- a/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/contract_data_oracle/index.ts @@ -135,7 +135,7 @@ export class ContractDataOracle { * @throws An Error if the contract is not found in the ContractDatabase. */ private async getTree(contractAddress: AztecAddress) { - let tree = this.trees.find(t => t.contract.address.equals(contractAddress)); + let tree = this.trees.find(t => t.contract.completeAddress.address.equals(contractAddress)); if (!tree) { const contract = await this.db.getContract(contractAddress); if (!contract) { diff --git a/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts b/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts index e32961f8bb2..a8b84dafda6 100644 --- a/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts +++ b/yarn-project/aztec-rpc/src/contract_database/memory_contract_database.ts @@ -22,7 +22,7 @@ export class MemoryContractDatabase implements ContractDatabase { * @returns A Promise that resolves when the contract is successfully added. */ public addContract(contract: ContractDao) { - this.log(`Adding contract ${contract.address.toString()}`); + this.log(`Adding contract ${contract.completeAddress.address.toString()}`); this.contracts.push(contract); return Promise.resolve(); } @@ -35,7 +35,7 @@ export class MemoryContractDatabase implements ContractDatabase { * @returns A Promise resolving to the ContractDao instance matching the given address or undefined. */ public getContract(address: AztecAddress): Promise { - return Promise.resolve(this.contracts.find(c => c.address.equals(address))); + return Promise.resolve(this.contracts.find(c => c.completeAddress.address.equals(address))); } public getContracts(): Promise { diff --git a/yarn-project/aztec-rpc/src/contract_tree/index.ts b/yarn-project/aztec-rpc/src/contract_tree/index.ts index 9c1d48a9e14..8bb6166266f 100644 --- a/yarn-project/aztec-rpc/src/contract_tree/index.ts +++ b/yarn-project/aztec-rpc/src/contract_tree/index.ts @@ -1,6 +1,7 @@ import { CONTRACT_TREE_HEIGHT, CircuitsWasm, + CompleteAddress, EthAddress, FUNCTION_TREE_HEIGHT, Fr, @@ -19,6 +20,7 @@ import { computeContractAddress, computeContractLeaf, computeFunctionTreeRoot, + computePartialAddress, computeVarArgsHash, hashConstructor, } from '@aztec/circuits.js/abis'; @@ -93,10 +95,15 @@ export class ContractTree { const vkHash = hashVKStr(constructorAbi.verificationKey, wasm); const argsHash = await computeVarArgsHash(wasm, args); const constructorHash = hashConstructor(wasm, functionData, argsHash, vkHash); + // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/1873: create computeCompleteAddress + // function --> The following is wasteful as it computes partial address twice + const partialAddress = computePartialAddress(wasm, contractAddressSalt, root, constructorHash); const address = computeContractAddress(wasm, from, contractAddressSalt, root, constructorHash); + const completeAddress = await CompleteAddress.create(address, from, partialAddress); + const contractDao: ContractDao = { ...abi, - address, + completeAddress, functions, portalContract, }; @@ -119,7 +126,7 @@ export class ContractTree { const abi = this.contract.functions.find(f => f.selector.equals(selector)); if (!abi) { throw new Error( - `Unknown function. Selector ${selector.toString()} not found in the ABI of contract ${this.contract.address.toString()}. Expected one of: ${this.contract.functions + `Unknown function. Selector ${selector.toString()} not found in the ABI of contract ${this.contract.completeAddress.address.toString()}. Expected one of: ${this.contract.functions .map(f => f.selector.toString()) .join(', ')}`, ); @@ -151,14 +158,14 @@ export class ContractTree { */ public async getContractMembershipWitness() { if (!this.contractMembershipWitness) { - const { address, portalContract } = this.contract; + const { completeAddress, portalContract } = this.contract; const root = await this.getFunctionTreeRoot(); - const newContractData = new NewContractData(address, portalContract, root); + const newContractData = new NewContractData(completeAddress.address, portalContract, root); const commitment = computeContractLeaf(this.wasm, newContractData); const index = await this.contractCommitmentProvider.findContractIndex(commitment.toBuffer()); if (index === undefined) { throw new Error( - `Failed to find contract at ${address} with portal ${portalContract} resulting in commitment ${commitment}.`, + `Failed to find contract at ${completeAddress.address} with portal ${portalContract} resulting in commitment ${commitment}.`, ); } diff --git a/yarn-project/aztec.js/src/aztec_rpc_client/aztec_rpc_client.ts b/yarn-project/aztec.js/src/aztec_rpc_client/aztec_rpc_client.ts index 09ccdcad49f..3add6a538d5 100644 --- a/yarn-project/aztec.js/src/aztec_rpc_client/aztec_rpc_client.ts +++ b/yarn-project/aztec.js/src/aztec_rpc_client/aztec_rpc_client.ts @@ -3,8 +3,7 @@ import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/cl import { AztecRPC, ContractData, - ContractDataAndBytecode, - ContractDeploymentTx, + ExtendedContractData, L2BlockL2Logs, Tx, TxExecutionRequest, @@ -22,14 +21,14 @@ export const createAztecRpcClient = (url: string, fetch = defaultFetch): AztecRP AztecAddress, TxExecutionRequest, ContractData, - ContractDataAndBytecode, + ExtendedContractData, TxHash, EthAddress, Point, PrivateKey, Fr, }, - { Tx, ContractDeploymentTx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs }, false, fetch, ); diff --git a/yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts b/yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts index 12c0fce9e4c..6efde784367 100644 --- a/yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts +++ b/yarn-project/aztec.js/src/aztec_rpc_client/wallet.ts @@ -2,8 +2,8 @@ import { AztecAddress, CircuitsWasm, Fr, PartialAddress, PrivateKey, TxContext } import { AztecRPC, ContractData, - ContractDataAndBytecode, DeployedContract, + ExtendedContractData, FunctionCall, L2BlockL2Logs, NodeInfo, @@ -70,8 +70,8 @@ export abstract class BaseWallet implements Wallet { viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise { return this.rpc.viewTx(functionName, args, to, from); } - getContractDataAndBytecode(contractAddress: AztecAddress): Promise { - return this.rpc.getContractDataAndBytecode(contractAddress); + getExtendedContractData(contractAddress: AztecAddress): Promise { + return this.rpc.getExtendedContractData(contractAddress); } getContractData(contractAddress: AztecAddress): Promise { return this.rpc.getContractData(contractAddress); diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 898f60b0dfa..8f821cf0ff8 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -1,12 +1,14 @@ import { AztecAddress, CompleteAddress, EthAddress } from '@aztec/circuits.js'; import { ABIParameterVisibility, ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { - ContractData, + DeployedContract, + ExtendedContractData, NodeInfo, Tx, TxExecutionRequest, TxHash, TxReceipt, + randomContractAbi, randomDeployedContract, } from '@aztec/types'; @@ -17,8 +19,8 @@ import { Contract } from './contract.js'; describe('Contract Class', () => { let wallet: MockProxy; - - const contractAddress = AztecAddress.random(); + let resolvedExtendedContractData: ExtendedContractData; + let contractAddress: AztecAddress; let account: CompleteAddress; const mockTx = { type: 'Tx' } as any as Tx; @@ -88,10 +90,13 @@ describe('Contract Class', () => { }; beforeEach(async () => { + resolvedExtendedContractData = ExtendedContractData.random(); + contractAddress = resolvedExtendedContractData.contractData.contractAddress; account = await CompleteAddress.random(); + wallet = mock(); wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest); - wallet.getContractData.mockResolvedValue(ContractData.random()); + wallet.getExtendedContractData.mockResolvedValue(resolvedExtendedContractData); wallet.sendTx.mockResolvedValue(mockTxHash); wallet.viewTx.mockResolvedValue(mockViewResultValue); wallet.getTxReceipt.mockResolvedValue(mockTxReceipt); @@ -139,8 +144,12 @@ describe('Contract Class', () => { }); it('should add contract and dependencies to aztec rpc', async () => { - const entry = randomDeployedContract(); - const contract = await Contract.at(entry.address, entry.abi, wallet); + const entry: DeployedContract = { + abi: randomContractAbi(), + completeAddress: resolvedExtendedContractData.getCompleteAddress(), + portalContract: EthAddress.random(), + }; + const contract = await Contract.at(entry.completeAddress.address, entry.abi, wallet); { await contract.attach(entry.portalContract); @@ -150,7 +159,7 @@ describe('Contract Class', () => { } { - const dependencies = [randomDeployedContract(), randomDeployedContract()]; + const dependencies = [await randomDeployedContract(), await randomDeployedContract()]; await contract.attach(entry.portalContract, dependencies); expect(wallet.addContracts).toHaveBeenCalledTimes(1); expect(wallet.addContracts).toHaveBeenCalledWith([entry, ...dependencies]); diff --git a/yarn-project/aztec.js/src/contract/contract.ts b/yarn-project/aztec.js/src/contract/contract.ts index bf141aedb1b..5f0c0aff12c 100644 --- a/yarn-project/aztec.js/src/contract/contract.ts +++ b/yarn-project/aztec.js/src/contract/contract.ts @@ -2,7 +2,6 @@ import { ContractAbi } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Wallet } from '../aztec_rpc_client/wallet.js'; -import { isContractDeployed } from '../index.js'; import { ContractBase } from './contract_base.js'; /** @@ -21,9 +20,10 @@ export class Contract extends ContractBase { * @returns A promise that resolves to a new Contract instance. */ public static async at(address: AztecAddress, abi: ContractAbi, wallet: Wallet): Promise { - if (!(await isContractDeployed(wallet, address))) { + const extendedContractData = await wallet.getExtendedContractData(address); + if (extendedContractData === undefined) { throw new Error('Contract ' + address.toString() + ' is not deployed'); } - return new Contract(address, abi, wallet); + return new Contract(extendedContractData.getCompleteAddress(), abi, wallet); } } diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index 4a20050fb2a..2cd9ec0a15c 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -1,7 +1,6 @@ import { ContractAbi, FunctionAbi, FunctionSelector } from '@aztec/foundation/abi'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { DeployedContract } from '@aztec/types'; +import { CompleteAddress, DeployedContract } from '@aztec/types'; import { Wallet } from '../aztec_rpc_client/wallet.js'; import { ContractFunctionInteraction } from './contract_function_interaction.js'; @@ -28,9 +27,9 @@ export abstract class ContractBase { protected constructor( /** - * The deployed contract's address. + * The deployed contract's complete address. */ - public readonly address: AztecAddress, + public readonly completeAddress: CompleteAddress, /** * The Application Binary Interface for the contract. */ @@ -42,7 +41,7 @@ export abstract class ContractBase { ) { abi.functions.forEach((f: FunctionAbi) => { const interactionFunction = (...args: any[]) => { - return new ContractFunctionInteraction(this.wallet, this.address!, f, args); + return new ContractFunctionInteraction(this.wallet, this.completeAddress.address!, f, args); }; this.methods[f.name] = Object.assign(interactionFunction, { @@ -57,6 +56,10 @@ export abstract class ContractBase { }); } + get address() { + return this.completeAddress.address; + } + /** * Attach the current contract instance to a portal contract and optionally add its dependencies. * The function will return a promise that resolves when all contracts have been added to the AztecRPCClient. @@ -69,7 +72,7 @@ export abstract class ContractBase { public attach(portalContract: EthAddress, dependencies: DeployedContract[] = []) { const deployedContract: DeployedContract = { abi: this.abi, - address: this.address, + completeAddress: this.completeAddress, portalContract, }; return this.wallet.addContracts([deployedContract, ...dependencies]); diff --git a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts index 51eea3c8ddc..a11f45ea0c7 100644 --- a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts @@ -1,12 +1,11 @@ import { + CompleteAddress, ContractDeploymentData, FunctionData, - PartialAddress, TxContext, getContractDeploymentInfo, } from '@aztec/circuits.js'; import { ContractAbi, FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { AztecRPC, PackedArguments, PublicKey, Tx, TxExecutionRequest } from '@aztec/types'; @@ -35,11 +34,8 @@ export interface DeployOptions extends SendMethodOptions { * Extends the ContractFunctionInteraction class. */ export class DeployMethod extends BaseContractInteraction { - /** The partially computed contract address. Known after creation of the deployment transaction. */ - public partialAddress?: PartialAddress = undefined; - - /** The complete contract address. */ - public completeContractAddress?: AztecAddress = undefined; + /** The complete address of the contract. */ + public completeAddress?: CompleteAddress = undefined; /** Constructor function to call. */ private constructorAbi: FunctionAbi; @@ -96,11 +92,10 @@ export class DeployMethod extends Bas }); this.txRequest = txRequest; - this.partialAddress = completeAddress.partialAddress; - this.completeContractAddress = completeAddress.address; + this.completeAddress = completeAddress; // TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined? - await this.rpc.addContracts([{ abi: this.abi, address: completeAddress.address, portalContract }]); + await this.rpc.addContracts([{ abi: this.abi, completeAddress, portalContract }]); return this.txRequest; } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 8126942f497..79307f9a9a5 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -10,8 +10,7 @@ export { AztecAddress, EthAddress, Point, Fr } from '@aztec/circuits.js'; export { AztecRPC, ContractData, - ContractDeploymentTx, - ContractDataAndBytecode, + ExtendedContractData as ExtendedContractData, DeployedContract, FunctionCall, L2BlockL2Logs, diff --git a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts index a358e4f5f56..1f3d3ed9e93 100644 --- a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts +++ b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts @@ -46,6 +46,8 @@ export async function getContractDeploymentInfo( const argsHash = await computeVarArgsHash(wasm, flatArgs); const constructorHash = hashConstructor(wasm, functionData, argsHash, constructorVkHash.toBuffer()); + // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/1873: create computeCompleteAddress + // function --> The following is wasteful as it computes partial address twice const partialAddress = computePartialAddress(wasm, contractAddressSalt, functionTreeRoot, constructorHash); const contractAddress = computeContractAddress( wasm, diff --git a/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts b/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts index 8c8e7054853..5bed24350ab 100644 --- a/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts @@ -73,13 +73,10 @@ describe('e2e_2_rpc_servers', () => { const deployPrivateTokenContract = async (initialBalance: bigint, owner: AztecAddress) => { logger(`Deploying PrivateToken contract...`); - const tx = PrivateTokenContract.deploy(aztecRpcServerA, initialBalance, owner).send(); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); - expect(receipt.status).toEqual(TxStatus.MINED); + const contract = await PrivateTokenContract.deploy(walletA, initialBalance, owner).send().deployed(); logger('L2 contract deployed'); - return receipt.contractAddress!; + return contract.completeAddress; }; it('transfers fund from user A to B via RPC server A followed by transfer from B to A via RPC server B', async () => { @@ -87,7 +84,8 @@ describe('e2e_2_rpc_servers', () => { const transferAmount1 = 654n; const transferAmount2 = 323n; - const tokenAddress = await deployPrivateTokenContract(initialBalance, userA.address); + const completeTokenAddress = await deployPrivateTokenContract(initialBalance, userA.address); + const tokenAddress = completeTokenAddress.address; // Add account B to wallet A await aztecRpcServerA.registerRecipient(userB); @@ -98,7 +96,7 @@ describe('e2e_2_rpc_servers', () => { await aztecRpcServerB.addContracts([ { abi: PrivateTokenContract.abi, - address: tokenAddress, + completeAddress: completeTokenAddress, portalContract: EthAddress.ZERO, }, ]); @@ -139,13 +137,10 @@ describe('e2e_2_rpc_servers', () => { const deployChildContractViaServerA = async () => { logger(`Deploying Child contract...`); - const tx = ChildContract.deploy(aztecRpcServerA).send(); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); - expect(receipt.status).toEqual(TxStatus.MINED); + const contract = await ChildContract.deploy(walletA).send().deployed(); logger('Child contract deployed'); - return receipt.contractAddress!; + return contract.completeAddress; }; const awaitServerSynchronised = async (server: AztecRPC) => { @@ -159,7 +154,7 @@ describe('e2e_2_rpc_servers', () => { aztecRpcServer.getPublicStorageAt(child.address, new Fr(1)).then(x => toBigInt(x!)); it('user calls a public function on a contract deployed by a different user using a different RPC server', async () => { - const childAddress = await deployChildContractViaServerA(); + const childCompleteAddress = await deployChildContractViaServerA(); await awaitServerSynchronised(aztecRpcServerA); @@ -167,14 +162,14 @@ describe('e2e_2_rpc_servers', () => { await aztecRpcServerB.addContracts([ { abi: ChildContract.abi, - address: childAddress, + completeAddress: childCompleteAddress, portalContract: EthAddress.ZERO, }, ]); const newValueToSet = 256n; - const childContractWithWalletB = await ChildContract.at(childAddress, walletB); + const childContractWithWalletB = await ChildContract.at(childCompleteAddress.address, walletB); const tx = childContractWithWalletB.methods.pubIncValue(newValueToSet).send({ origin: userB.address }); await tx.isMined({ interval: 0.1 }); @@ -183,7 +178,7 @@ describe('e2e_2_rpc_servers', () => { await awaitServerSynchronised(aztecRpcServerA); - const storedValue = await getChildStoredValue({ address: childAddress }, aztecRpcServerB); + const storedValue = await getChildStoredValue({ address: childCompleteAddress.address }, aztecRpcServerB); expect(storedValue).toBe(newValueToSet); }, 60_000); }); diff --git a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts index abc628c092a..9c3e15a0454 100644 --- a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts @@ -59,11 +59,8 @@ describe('e2e_pending_commitments_contract', () => { const deployContract = async () => { logger(`Deploying L2 contract...`); - const tx = PendingCommitmentsContract.deploy(aztecRpcServer).send(); - await tx.isMined({ interval: 0.1 }); - const receipt = await tx.getReceipt(); + contract = await PendingCommitmentsContract.deploy(wallet).send().deployed(); logger('L2 contract deployed'); - contract = await PendingCommitmentsContract.at(receipt.contractAddress!, wallet); return contract; }; diff --git a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts index afec182fe91..eeb564a3cea 100644 --- a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts +++ b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts @@ -112,7 +112,7 @@ describe('e2e_sandbox_example', () => { .send() .deployed(); - logger(`Contract successfully deployed at address ${contract.address!.toShortString()}`); + logger(`Contract successfully deployed at address ${contract.address.toShortString()}`); // docs:end:Deployment // ensure that private token contract is registered in the rpc @@ -123,10 +123,10 @@ describe('e2e_sandbox_example', () => { ////////////// QUERYING THE TOKEN BALANCE FOR EACH ACCOUNT ////////////// // Create the contract abstraction and link to Alice's wallet for future signing - const tokenContractAlice = await PrivateTokenContract.at(contract.address!, await accounts[0].getWallet()); + const tokenContractAlice = await PrivateTokenContract.at(contract.address, await accounts[0].getWallet()); // Bob wants to mint some funds, the contract is already deployed, create an abstraction and link it his wallet - const tokenContractBob = await PrivateTokenContract.at(contract.address!, await accounts[1].getWallet()); + const tokenContractBob = await PrivateTokenContract.at(contract.address, await accounts[1].getWallet()); let aliceBalance = await tokenContractAlice.methods.getBalance(alice).view(); logger(`Alice's balance ${aliceBalance}`); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 63b13b3c2a6..250a09a09fb 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -17,7 +17,7 @@ import { getUnsafeSchnorrAccount, makeFetch, } from '@aztec/aztec.js'; -import { CompleteAddress, PrivateKey, PublicKey } from '@aztec/circuits.js'; +import { CompleteAddress, PrivateKey } from '@aztec/circuits.js'; import { DeployL1Contracts, deployL1Contract, deployL1Contracts } from '@aztec/ethereum'; import { ContractAbi } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; @@ -266,31 +266,6 @@ export async function setup( }; } -/** - * Deploys a smart contract on L2. - * @param aztecRpcServer - An instance of AztecRPC that will be used for contract deployment. - * @param publicKey - The encryption public key. - * @param abi - The Contract ABI (Application Binary Interface) that defines the contract's interface. - * @param args - An array of arguments to be passed to the contract constructor during deployment. - * @param contractAddressSalt - A random value used as a salt to generate the contract address. If not provided, the contract address will be deterministic. - * @returns An object containing the deployed contract's address and partial address. - */ -export async function deployContract( - aztecRpcServer: AztecRPC, - publicKey: PublicKey, - abi: ContractAbi, - args: any[], - contractAddressSalt?: Fr, -) { - const deployer = new ContractDeployer(abi, aztecRpcServer, publicKey); - const deployMethod = deployer.deploy(...args); - await deployMethod.create({ contractAddressSalt }); - const tx = deployMethod.send(); - expect(await tx.isMined({ interval: 0.1 })).toBeTruthy(); - const receipt = await tx.getReceipt(); - return { address: receipt.contractAddress!, partialAddress: deployMethod.partialAddress! }; -} - /** * Sets the timestamp of the next block. * @param rpcUrl - rpc url of the blockchain instance to connect to diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts index 48e824408b9..003dae14cce 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts @@ -83,23 +83,23 @@ function generateDeploy(input: ContractAbi) { function generateConstructor(name: string) { return ` private constructor( - /** The deployed contract's address. */ - address: AztecAddress, + /** The deployed contract's complete address. */ + completeAddress: CompleteAddress, /** The wallet. */ wallet: Wallet, ) { - super(address, ${name}ContractAbi, wallet); + super(completeAddress, ${name}ContractAbi, wallet); } `; } /** - * Generates the create method for this contract. + * Generates the at method for this contract. * @param name - Name of the contract to derive the ABI name from. - * @returns A create method. + * @returns An at method. * @remarks We don't use constructor directly because of the async `wallet.getContractData` call. */ -function generateCreate(name: string) { +function generateAt(name: string) { return ` /** * Creates a contract instance. @@ -113,10 +113,11 @@ function generateCreate(name: string) { /** The wallet. */ wallet: Wallet, ) { - if ((await wallet.getContractData(address)) === undefined) { + const extendedContractData = await wallet.getExtendedContractData(address); + if (extendedContractData === undefined) { throw new Error('Contract ' + address.toString() + ' is not deployed'); } - return new ${name}Contract(address, wallet); + return new ${name}Contract(extendedContractData.getCompleteAddress(), wallet); }`; } @@ -161,7 +162,7 @@ export function generateTypescriptContractInterface(input: ContractAbi, abiImpor const methods = compact(input.functions.filter(f => f.name !== 'constructor').map(generateMethod)); const deploy = abiImportPath && generateDeploy(input); const ctor = abiImportPath && generateConstructor(input.name); - const create = abiImportPath && generateCreate(input.name); + const at = abiImportPath && generateAt(input.name); const abiStatement = abiImportPath && generateAbiStatement(input.name, abiImportPath); const abiGetter = abiImportPath && generateAbiGetter(input.name); @@ -169,7 +170,7 @@ export function generateTypescriptContractInterface(input: ContractAbi, abiImpor /* Autogenerated file, do not edit! */ /* eslint-disable */ -import { AztecAddress, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, FieldLike, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, CompleteAddress, ContractBase, ContractFunctionInteraction, ContractMethod, DeployMethod, FieldLike, Wallet } from '@aztec/aztec.js'; import { Fr, Point } from '@aztec/foundation/fields'; import { AztecRPC, PublicKey } from '@aztec/types'; import { ContractAbi } from '@aztec/foundation/abi'; @@ -181,7 +182,11 @@ ${abiStatement} export class ${input.name}Contract extends ContractBase { ${ctor} - ${create} + get address() { + return this.completeAddress.address; + } + + ${at} ${deploy} diff --git a/yarn-project/p2p/src/service/tx_messages.test.ts b/yarn-project/p2p/src/service/tx_messages.test.ts index 21cc5c51efe..80dc2eac333 100644 --- a/yarn-project/p2p/src/service/tx_messages.test.ts +++ b/yarn-project/p2p/src/service/tx_messages.test.ts @@ -1,10 +1,7 @@ -import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof } from '@aztec/circuits.js'; -import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories'; -import { EncodedContractFunction, Tx, TxHash, TxL2Logs } from '@aztec/types'; +import { Tx, TxHash, mockTx } from '@aztec/types'; import { expect } from '@jest/globals'; import { randomBytes } from 'crypto'; -import times from 'lodash.times'; import { Messages, @@ -20,19 +17,6 @@ import { toTxMessage, } from './tx_messages.js'; -const makeTx = () => { - const encodedPublicFunctions = [EncodedContractFunction.random(), EncodedContractFunction.random()]; - const enqueuedPublicFunctionCalls = times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, i => makePublicCallRequest(i)); - return new Tx( - makeKernelPublicInputs(), - Proof.fromBuffer(Buffer.alloc(10, 9)), - TxL2Logs.random(8, 2), - TxL2Logs.random(8, 3), - encodedPublicFunctions, - enqueuedPublicFunctionCalls, - ); -}; - const makeTxHash = () => { return new TxHash(randomBytes(32)); }; @@ -41,24 +25,22 @@ const verifyTx = (actual: Tx, expected: Tx) => { expect(actual.data!.toBuffer()).toEqual(expected.data?.toBuffer()); expect(actual.proof!.toBuffer()).toEqual(expected.proof!.toBuffer()); expect(actual.encryptedLogs!.toBuffer()).toEqual(expected.encryptedLogs?.toBuffer()); - expect(actual.newContractPublicFunctions!.length).toEqual(expected.newContractPublicFunctions!.length); - for (let i = 0; i < actual.newContractPublicFunctions!.length; i++) { - expect(actual.newContractPublicFunctions![i].toBuffer()).toEqual( - expected.newContractPublicFunctions![i].toBuffer(), - ); + expect(actual.newContracts!.length).toEqual(expected.newContracts!.length); + for (let i = 0; i < actual.newContracts!.length; i++) { + expect(actual.newContracts![i].toBuffer()).toEqual(expected.newContracts![i].toBuffer()); } }; describe('Messages', () => { it('Correctly serialises and deserialises a single private transaction', () => { - const transaction = makeTx(); + const transaction = mockTx(); const message = toTxMessage(transaction); const decodedTransaction = fromTxMessage(message); verifyTx(decodedTransaction, transaction); }); it('Correctly serialises and deserialises transactions messages', () => { - const privateTransactions = [makeTx(), makeTx(), makeTx()]; + const privateTransactions = [mockTx(), mockTx(), mockTx()]; const message = createTransactionsMessage(privateTransactions); expect(decodeMessageType(message)).toBe(Messages.POOLED_TRANSACTIONS); const decodedTransactions = decodeTransactionsMessage(getEncodedMessage(message)); diff --git a/yarn-project/p2p/src/service/tx_messages.ts b/yarn-project/p2p/src/service/tx_messages.ts index 170ea6f63aa..33eea14ceaf 100644 --- a/yarn-project/p2p/src/service/tx_messages.ts +++ b/yarn-project/p2p/src/service/tx_messages.ts @@ -1,6 +1,6 @@ -import { KernelCircuitPublicInputs, Proof, PublicCallRequest } from '@aztec/circuits.js'; -import { numToUInt32BE } from '@aztec/foundation/serialize'; -import { EncodedContractFunction, Tx, TxHash, TxL2Logs } from '@aztec/types'; +import { KernelCircuitPublicInputs, MAX_NEW_CONTRACTS_PER_TX, Proof, PublicCallRequest } from '@aztec/circuits.js'; +import { Tuple, numToUInt32BE } from '@aztec/foundation/serialize'; +import { ExtendedContractData, Tx, TxHash, TxL2Logs } from '@aztec/types'; /** * Enumeration of P2P message types. @@ -145,8 +145,8 @@ export function toTxMessage(tx: Tx): Buffer { createMessageComponent(tx.proof), createMessageComponent(tx.encryptedLogs), createMessageComponent(tx.unencryptedLogs), - createMessageComponents(tx.newContractPublicFunctions), createMessageComponents(tx.enqueuedPublicFunctionCalls), + createMessageComponents(tx.newContracts), ]); const messageLength = numToUInt32BE(messageBuffer.length); return Buffer.concat([messageLength, messageBuffer]); @@ -198,14 +198,14 @@ export function fromTxMessage(buffer: Buffer): Tx { unencryptedLogs.obj = new TxL2Logs([]); } - const functions = toObjectArray(unencryptedLogs.remainingData, EncodedContractFunction); - const publicCalls = toObjectArray(functions.remainingData, PublicCallRequest); + const publicCalls = toObjectArray(unencryptedLogs.remainingData, PublicCallRequest); + const newContracts = toObjectArray(publicCalls.remainingData, ExtendedContractData); return new Tx( publicInputs.obj!, proof.obj!, encryptedLogs.obj, unencryptedLogs.obj, - functions.objects, publicCalls.objects, + newContracts.objects as Tuple, ); } diff --git a/yarn-project/rollup-provider/src/app.ts b/yarn-project/rollup-provider/src/app.ts index bdd223e1994..aea93a4aa49 100644 --- a/yarn-project/rollup-provider/src/app.ts +++ b/yarn-project/rollup-provider/src/app.ts @@ -118,7 +118,7 @@ export function appFactory(node: AztecNode, prefix: string) { const address = ctx.query.address; ctx.set('content-type', 'application/json'); ctx.body = { - contractData: await node.getContractDataAndBytecode(AztecAddress.fromString(address as string)), + contractData: await node.getExtendedContractData(AztecAddress.fromString(address as string)), }; ctx.status = 200; }); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 099b240f9c8..fcc9a06e607 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -32,6 +32,7 @@ import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { to2Fields } from '@aztec/foundation/serialize'; import { ContractData, + ExtendedContractData, L2Block, L2BlockL2Logs, MerkleTreeId, @@ -177,8 +178,8 @@ describe('sequencer/solo_block_builder', () => { emptyProof, makeEmptyLogs(), makeEmptyLogs(), - [], times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makePublicCallRequest), + [ExtendedContractData.random()], ), ); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 6100d7b87b4..026c698edd7 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -1,6 +1,6 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { InterruptableSleep } from '@aztec/foundation/sleep'; -import { ContractDataAndBytecode, L2Block } from '@aztec/types'; +import { ExtendedContractData, L2Block } from '@aztec/types'; import { L2BlockReceiver } from '../receiver.js'; import { PublisherConfig } from './config.js'; @@ -31,16 +31,22 @@ export interface L1PublisherTxSender { sendProcessTx(encodedData: L1ProcessArgs): Promise; /** - * Sends a tx to the public contract data emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined. - * @param l2BlockNum - Number of the L2 block that owns this public contract data. + * Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined. + * @param l2BlockNum - Number of the L2 block that owns this encrypted logs. * @param l2BlockHash - The hash of the block corresponding to this data. - * @param contractData - Data to publish. + * @param partialAddresses - The partial addresses of the deployed contract + * @param publicKeys - The public keys of the deployed contract + * @param newExtendedContractData - Data to publish. * @returns The hash of the mined tx. + * @remarks Partial addresses, public keys and contract data has to be in the same order. + * @remarks See the link bellow for more info on partial address and public key: + * https://github.com/AztecProtocol/aztec-packages/blob/master/docs/docs/concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys + * TODO: replace the link above with the link to deployed docs */ sendEmitContractDeploymentTx( l2BlockNum: number, l2BlockHash: Buffer, - contractData: ContractDataAndBytecode[], + newExtendedContractData: ExtendedContractData[], ): Promise<(string | undefined)[]>; /** @@ -139,12 +145,8 @@ export class L1Publisher implements L2BlockReceiver { * @param contractData - The new contract data to publish. * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise. */ - public async processNewContractData( - l2BlockNum: number, - l2BlockHash: Buffer, - contractData: ContractDataAndBytecode[], - ) { - let _contractData: ContractDataAndBytecode[] = []; + public async processNewContractData(l2BlockNum: number, l2BlockHash: Buffer, contractData: ExtendedContractData[]) { + let _contractData: ExtendedContractData[] = []; while (!this.interrupted) { if (!(await this.checkFeeDistributorBalance())) { this.log(`Fee distributor ETH balance too low, awaiting top up...`); @@ -217,11 +219,11 @@ export class L1Publisher implements L2BlockReceiver { private async sendEmitNewContractDataTx( l2BlockNum: number, l2BlockHash: Buffer, - contractData: ContractDataAndBytecode[], + newExtendedContractData: ExtendedContractData[], ) { while (!this.interrupted) { try { - return await this.txSender.sendEmitContractDeploymentTx(l2BlockNum, l2BlockHash, contractData); + return await this.txSender.sendEmitContractDeploymentTx(l2BlockNum, l2BlockHash, newExtendedContractData); } catch (err) { this.log.error(`Error sending contract data to L1`, err); await this.sleepOrInterrupted(); diff --git a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts index a5d841993ee..81d0e5ff90f 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -1,7 +1,7 @@ import { createEthereumChain } from '@aztec/ethereum'; import { createDebugLogger } from '@aztec/foundation/log'; import { ContractDeploymentEmitterAbi, RollupAbi } from '@aztec/l1-artifacts'; -import { ContractDataAndBytecode } from '@aztec/types'; +import { ExtendedContractData } from '@aztec/types'; import { GetContractReturnType, @@ -120,22 +120,25 @@ export class ViemTxSender implements L1PublisherTxSender { * Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined. * @param l2BlockNum - Number of the L2 block that owns this encrypted logs. * @param l2BlockHash - The hash of the block corresponding to this data. - * @param newContractDataAndBytecode - Data to publish. + * @param newExtendedContractData - Data to publish. * @returns The hash of the mined tx. */ async sendEmitContractDeploymentTx( l2BlockNum: number, l2BlockHash: Buffer, - newContractDataAndBytecode: ContractDataAndBytecode[], + newExtendedContractData: ExtendedContractData[], ): Promise<(string | undefined)[]> { const hashes: string[] = []; - for (const contractDataAndBytecode of newContractDataAndBytecode) { + for (const extendedContractData of newExtendedContractData) { const args = [ BigInt(l2BlockNum), - contractDataAndBytecode.contractData.contractAddress.toString() as Hex, - contractDataAndBytecode.contractData.portalContractAddress.toString() as Hex, + extendedContractData.contractData.contractAddress.toString() as Hex, + extendedContractData.contractData.portalContractAddress.toString() as Hex, `0x${l2BlockHash.toString('hex')}`, - `0x${contractDataAndBytecode.bytecode.toString('hex')}`, + extendedContractData.partialAddress.toString(true), + extendedContractData.publicKey.x.toString(true), + extendedContractData.publicKey.y.toString(true), + `0x${extendedContractData.bytecode.toString('hex')}`, ] as const; const gas = await this.contractDeploymentEmitterContract.estimateGas.emitContractDeployment(args, { diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 2f2fa204759..863cd2289fa 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -26,9 +26,9 @@ import { } from '@aztec/circuits.js/factories'; import { padArrayEnd } from '@aztec/foundation/collection'; import { - ContractDataAndBytecode, ContractDataSource, EncodedContractFunction, + ExtendedContractData, FunctionCall, FunctionL2Logs, SiblingPath, @@ -54,7 +54,7 @@ describe('public_processor', () => { let contractDataSource: MockProxy; let publicFunction: EncodedContractFunction; - let contractData: ContractDataAndBytecode; + let contractData: ExtendedContractData; let proof: Proof; let root: Buffer; @@ -66,7 +66,7 @@ describe('public_processor', () => { publicProver = mock(); contractDataSource = mock(); - contractData = ContractDataAndBytecode.random(); + contractData = ExtendedContractData.random(); publicFunction = EncodedContractFunction.random(); proof = makeEmptyProof(); root = Buffer.alloc(32, 5); @@ -74,7 +74,7 @@ describe('public_processor', () => { publicProver.getPublicCircuitProof.mockResolvedValue(proof); publicProver.getPublicKernelCircuitProof.mockResolvedValue(proof); db.getTreeInfo.mockResolvedValue({ root } as TreeInfo); - contractDataSource.getContractDataAndBytecode.mockResolvedValue(contractData); + contractDataSource.getExtendedContractData.mockResolvedValue(contractData); contractDataSource.getPublicFunction.mockResolvedValue(publicFunction); }); @@ -155,7 +155,9 @@ describe('public_processor', () => { kernelOutput.end.publicCallStack = padArrayEnd(callStackHashes, Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); - const tx = new Tx(kernelOutput, proof, TxL2Logs.random(2, 3), TxL2Logs.random(3, 2), [], callRequests); + const tx = new Tx(kernelOutput, proof, TxL2Logs.random(2, 3), TxL2Logs.random(3, 2), callRequests, [ + ExtendedContractData.random(), + ]); publicExecutor.execute.mockImplementation(execution => { for (const request of callRequests) { @@ -183,7 +185,14 @@ describe('public_processor', () => { kernelOutput.end.publicCallStack = padArrayEnd([callStackHash], Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); - const tx = new Tx(kernelOutput, proof, TxL2Logs.random(2, 3), TxL2Logs.random(3, 2), [], [callRequest]); + const tx = new Tx( + kernelOutput, + proof, + TxL2Logs.random(2, 3), + TxL2Logs.random(3, 2), + [callRequest], + [ExtendedContractData.random()], + ); const publicExecutionResult = makePublicExecutionResultFromRequest(callRequest); publicExecutionResult.nestedExecutions = [ diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index b3a6e3b7540..d473dec8e48 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -3,15 +3,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { P2P } from '@aztec/p2p'; -import { - ContractData, - ContractDataAndBytecode, - L1ToL2MessageSource, - L2Block, - L2BlockSource, - MerkleTreeId, - Tx, -} from '@aztec/types'; +import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, Tx } from '@aztec/types'; import { WorldStateStatus, WorldStateSynchroniser } from '@aztec/world-state'; import times from 'lodash.times'; @@ -170,7 +162,7 @@ export class Sequencer { const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, newGlobalVariables); this.log(`Assembled block ${block.number}`); - await this.publishContractDataAndBytecode(validTxs, block); + await this.publishExtendedContractData(validTxs, block); await this.publishL2Block(block); this.log.info(`Submitted rollup block ${block.number} with ${processedTxs.length} transactions`); @@ -182,28 +174,25 @@ export class Sequencer { } /** - * Gets new contract data and bytecode from the txs and publishes it on chain. + * Gets new extended contract data from the txs and publishes it on chain. * @param validTxs - The set of real transactions being published as part of the block. * @param block - The L2Block to be published. */ - protected async publishContractDataAndBytecode(validTxs: Tx[], block: L2Block) { + protected async publishExtendedContractData(validTxs: Tx[], block: L2Block) { // Publishes contract data for txs to the network and awaits the tx to be mined this.state = SequencerState.PUBLISHING_CONTRACT_DATA; const newContractData = validTxs .map(tx => { // Currently can only have 1 new contract per tx const newContract = tx.data?.end.newContracts[0]; - if (newContract && tx.newContractPublicFunctions?.length) { - return new ContractDataAndBytecode( - new ContractData(newContract.contractAddress, newContract.portalContractAddress), - tx.newContractPublicFunctions, - ); + if (newContract) { + return tx.newContracts[0]; } }) .filter((cd): cd is Exclude => cd !== undefined); const blockHash = block.getCalldataHash(); - this.log(`Publishing contract data and bytecode with block hash ${blockHash.toString('hex')}`); + this.log(`Publishing extended contract data with block hash ${blockHash.toString('hex')}`); const publishedContractData = await this.publisher.processNewContractData(block.number, blockHash, newContractData); if (publishedContractData) { diff --git a/yarn-project/types/src/contract_dao.ts b/yarn-project/types/src/contract_dao.ts index 3faf5746921..46379390981 100644 --- a/yarn-project/types/src/contract_dao.ts +++ b/yarn-project/types/src/contract_dao.ts @@ -1,6 +1,5 @@ -import { ContractFunctionDao } from '@aztec/circuits.js'; +import { CompleteAddress, ContractFunctionDao } from '@aztec/circuits.js'; import { ContractAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { EncodedContractFunction } from './contract_data.js'; @@ -12,9 +11,9 @@ import { EncodedContractFunction } from './contract_data.js'; */ export interface ContractDao extends ContractAbi { /** - * The noir contract address. + * The complete address representing the contract on L2. */ - address: AztecAddress; + completeAddress: CompleteAddress; /** * The Ethereum address of the L1 contract serving as a bridge for cross-layer interactions. */ @@ -30,18 +29,22 @@ export interface ContractDao extends ContractAbi { * such as the address, portal contract, and function selectors. * * @param abi - The contract ABI. - * @param address - The AztecAddress representing the contract's address. + * @param completeAddress - The AztecAddress representing the contract's address. * @param portalContract - The EthAddress representing the address of the associated portal contract. * @returns A ContractDao object containing the provided information along with generated function selectors. */ -export function toContractDao(abi: ContractAbi, address: AztecAddress, portalContract: EthAddress): ContractDao { +export function toContractDao( + abi: ContractAbi, + completeAddress: CompleteAddress, + portalContract: EthAddress, +): ContractDao { const functions = abi.functions.map(f => ({ ...f, selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), })); return { ...abi, - address, + completeAddress, functions, portalContract, }; diff --git a/yarn-project/types/src/contract_data.test.ts b/yarn-project/types/src/contract_data.test.ts index f5e4ffab9af..de586d54fe0 100644 --- a/yarn-project/types/src/contract_data.test.ts +++ b/yarn-project/types/src/contract_data.test.ts @@ -1,28 +1,25 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { ContractData, ContractDataAndBytecode, EncodedContractFunction } from './contract_data.js'; +import { ContractData, ExtendedContractData } from './contract_data.js'; describe('ContractData', () => { const aztecAddress = AztecAddress.random(); const portalAddress = EthAddress.random(); it('serializes / deserializes correctly', () => { - const contractDataAndBytecode = new ContractDataAndBytecode(new ContractData(aztecAddress, portalAddress), [ - EncodedContractFunction.random(), - EncodedContractFunction.random(), - ]); - const buf = contractDataAndBytecode.toBuffer(); - const serContractData = ContractDataAndBytecode.fromBuffer(buf); + const extendedContractData = ExtendedContractData.random(); + const buf = extendedContractData.toBuffer(); + const serContractData = ExtendedContractData.fromBuffer(buf); + expect(extendedContractData.contractData.contractAddress.equals(serContractData.contractData.contractAddress)).toBe( + true, + ); expect( - contractDataAndBytecode.contractData.contractAddress.equals(serContractData.contractData.contractAddress), - ).toBe(true); - expect( - contractDataAndBytecode.contractData.portalContractAddress.equals( + extendedContractData.contractData.portalContractAddress.equals( serContractData.contractData.portalContractAddress, ), ).toBe(true); - expect(contractDataAndBytecode.bytecode?.equals(serContractData?.bytecode || Buffer.alloc(0))).toBe(true); + expect(extendedContractData.bytecode?.equals(serContractData?.bytecode || Buffer.alloc(0))).toBe(true); }); it('serializes / deserializes correctly without bytecode', () => { diff --git a/yarn-project/types/src/contract_data.ts b/yarn-project/types/src/contract_data.ts index 0879bd5d05d..56b5d5f0bc7 100644 --- a/yarn-project/types/src/contract_data.ts +++ b/yarn-project/types/src/contract_data.ts @@ -1,4 +1,12 @@ -import { FUNCTION_SELECTOR_NUM_BYTES, FunctionSelector } from '@aztec/circuits.js'; +import { + CompleteAddress, + FUNCTION_SELECTOR_NUM_BYTES, + Fr, + FunctionSelector, + PartialAddress, + Point, + PublicKey, +} from '@aztec/circuits.js'; import { BufferReader, serializeToBuffer } from '@aztec/circuits.js/utils'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { randomBytes } from '@aztec/foundation/crypto'; @@ -12,13 +20,11 @@ export { BufferReader } from '@aztec/circuits.js/utils'; */ export interface ContractDataSource { /** - * Lookup the L2 contract data for this contract. - * Contains information such as the ethereum portal address and bytecode. - * NOTE: This method works only for contracts that have public function bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns Contract data and bytecode or undefined if not found. + * @returns The extended contract data or undefined if not found. */ - getContractDataAndBytecode(contractAddress: AztecAddress): Promise; + getExtendedContractData(contractAddress: AztecAddress): Promise; /** * Lookup the L2 contract base info for this contract. @@ -29,11 +35,11 @@ export interface ContractDataSource { getContractData(contractAddress: AztecAddress): Promise; /** - * Lookup all contract data and bytecode in an L2 block. + * Gets extended contract data for all contracts deployed in L2 block. * @param blockNumber - The block number. - * @returns Public data of contracts deployed in L2 block, including public function bytecode. + * @returns Extended contract data of contracts deployed in L2 block. */ - getContractDataAndBytecodeInBlock(blockNumber: number): Promise; + getExtendedContractDataInBlock(blockNumber: number): Promise; /** * Lookup contract data in an L2 block. @@ -101,28 +107,22 @@ export class EncodedContractFunction { } /** - * A contract data blob, containing L1 and L2 addresses, as well as public functions' bytecode. + * A contract data blob, containing L1 and L2 addresses, public functions' bytecode, partial address and public key. */ -export class ContractDataAndBytecode { - /** - * The contract's encoded ACIR code. This should become Brillig code once implemented. - */ +export class ExtendedContractData { + /** The contract's encoded ACIR code. This should become Brillig code once implemented. */ public bytecode: Buffer; constructor( - /** - * The base contract data: aztec & portal addresses. - */ + /** The base contract data: aztec & portal addresses. */ public contractData: ContractData, - - /** - * ABIs of public functions. - */ + /** ABIs of public functions. */ private publicFunctions: EncodedContractFunction[], + /** Partial addresses of the contract. */ + public readonly partialAddress: PartialAddress, + /** Public keys of the contract. */ + public readonly publicKey: PublicKey, ) { - if (!publicFunctions.length) { - throw Error('No public functions provided for ContractDataAndBytecode.'); - } this.bytecode = serializeBufferArrayToVector(publicFunctions.map(fn => fn.toBuffer())); } @@ -141,7 +141,7 @@ export class ContractDataAndBytecode { */ public toBuffer(): Buffer { const contractDataBuf = this.contractData.toBuffer(); - return serializeToBuffer(contractDataBuf, this.bytecode); + return serializeToBuffer(contractDataBuf, this.bytecode, this.partialAddress, this.publicKey); } /** @@ -152,6 +152,14 @@ export class ContractDataAndBytecode { return this.toBuffer().toString('hex'); } + /** + * Gets the complete address. + * @returns The complete address. + */ + public getCompleteAddress(): CompleteAddress { + return new CompleteAddress(this.contractData.contractAddress, this.publicKey, this.partialAddress); + } + /** * Deserializes a contract data object from an encoded buffer, using 20 bytes for the eth address. * @param buffer - Byte array resulting from calling toBuffer. @@ -161,7 +169,9 @@ export class ContractDataAndBytecode { const reader = BufferReader.asReader(buffer); const contractData = reader.readObject(ContractData); const publicFns = reader.readVector(EncodedContractFunction); - return new ContractDataAndBytecode(contractData, publicFns); + const partialAddress = reader.readObject(Fr); + const publicKey = reader.readObject(Point); + return new ExtendedContractData(contractData, publicFns, partialAddress, publicKey); } /** @@ -170,18 +180,20 @@ export class ContractDataAndBytecode { * @returns Deserialized instance. */ static fromString(str: string) { - return ContractDataAndBytecode.fromBuffer(Buffer.from(str, 'hex')); + return ExtendedContractData.fromBuffer(Buffer.from(str, 'hex')); } /** * Generate ContractData with random addresses. - * @returns A random ContractDataAndBytecode object. + * @returns A random ExtendedContractData object. */ - static random(): ContractDataAndBytecode { - return new ContractDataAndBytecode(ContractData.random(), [ - EncodedContractFunction.random(), - EncodedContractFunction.random(), - ]); + static random(): ExtendedContractData { + return new ExtendedContractData( + ContractData.random(), + [EncodedContractFunction.random(), EncodedContractFunction.random()], + Fr.random(), + Point.random(), + ); } } diff --git a/yarn-project/types/src/interfaces/aztec-node.ts b/yarn-project/types/src/interfaces/aztec-node.ts index 4ae7e4f65c3..5d53f1a319a 100644 --- a/yarn-project/types/src/interfaces/aztec-node.ts +++ b/yarn-project/types/src/interfaces/aztec-node.ts @@ -5,8 +5,8 @@ import { Fr } from '@aztec/foundation/fields'; import { ContractCommitmentProvider, ContractData, - ContractDataAndBytecode, DataCommitmentProvider, + ExtendedContractData, L1ToL2MessageProvider, L2Block, L2BlockL2Logs, @@ -68,12 +68,11 @@ export interface AztecNode extends DataCommitmentProvider, L1ToL2MessageProvider getRollupAddress(): Promise; /** - * Lookup the L2 contract data for this contract. - * Contains the ethereum portal address and bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The complete contract data including portal address & bytecode (if we didn't throw an error). + * @returns The extended contract data or undefined if not found. */ - getContractDataAndBytecode(contractAddress: AztecAddress): Promise; + getExtendedContractData(contractAddress: AztecAddress): Promise; /** * Lookup the contract data for this contract. diff --git a/yarn-project/types/src/interfaces/aztec_rpc.ts b/yarn-project/types/src/interfaces/aztec_rpc.ts index 3c4ce90c0e8..b30cbec92c1 100644 --- a/yarn-project/types/src/interfaces/aztec_rpc.ts +++ b/yarn-project/types/src/interfaces/aztec_rpc.ts @@ -3,7 +3,7 @@ import { ContractAbi } from '@aztec/foundation/abi'; import { CompleteAddress, ContractData, - ContractDataAndBytecode, + ExtendedContractData, L2BlockL2Logs, Tx, TxExecutionRequest, @@ -21,9 +21,9 @@ export interface DeployedContract { */ abi: ContractAbi; /** - * The address representing the contract on L2. + * The complete address representing the contract on L2. */ - address: AztecAddress; + completeAddress: CompleteAddress; /** * The Ethereum address of the L1 portal contract. */ @@ -183,12 +183,11 @@ export interface AztecRPC { viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; /** - * Lookup the L2 contract data for this contract. - * Contains the ethereum portal address and bytecode. + * Get the extended contract data for this contract. * @param contractAddress - The contract data address. - * @returns The complete contract data including portal address & bytecode (if we didn't throw an error). + * @returns The extended contract data or undefined if not found. */ - getContractDataAndBytecode(contractAddress: AztecAddress): Promise; + getExtendedContractData(contractAddress: AztecAddress): Promise; /** * Lookup the L2 contract data for this contract. diff --git a/yarn-project/types/src/mocks.ts b/yarn-project/types/src/mocks.ts index 9136d6adb8f..91065c6a6fe 100644 --- a/yarn-project/types/src/mocks.ts +++ b/yarn-project/types/src/mocks.ts @@ -1,11 +1,18 @@ -import { AztecAddress, EthAddress, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof } from '@aztec/circuits.js'; +import { + CompleteAddress, + EthAddress, + MAX_NEW_CONTRACTS_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + Proof, +} from '@aztec/circuits.js'; import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories'; import { ContractAbi } from '@aztec/foundation/abi'; import { randomBytes } from '@aztec/foundation/crypto'; +import { Tuple } from '@aztec/foundation/serialize'; import times from 'lodash.times'; -import { DeployedContract, EncodedContractFunction, FunctionL2Logs, TxL2Logs } from './index.js'; +import { DeployedContract, ExtendedContractData, FunctionL2Logs, TxL2Logs } from './index.js'; import { Tx } from './tx/index.js'; /** @@ -22,8 +29,11 @@ export const mockTx = (seed = 1) => { new Proof(Buffer.alloc(0)), TxL2Logs.random(8, 3), // 8 priv function invocations creating 3 encrypted logs each TxL2Logs.random(11, 2), // 8 priv + 3 pub function invocations creating 2 unencrypted logs each - times(3, EncodedContractFunction.random), times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makePublicCallRequest), + times(MAX_NEW_CONTRACTS_PER_TX, ExtendedContractData.random) as Tuple< + ExtendedContractData, + typeof MAX_NEW_CONTRACTS_PER_TX + >, ); }; @@ -32,8 +42,8 @@ export const randomContractAbi = (): ContractAbi => ({ functions: [], }); -export const randomDeployedContract = (): DeployedContract => ({ +export const randomDeployedContract = async (): Promise => ({ abi: randomContractAbi(), - address: AztecAddress.random(), + completeAddress: await CompleteAddress.random(), portalContract: EthAddress.random(), }); diff --git a/yarn-project/types/src/tx/tx.ts b/yarn-project/types/src/tx/tx.ts index 4ba5c6d83cd..8160f76eb02 100644 --- a/yarn-project/types/src/tx/tx.ts +++ b/yarn-project/types/src/tx/tx.ts @@ -1,17 +1,15 @@ import { - AztecAddress, - Fr, KernelCircuitPublicInputs, + MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - PartialAddress, Proof, PublicCallRequest, } from '@aztec/circuits.js'; import { serializeToBuffer } from '@aztec/circuits.js/utils'; import { arrayNonEmptyLength } from '@aztec/foundation/collection'; -import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize'; +import { BufferReader, Tuple } from '@aztec/foundation/serialize'; -import { EncodedContractFunction } from '../contract_data.js'; +import { ExtendedContractData } from '../contract_data.js'; import { TxL2Logs } from '../logs/tx_l2_logs.js'; import { TxHash } from './tx_hash.js'; @@ -36,15 +34,16 @@ export class Tx { * Unencrypted logs generated by the tx. */ public readonly unencryptedLogs: TxL2Logs, - /** - * New public functions made available by this tx. - */ - public readonly newContractPublicFunctions: EncodedContractFunction[], /** * Enqueued public functions from the private circuit to be run by the sequencer. * Preimages of the public call stack entries from the private kernel circuit output. */ public readonly enqueuedPublicFunctionCalls: PublicCallRequest[], + /** + * Contracts deployed in this tx. + * Note: Portal address is always set to zero in the tx's new contracts. + */ + public readonly newContracts: Tuple, ) { if (this.unencryptedLogs.functionLogs.length < this.encryptedLogs.functionLogs.length) { // This check is present because each private function invocation creates encrypted FunctionL2Logs object and @@ -78,8 +77,8 @@ export class Tx { reader.readObject(Proof), reader.readObject(TxL2Logs), reader.readObject(TxL2Logs), - reader.readArray(reader.readNumber(), EncodedContractFunction), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PublicCallRequest), + reader.readArray(MAX_NEW_CONTRACTS_PER_TX, ExtendedContractData), ); } @@ -93,10 +92,8 @@ export class Tx { this.proof, this.encryptedLogs, this.unencryptedLogs, - // number of new contract public functions is not constant so we need to include it in the serialization - numToUInt32BE(this.newContractPublicFunctions.length), - this.newContractPublicFunctions, this.enqueuedPublicFunctionCalls, + this.newContracts, ]); } @@ -110,8 +107,8 @@ export class Tx { encryptedLogs: this.encryptedLogs.toBuffer().toString('hex'), unencryptedLogs: this.unencryptedLogs.toBuffer().toString('hex'), proof: this.proof.toBuffer().toString('hex'), - newContractPublicFunctions: this.newContractPublicFunctions.map(f => f.toBuffer().toString('hex')) ?? [], enqueuedPublicFunctions: this.enqueuedPublicFunctionCalls.map(f => f.toBuffer().toString('hex')) ?? [], + newContracts: this.newContracts.map(c => c.toBuffer().toString('hex')), }; } @@ -125,19 +122,17 @@ export class Tx { const encryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.encryptedLogs, 'hex')); const unencryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.unencryptedLogs, 'hex')); const proof = Buffer.from(obj.proof, 'hex'); - const newContractPublicFunctions = obj.newContractPublicFunctions - ? obj.newContractPublicFunctions.map((x: string) => EncodedContractFunction.fromBuffer(Buffer.from(x, 'hex'))) - : []; const enqueuedPublicFunctions = obj.enqueuedPublicFunctions ? obj.enqueuedPublicFunctions.map((x: string) => PublicCallRequest.fromBuffer(Buffer.from(x, 'hex'))) : []; + const newContracts = obj.newContracts.map((x: string) => ExtendedContractData.fromBuffer(Buffer.from(x, 'hex'))); return new Tx( publicInputs, Proof.fromBuffer(proof), encryptedLogs, unencryptedLogs, - newContractPublicFunctions, enqueuedPublicFunctions, + newContracts, ); } @@ -171,51 +166,13 @@ export class Tx { const proof = Proof.fromBuffer(tx.proof.toBuffer()); const encryptedLogs = TxL2Logs.fromBuffer(tx.encryptedLogs.toBuffer()); const unencryptedLogs = TxL2Logs.fromBuffer(tx.unencryptedLogs.toBuffer()); - const publicFunctions = tx.newContractPublicFunctions.map(x => { - return EncodedContractFunction.fromBuffer(x.toBuffer()); - }); const enqueuedPublicFunctions = tx.enqueuedPublicFunctionCalls.map(x => { return PublicCallRequest.fromBuffer(x.toBuffer()); }); - return new Tx(publicInputs, proof, encryptedLogs, unencryptedLogs, publicFunctions, enqueuedPublicFunctions); - } -} - -/** - * Wrapper class for a contract deployment transaction. - * Also contains the contract partial address - */ -export class ContractDeploymentTx { - public constructor( - /** - * The Tx being wrapped. - */ - public readonly tx: Tx, - - /** - * The partially conputed contract address. - */ - public readonly partialAddress: PartialAddress, - - /** - * The complete contract address. - */ - public readonly contractAddress: AztecAddress, - ) {} - - toJSON() { - return { - tx: this.tx.toJSON(), - partialAddress: this.partialAddress.toBuffer().toString(), - contractAddress: this.contractAddress.toBuffer().toString(), - }; - } - - static fromJSON(obj: any) { - return new ContractDeploymentTx( - Tx.fromJSON(obj.tx), - Fr.fromBuffer(Buffer.from(obj.partialAddress, 'hex')), - AztecAddress.fromBuffer(Buffer.from(obj.contractAddress, 'hex')), - ); + const newContracts = tx.newContracts.map(c => ExtendedContractData.fromBuffer(c.toBuffer())) as Tuple< + ExtendedContractData, + typeof MAX_NEW_CONTRACTS_PER_TX + >; + return new Tx(publicInputs, proof, encryptedLogs, unencryptedLogs, enqueuedPublicFunctions, newContracts); } }