Skip to content

Commit 2ea329a

Browse files
authored
feat: expose wallet.registerContractClass (prep for simulating contract upgrades) (#22932)
Adds `wallet.registerContractClass(artifact)` (a thin pass-through to PXE) so external callers can register a new class artifact locally before passing an instance override (next pr) that targets it. Without this, PXE-side ACIR dispatch can't resolve private functions of the override's class. `ContractClassesCapability` gains a `canRegister?: boolean` flag so wallets can grant or deny the new method via the capability manifest, matching the existing `ContractsCapability.canRegister` pattern. With `fastForwardContractUpdate` (next pr in stack) plus this method, a single `.simulate({ overrides })` covers both private and public function calls on an upgraded contract: ```typescript await wallet.registerContractClass(UpdatedContract.artifact); // and then upcoming work: const overrides = await fastForwardContractUpdate({ instanceAddress, newClassId, node }); await updatedContract.methods.set_private_value().simulate({ from, overrides }); ```
1 parent eb2103c commit 2ea329a

5 files changed

Lines changed: 41 additions & 5 deletions

File tree

yarn-project/aztec.js/src/wallet/capabilities.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,25 @@ export interface ContractsCapability {
138138
export interface GrantedContractsCapability extends ContractsCapability {}
139139

140140
/**
141-
* Contract class capability - for querying contract class metadata.
141+
* Contract class capability - for querying contract class meatadata and registering contract classes.
142142
*
143143
* Maps to wallet methods:
144-
* - getContractClassMetadata
144+
* - getContractClassMetadata (when canGetMetadata: true)
145+
* - registerContractClass (when canRegister: true)
145146
*
146147
* Contract classes are identified by their class ID (Fr), not by contract address.
147148
* Multiple contract instances can share the same class. This capability grants
148-
* permission to query metadata for specific contract classes.
149+
* permission to query metadata for, and register, specific contract classes.
149150
*
150151
* Apps typically acquire this permission automatically when registering a contract
151152
* with an artifact (the wallet auto-grants permission for that contract's class ID).
152153
*
153154
* @example
154-
* // Query specific contract classes
155+
* // Register and query a specific contract class
155156
* \{
156157
* type: 'contractClasses',
157-
* classes: [classId1, classId2],
158+
* classes: [classId1],
159+
* canRegister: true,
158160
* canGetMetadata: true
159161
* \}
160162
*
@@ -177,6 +179,9 @@ export interface ContractClassesCapability {
177179
*/
178180
classes: '*' | Fr[];
179181

182+
/** Can register a contract class artifact in the local PXE. Maps to: registerContractClass */
183+
canRegister?: boolean;
184+
180185
/** Can query contract class metadata. Maps to: getContractClassMetadata */
181186
canGetMetadata: boolean;
182187
}

yarn-project/aztec.js/src/wallet/wallet.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,19 @@ describe('WalletSchema', () => {
157157
});
158158
});
159159

160+
it('registerContractClass', async () => {
161+
const mockArtifact: ContractArtifact = {
162+
name: 'TestContract',
163+
aztecVersion: DEV_VERSION,
164+
functions: [],
165+
nonDispatchPublicFunctions: [],
166+
outputs: { structs: {}, globals: {} },
167+
fileMap: {},
168+
storageLayout: {},
169+
};
170+
await context.client.registerContractClass(mockArtifact);
171+
});
172+
160173
it('simulateTx', async () => {
161174
const exec: ExecutionPayload = {
162175
calls: [],
@@ -451,6 +464,8 @@ class MockWallet implements Wallet {
451464
};
452465
}
453466

467+
async registerContractClass(_artifact: any): Promise<void> {}
468+
454469
async simulateTx(_exec: ExecutionPayload, _opts: SimulateOptions): Promise<TxSimulationResultWithAppOffset> {
455470
return TxSimulationResultWithAppOffset.fromResultAndOffset(await TxSimulationResult.random(), 0);
456471
}

yarn-project/aztec.js/src/wallet/wallet.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,12 @@ export type Wallet = {
272272
artifact?: ContractArtifact,
273273
secretKey?: Fr,
274274
): Promise<ContractInstanceWithAddress>;
275+
/**
276+
* Registers a contract class artifact in the local PXE without binding it to any instance.
277+
* Useful for simulation flows that need the artifact available locally before any on-chain
278+
* upgrade has taken effect. No chain check.
279+
*/
280+
registerContractClass(artifact: ContractArtifact): Promise<void>;
275281
simulateTx(exec: ExecutionPayload, opts: SimulateOptions): Promise<TxSimulationResultWithAppOffset>;
276282
executeUtility(call: FunctionCall, opts: ExecuteUtilityOptions): Promise<UtilityExecutionResult>;
277283
profileTx(exec: ExecutionPayload, opts: ProfileOptions): Promise<TxProfileResult>;
@@ -429,6 +435,7 @@ export const GrantedContractsCapabilitySchema = ContractsCapabilitySchema;
429435
export const ContractClassesCapabilitySchema = z.object({
430436
type: z.literal('contractClasses'),
431437
classes: z.union([z.literal('*'), z.array(schemas.Fr)]),
438+
canRegister: optional(z.boolean()),
432439
canGetMetadata: z.boolean(),
433440
});
434441

@@ -559,6 +566,7 @@ const WalletMethodSchemas = {
559566
.function()
560567
.args(ContractInstanceWithAddressSchema, optional(ContractArtifactSchema), optional(schemas.Fr))
561568
.returns(ContractInstanceWithAddressSchema),
569+
registerContractClass: z.function().args(ContractArtifactSchema).returns(z.void()),
562570
simulateTx: z
563571
.function()
564572
.args(ExecutionPayloadSchema, SimulateOptionsSchema)

yarn-project/end-to-end/src/test-wallet/worker_wallet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ export class WorkerWallet implements Wallet {
166166
return this.call('registerContract', instance, artifact, secretKey);
167167
}
168168

169+
registerContractClass(artifact: ContractArtifact): Promise<void> {
170+
return this.call('registerContractClass', artifact);
171+
}
172+
169173
simulateTx(exec: ExecutionPayload, opts: SimulateOptions): Promise<TxSimulationResultWithAppOffset> {
170174
return this.call('simulateTx', exec, opts);
171175
}

yarn-project/wallet-sdk/src/base-wallet/base_wallet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ export abstract class BaseWallet implements Wallet {
348348
return instance;
349349
}
350350

351+
registerContractClass(artifact: ContractArtifact): Promise<void> {
352+
return this.pxe.registerContractClass(artifact);
353+
}
354+
351355
/**
352356
* Simulates calls through the standard PXE path (account entrypoint).
353357
* @param executionPayload - The execution payload to simulate.

0 commit comments

Comments
 (0)