Migration notes
Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them.
0.86.0
[PXE] Removed PXE_L2_STARTING_BLOCK environment variable
PXE now fast-syncs by skipping finalized blocks and never downloads all blocks, so there is no longer a need to specify a starting block.
[Aztec.nr] Logs and messages renaming
The following renamings have taken place:
encrypted_logs
tomessages
: this module now handles much more than just encrypted logs (including unconstrained message delivery, message encoding, etc.)log_assembly_strategies
tologs
discovery
moved tomessages
: given that what is discovered are messagesdefault_aes128
removed
Most contracts barely used these modules, the only frequent imports are the encode_and_encrypt
functions:
- use dep::aztec::messages::logs::note::encode_and_encrypt_note;
+ use dep::aztec::messages::logs::note::encode_and_encrypt_note;
[noir-contracts] Reference Noir contracts directory structure change
noir-projects/noir-contracts/contracts
directory became too cluttered so we grouped contracts into account
, app
, docs
, fees
, libs
, protocol
and test
dirs.
If you import contract from the directory make sure to update the paths accordingly.
E.g. for a token contract:
#[dependencies]
-token = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v0.83.0", directory = "noir-projects/noir-contracts/contracts/src/token_contract" }
+token = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v0.83.0", directory = "noir-projects/noir-contracts/contracts/app/src/token_contract" }
[Aztec.nr] #[utility] contract functions
Aztec contracts have three kinds of functions: #[private]
, #[public]
and what was sometimes called 'top-level unconstrained': an unmarked unconstrained function in the contract module. These are now called [#utility]
functions, and must be explicitly marked as such:
+ #[utility]
unconstrained fn balance_of_private(owner: AztecAddress) -> u128 {
storage.balances.at(owner).balance_of()
}
Utility functions are standalone unconstrained functions that cannot be called from private or public functions: they are meant to be called by applications to perform auxiliary tasks: query contract state (e.g. a token balance), process messages received off-chain, etc.
All functions in a contract
block must now be marked as one of either #[private]
, #[public]
, #[utility]
, #[contract_library_method]
, or #[test]
.
Additionally, the UnconstrainedContext
type has been renamed to UtilityContext
. This led us to rename the unkonstrained
method on TestEnvironment
to utility
, so any tests using it also need updating:
- SharedMutable::new(env.unkonstrained(), storage_slot)
+ SharedMutable::new(env.utility(), storage_slot)
[AuthRegistry] function name change
As part of the broader transition from "top-level unconstrained" to "utility" name (detailed in the note above), the unconstrained_is_consumable
function in AuthRegistry has been renamed to utility_is_consumable
. The function's signature and behavior remain unchanged - only the name has been updated to align with the new convention. If you're currently using this function, a simple rename in your code will suffice.
0.83.0
[aztec.js] AztecNode.getPrivateEvents API change
The getPrivateEvents
method signature has changed to require an address of a contract that emitted the event and use recipient addresses instead of viewing public keys:
- const events = await wallet.getPrivateEvents<Transfer>(TokenContract.events.Transfer, 1, 1, [recipient.getCompleteAddress().publicKeys.masterIncomingViewingPublicKey()]);
+ const events = await wallet.getPrivateEvents<Transfer>(token.address, TokenContract.events.Transfer, 1, 1, [recipient.getAddress()]);
[portal contracts] Versions and Non-following message boxes
The version number is no longer hard-coded to be 1
across all deployments (it not depends on where it is deployed to and with what genesis and logic).
This means that if your portal were hard-coding 1
it will now fail when inserting into the inbox
or consuming from the outbox
because of a version mismatch.
Instead you can get the real version (which don't change for a deployment) by reading the VERSION
on inbox and outbox, or using getVersion()
on the rollup.
New Deployments of the protocol do not preserve former state/across each other. This means that after a new deployment, any "portal" following the registry would try to send messages into this empty rollup to non-existant contracts. To solve, the portal should be linked to a specific deployment, e.g., a specific inbox. This can be done by storing the inbox/outbox/version at the time of deployment or initialize and not update them.
Both of these issues were in the token portal and the uniswap portal, so if you used them as a template it is very likely that you will also have it.
0.82.0
[aztec.js] AztecNode.findLeavesIndexes returns indexes with block metadata
It's common that we need block metadata of a block in which leaves where inserted when querying indexes of these tree leaves. For this reason we now return that information along with the indexes. This allows us to reduce the number of individual AztecNode queries.
Along this change findNullifiersIndexesWithBlock
and findBlockNumbersForIndexes
functions wer removed as all its uses can now be replaced with the newly modified findLeavesIndexes
function.
[aztec.js] AztecNode.getPublicDataTreeWitness renamed as AztecNode.getPublicDataWitness
This change was done to have consistent naming across codebase.
[aztec.js] Wallet interface and Authwit management
The Wallet
interface in aztec.js
is undergoing transformations, trying to be friendlier to wallet builders and reducing the surface of its API. This means Wallet
no longer extends PXE
, and instead just implements a subset of the methods of the former. This is NOT going to be its final form, but paves the way towards better interfaces and starts to clarify what the responsibilities of the wallet are:
/**
* The wallet interface.
*/
export type Wallet = AccountInterface &
Pick<
PXE,
// Simulation
| "simulateTx"
| "simulateUnconstrained"
| "profileTx"
// Sending
| "sendTx"
// Contract management (will probably be collapsed in the future to avoid instance and class versions)
| "getContractClassMetadata"
| "getContractMetadata"
| "registerContract"
| "registerContractClass"
// Likely to be removed
| "proveTx"
// Will probably be collapsed
| "getNodeInfo"
| "getPXEInfo"
// Fee info
| "getCurrentBaseFees"
// Still undecided, kept for the time being
| "updateContract"
// Sender management
| "registerSender"
| "getSenders"
| "removeSender"
// Tx status
| "getTxReceipt"
// Events. Kept since events are going to be reworked and changes will come when that's done
| "getPrivateEvents"
| "getPublicEvents"
> & {
createAuthWit(intent: IntentInnerHash | IntentAction): Promise<AuthWitness>;
};
As a side effect, a few debug only features have been removed
// Obtain tx effects
const { txHash, debugInfo } = await contract.methods
.set_constant(value)
.send()
-- .wait({ interval: 0.1, debug: true });
++ .wait({ interval: 0.1 })
-- // check that 1 note hash was created
-- expect(debugInfo!.noteHashes.length).toBe(1);
++ const txEffect = await aztecNode.getTxEffect(txHash);
++ const noteHashes = txEffect?.data.noteHashes;
++ // check that 1 note hash was created
++ expect(noteHashes?.length).toBe(1);
// Wait for a tx to be proven
-- tx.wait({ timeout: 300, interval: 10, proven: true, provenTimeout: 3000 })));
++ const receipt = await tx.wait({ timeout: 300, interval: 10 });
++ await waitForProven(aztecNode, receipt, { provenTimeout: 3000 });
Authwit management has changed, and PXE no longer stores them. This is unnecessary because now they can be externally provided to simulations and transactions, making sure no stale authorizations are kept inside PXE's db.
const witness = await wallet.createAuthWit({ caller, action });
--await callerWallet.addAuthWitness(witness);
--await action.send().wait();
++await action.send({ authWitnesses: [witness] }).wait();
Another side effect of this is that the interface of the lookupValidity
method has changed, and now the authwitness has to be provided:
const witness = await wallet.createAuthWit({ caller, action });
--await callerWallet.addAuthWitness(witness);
--await wallet.lookupValidity(wallet.getAddress(), { caller, action });
++await wallet.lookupValidity(wallet.getAddress(), { caller, action }, witness);
0.80.0
[PXE] Concurrent contract function simulation disabled
PXE is no longer be able to execute contract functions concurrently (e.g. by collecting calls to simulateTx
and then using await Promise.all
). They will instead be put in a job queue and executed sequentially in order of arrival.
0.79.0
[aztec.js] Changes to BatchCall
and BaseContractInteraction
The constructor arguments of BatchCall
have been updated to improve usability. Previously, it accepted an array of FunctionCall
, requiring users to manually set additional data such as authwit
and capsules
. Now, BatchCall
takes an array of BaseContractInteraction
, which encapsulates all necessary information.
class BatchCall extends BaseContractInteraction {
- constructor(wallet: Wallet, protected calls: FunctionCall[]) {
+ constructor(wallet: Wallet, protected calls: BaseContractInteraction[]) {
...
}
The request
method of BaseContractInteraction
now returns ExecutionPayload
. This object includes all the necessary data to execute one or more functions. BatchCall
invokes this method on all interactions to aggregate the required information. It is also used internally in simulations for fee estimation.
Declaring a BatchCall
:
new BatchCall(wallet, [
- await token.methods.transfer(alice, amount).request(),
- await token.methods.transfer_to_private(bob, amount).request(),
+ token.methods.transfer(alice, amount),
+ token.methods.transfer_to_private(bob, amount),
])
0.77.0
[aztec-nr] TestEnvironment::block_number()
refactored
The block_number
function from TestEnvironment
has been expanded upon with two extra functions, the first being pending_block_number
, and the second being committed_block_number
. pending_block_number
now returns what block_number
does. In other words, it returns the block number of the block we are currently building. committed_block_number
returns the block number of the last committed block, i.e. the block number that gets used to execute the private part of transactions when your PXE is successfully synced to the tip of the chain.
+ `TestEnvironment::pending_block_number()`
+ `TestEnvironment::committed_block_number()`
[aztec-nr] compute_nullifier_without_context
renamed
The compute_nullifier_without_context
function from NoteHash
(ex NoteInterface
) is now called compute_nullifier_unconstrained
, and instead of taking storage slot, contract address and nonce it takes a note hash for nullification (same as compute_note_hash
). This makes writing this
function simpler:
- unconstrained fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, nonce: Field) -> Field {
- let note_hash_for_nullify = ...;
+ unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field {
...
}