Skip to content

Conversation

@Thunkar
Copy link
Contributor

@Thunkar Thunkar commented Jan 9, 2026

This PR aims to improve getContractMetadata and getContractClassMetadata in the Wallet interface, avoiding the expensive back-and-forth of sending artifacts and classes.

Main change is that there was a weird roundabout thing when accessing protocol contracts. These are preloaded in PXE and fixed for a given aztec version, so pulling them from the wallet just to compute the ABI was incredibly wasteful.
This PR pregenerates the ABI for them because we can count on the contracts being available inside PXE. It does add a generate step to aztec.js but I think the tradeoff is well worth it. It also hints that we should separate bytecode and ABI soon.

It also removes getContractMetadata and getContractClassMetadata from PXE. These are from a time when PXE was accessed directly by apps and it obscured information, you could never be sure if you were pulling from PXE's internal storage or were asking the node directly. They are replaced by simple instance artifact getters, and it's the wallet's job to assemble the metadata. This metadata has been refactored:

ContractMetadata

  • instance: very lightweight, essentially tells you about the "version" of the contract PXE has registered if at all. An undefined value would mean PXE does not know about it (no node proxying nonsense). This is a potential privacy leak, however:
    • Wallets need a comprehensive authorization framework anyways: "do you want to let app X know information about stored contract Y?"
    • A malicious app could always attempt to simulate an see if it gets a "contract not registered in PXE" error
  • isContractInitialized : even if PXE does not know about the contract, we can compute the initialization nullifier and check if it's published. Not leaky, public info.
  • isContractPublished: does the contract exist in the node?
  • isContractUpdated: Since updates are forcibly public, we can get the contract from the node and check its currentContractClassId and originalContractClassId. If mismatched, the contract has been updated.
  • updatedContractClassId: If the previous is true, we put nodeContract.currentContractClassId here, allowing the app to see if instance.currentContractClassId matches and creating a convenient way to know if it's necessary to registerContract(instance, newArtifact)

ContractClassMetadata

  • isContractClassPubliclyRegistered: This makes deployments extremely convenient, as we can know in the TS wrapper for the contract with just the wallet whether we need to include class registration in the payload or not.
  • isArtifactRegistered: Does PXE know about this artifact?

@Thunkar Thunkar self-assigned this Jan 9, 2026
@Thunkar Thunkar added the ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure label Jan 9, 2026
@Thunkar Thunkar force-pushed the gj/cleanup_wallet_interface branch from 9ed5b8f to 0b94a99 Compare January 12, 2026 06:14
@Thunkar Thunkar changed the title feat: remove getContractMetadata and getContractClassMetadata from Wallet feat: refactor getContractMetadata and getContractClassMetadata in Wallet Jan 12, 2026
@AztecBot
Copy link
Collaborator

AztecBot commented Jan 12, 2026

Flakey Tests

🤖 says: This CI run detected 4 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/9e4b0af83bee49a0�9e4b0af83bee49a08;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_epochs/epochs_invalidate_block.parallel.test.ts "committee member invalidates a block if proposer does not come through" (96s) (code: 1) group:e2e-p2p-epoch-flakes (\033Gregorio Juliana\033: feat: refactor `getContractMetadata` and `getContractClassMetadata` in `Wallet` (#19457))
\033FLAKED\033 (8;;http://ci.aztec-labs.com/9a8124864c57af4d�9a8124864c57af4d8;;�): yarn-project/end-to-end/scripts/run_test.sh web3signer src/composed/web3signer/e2e_multi_validator_node_key_store.test.ts (36s) (code: 1) (\033Gregorio Juliana\033: feat: refactor `getContractMetadata` and `getContractClassMetadata` in `Wallet` (#19457))
\033FLAKED\033 (8;;http://ci.aztec-labs.com/b6fb4b1e246b8140�b6fb4b1e246b81408;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_epochs/epochs_high_tps_block_building.test.ts (289s) (code: 1) group:e2e-p2p-epoch-flakes (\033Gregorio Juliana\033: feat: refactor `getContractMetadata` and `getContractClassMetadata` in `Wallet` (#19457))
\033FLAKED\033 (8;;http://ci.aztec-labs.com/5a12ed38509aed39�5a12ed38509aed398;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_p2p/gossip_network.test.ts (451s) (code: 1) group:e2e-p2p-epoch-flakes (\033Gregorio Juliana\033: feat: refactor `getContractMetadata` and `getContractClassMetadata` in `Wallet` (#19457))

Copy link
Contributor

@benesjan benesjan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great and would approve if it was for the duplicate code between builder and aztec.js.

BTW any reasons why the protocol contract generation could not be in a separate PR? It seems quite independent from the other changes in this PR and it makes the change somewhat hidden (it's not in the PR title) and the PR harder to review.

: undefined,
);
await Promise.all(classIds.map(classId => (classId ? wallet.getContractArtifact(classId) : undefined)))
).map((artifact, index) => (artifact ? { ...artifact, classId: classIds[index] } : undefined));
Copy link
Contributor

@benesjan benesjan Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This transformation is quite hard to grok.

Why not first filter out the undefineds so that we don't need to do classId ? ... and artifact ? ...?

Copy link
Contributor Author

@Thunkar Thunkar Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we would lose the indexing information, and the classId assignment would get messed up. TBH I'm still very much in favor of killing this command...

@Thunkar
Copy link
Contributor Author

Thunkar commented Jan 13, 2026

BTW any reasons why the protocol contract generation could not be in a separate PR? It seems quite independent from the other changes in this PR and it makes the change somewhat hidden (it's not in the PR title) and the PR harder to review.

The main objective was to unblock the removal of getContractMetadata and getContractClassMetadata, which required the protocol contract change and not much else. Unfortunately ran into the problems I detailed on slack, so it became a bigger refactor 😢

…n `Wallet`

This PR aims to improve `getContractMetadata` and `getContractClassMetadata` in the `Wallet` interface, avoiding the expensive back-and-forth of sending artifacts and classes.

Main change is that there was a weird roundabout thing when accessing protocol contracts. These are preloaded in PXE and fixed for a given aztec version, so pulling them from the wallet just to compute the ABI was incredibly wasteful.
This PR pregenerates the ABI for them because we can count on the contracts being available inside PXE. It does add a `generate` step to `aztec.js` but I think the tradeoff is well worth it. It also hints that we should separate bytecode and ABI soon.

It also removes `getContractMetadata` and `getContractClassMetadata` from PXE. These are from a time when PXE was accessed directly by apps and it obscured information, you could never be sure if you were pulling from PXE's internal storage or were asking the node directly. They are replaced by simple instance artifact getters, and it's the wallet's job to assemble the metadata. This metadata has been refactored:

## `ContractMetadata`

* `instance`: very lightweight, essentially tells you about the "version" of the contract PXE has registered if at all. An undefined value would mean PXE does not know about it (no node proxying nonsense). This is a potential privacy leak, however:
  - Wallets need a comprehensive authorization framework anyways: "do you want to let app X know information about stored contract Y?"
  - A malicious app could always attempt to simulate an see if it gets a "contract not registered in PXE" error
* `isContractInitialized` : even if PXE does not know about the contract, we can compute the initialization nullifier and check if it's published. Not leaky, public info.
* `isContractPublished`: does the contract exist in the node?
* `isContractUpdated`: Since updates are forcibly public, we can get the contract from the node and check its currentContractClassId and originalContractClassId. If mismatched, the contract has been updated.
* `updatedContractClassId`: If the previous is true, we put nodeContract.currentContractClassId here, allowing the app to see if instance.currentContractClassId matches and creating a convenient way to know if it's necessary to `registerContract(instance, newArtifact)`

## `ContractClassMetadata`
* `isContractClassPubliclyRegistered`: This makes deployments extremely convenient, as we can know in the TS wrapper for the contract with just the wallet whether we need to include class registration in the payload or not.
* `isArtifactRegistered`: Does PXE know about this artifact?
@AztecBot AztecBot force-pushed the gj/cleanup_wallet_interface branch from 4e46222 to cb46a9d Compare January 13, 2026 07:37
Copy link
Contributor

@mverzilli mverzilli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always nice to see some code go away from PXE :D

@AztecBot AztecBot added this pull request to the merge queue Jan 13, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 13, 2026
@Thunkar Thunkar added this pull request to the merge queue Jan 13, 2026
Merged via the queue into next with commit b37c199 Jan 13, 2026
17 checks passed
@Thunkar Thunkar deleted the gj/cleanup_wallet_interface branch January 13, 2026 11:11
AztecBot pushed a commit that referenced this pull request Jan 16, 2026
Allows ALL methods in the wallet to be batched (because why not). Initially I was going for allowing them on a case-by-case basis, but integrating the Wallet SDK has made apparent apps can have many interaction flows and this extra flexibility is nice.

Updated the migration notes and in the process realized I missed exporting some artifacts in #19457, so here they are (protocol contract wrappers)

Co-authored-by: thunkar <gregojquiros@gmail.com>
AztecBot pushed a commit that referenced this pull request Jan 16, 2026
Allows ALL methods in the wallet to be batched (because why not). Initially I was going for allowing them on a case-by-case basis, but integrating the Wallet SDK has made apparent apps can have many interaction flows and this extra flexibility is nice.

Updated the migration notes and in the process realized I missed exporting some artifacts in #19457, so here they are (protocol contract wrappers)
AztecBot pushed a commit that referenced this pull request Jan 18, 2026
Allows ALL methods in the wallet to be batched (because why not). Initially I was going for allowing them on a case-by-case basis, but integrating the Wallet SDK has made apparent apps can have many interaction flows and this extra flexibility is nice.

Updated the migration notes and in the process realized I missed exporting some artifacts in #19457, so here they are (protocol contract wrappers)

Co-authored-by: thunkar <gregojquiros@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants