Skip to content

fix: always register contracts with wallet PXE#11

Closed
alejoamiras wants to merge 1 commit intomainfrom
fix/always-register-contracts-with-pxe
Closed

fix: always register contracts with wallet PXE#11
alejoamiras wants to merge 1 commit intomainfrom
fix/always-register-contracts-with-pxe

Conversation

@alejoamiras
Copy link

Summary

Fixes "Unknown contract" error during onboarding simulation (balance_of_private on gregoCoin) when connecting an external wallet.

  • Remove conditional getContractMetadata check before contract registration in both registerSwapContracts and registerDripContracts
  • Always register all contracts with their artifacts in a single batch call
  • Fix gregoCoinPremium artifact — was registered with undefined, now explicitly passes TokenContractArtifact

Root cause

The old code called getContractMetadata first and skipped registration when metadata.result.instance was truthy. This broke because:

  1. instance comes from the PXE's LMDB (pxe.getContractInstance() — pure local read, no node fallback). A wallet with persistent storage from a prior session returns truthy instance data even when the artifact is missing (e.g. after a wallet extension update or SDK version change).

  2. The wallet SDK's registerContract (base_wallet.ts:264-273) treats matching class IDs as a no-op — it does not verify the artifact is still present. So skipping registration left the PXE with instance data but no artifact.

  3. During simulation, contractStore.getContract() needs both instance AND artifact to resolve. Returns undefined when either is missing → getFunctionCall() throws Unknown contract.

Why removing the check is actually faster

The old code was not a performance optimization — it was slower:

Old code New code
Batch round-trips 2 (getContractMetadata + registerContract) 1 (registerContract only)
Node queries 6 (getContractMetadata queries aztecNode.getContract() + getNullifierMembershipWitness() per contract) 0
Local computation Conditional getContractInstanceFromInstantiationParams Always (pure hash, no I/O)

The getContractMetadata pre-check was redundantregisterContract already does its own idempotency check internally via pxe.getContractInstance() (base_wallet.ts:262). So the old code was paying for an extra batch round-trip + 6 node queries just to duplicate a check that the SDK already performs.

Known limitation

If the wallet's PXE has a stale instance with matching class ID but a lost artifact, the wallet SDK's registerContract will still no-op (it only calls pxe.updateContract when class IDs differ). This is a wallet SDK concern — it should verify artifact presence, not just class ID equality.

Test plan

  • Connect external wallet on devnet → onboarding completes without "Unknown contract" error
  • Token balances display correctly after onboarding
  • Swap flow works end-to-end
  • Drip (faucet) flow works for zero-balance accounts
  • Reconnecting a previously-used wallet still works (idempotent registration)

🤖 Generated with Claude Code

… check

The old code called getContractMetadata before registration and skipped
contracts where metadata.result.instance was truthy. This caused
"Unknown contract" errors during simulation because:

1. getContractMetadata.instance comes from pxe.getContractInstance()
   (LMDB local read). A wallet with persistent storage from a prior
   session returns truthy instance data even when the artifact is
   missing (e.g. after a wallet update or SDK version change).

2. The wallet SDK's registerContract (base_wallet.ts:257-293) treats
   matching class IDs as a no-op—it does NOT verify the artifact is
   still present. So skipping registration left the PXE with instance
   data but no artifact, causing getContract() to return undefined
   and simulation to throw "Unknown contract".

3. gregoCoinPremium was registered with undefined artifact, relying on
   gregoCoin's class being registered first in the same sequential
   batch. This was fragile and would break if gregoCoin was skipped.

The fix:
- Remove the getContractMetadata check entirely (also saves a batch
  round-trip through the wallet SDK communication layer)
- Always construct instances and register all contracts with their
  artifacts in a single batch
- registerContract is idempotent by design (base_wallet.ts checks
  pxe.getContractInstance internally), so re-registering is safe

Applied the same fix to registerDripContracts for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Mar 2, 2026

🚀 Deployed to Vercel!

Preview URL: https://gregoswap-kzyoppimm-thunkars-projects.vercel.app

@alejoamiras alejoamiras closed this Mar 2, 2026
@alejoamiras alejoamiras deleted the fix/always-register-contracts-with-pxe branch March 3, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant