@aztec/aztec.js 0.33.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dest/account/contract.d.ts +6 -1
  2. package/dest/account/contract.d.ts.map +1 -1
  3. package/dest/account/contract.js +1 -1
  4. package/dest/account_manager/deploy_account_method.d.ts +15 -0
  5. package/dest/account_manager/deploy_account_method.d.ts.map +1 -0
  6. package/dest/account_manager/deploy_account_method.js +43 -0
  7. package/dest/account_manager/deploy_account_sent_tx.d.ts +3 -3
  8. package/dest/account_manager/deploy_account_sent_tx.d.ts.map +1 -1
  9. package/dest/account_manager/deploy_account_sent_tx.js +7 -6
  10. package/dest/account_manager/index.d.ts +9 -3
  11. package/dest/account_manager/index.d.ts.map +1 -1
  12. package/dest/account_manager/index.js +21 -17
  13. package/dest/contract/batch_call.d.ts.map +1 -1
  14. package/dest/contract/batch_call.js +5 -2
  15. package/dest/contract/contract_function_interaction.d.ts +4 -4
  16. package/dest/contract/contract_function_interaction.d.ts.map +1 -1
  17. package/dest/contract/contract_function_interaction.js +9 -5
  18. package/dest/contract/deploy_method.d.ts +11 -4
  19. package/dest/contract/deploy_method.d.ts.map +1 -1
  20. package/dest/contract/deploy_method.js +33 -15
  21. package/dest/contract/deploy_sent_tx.js +2 -2
  22. package/dest/entrypoint/default_entrypoint.d.ts +3 -3
  23. package/dest/entrypoint/default_entrypoint.d.ts.map +1 -1
  24. package/dest/entrypoint/default_entrypoint.js +11 -7
  25. package/dest/entrypoint/default_multi_call_entrypoint.d.ts +15 -0
  26. package/dest/entrypoint/default_multi_call_entrypoint.d.ts.map +1 -0
  27. package/dest/entrypoint/default_multi_call_entrypoint.js +85 -0
  28. package/dest/entrypoint/entrypoint.d.ts +17 -14
  29. package/dest/entrypoint/entrypoint.d.ts.map +1 -1
  30. package/dest/entrypoint/entrypoint.js +5 -2
  31. package/dest/entrypoint/payload.d.ts +73 -0
  32. package/dest/entrypoint/payload.d.ts.map +1 -0
  33. package/dest/entrypoint/payload.js +109 -0
  34. package/dest/fee/fee_payment_method.d.ts +3 -4
  35. package/dest/fee/fee_payment_method.d.ts.map +1 -1
  36. package/dest/fee/native_fee_payment_method.d.ts +4 -5
  37. package/dest/fee/native_fee_payment_method.d.ts.map +1 -1
  38. package/dest/fee/native_fee_payment_method.js +5 -5
  39. package/dest/fee/private_fee_payment_method.d.ts +3 -2
  40. package/dest/fee/private_fee_payment_method.d.ts.map +1 -1
  41. package/dest/fee/private_fee_payment_method.js +4 -3
  42. package/dest/fee/public_fee_payment_method.d.ts +3 -3
  43. package/dest/fee/public_fee_payment_method.d.ts.map +1 -1
  44. package/dest/fee/public_fee_payment_method.js +4 -3
  45. package/dest/index.d.ts +1 -1
  46. package/dest/index.d.ts.map +1 -1
  47. package/dest/index.js +2 -2
  48. package/dest/utils/authwit.d.ts.map +1 -1
  49. package/dest/utils/authwit.js +3 -3
  50. package/dest/utils/cheat_codes.d.ts +4 -4
  51. package/dest/utils/cheat_codes.d.ts.map +1 -1
  52. package/dest/utils/cheat_codes.js +11 -11
  53. package/dest/utils/pxe.js +3 -3
  54. package/dest/wallet/account_wallet.d.ts +2 -2
  55. package/dest/wallet/account_wallet.d.ts.map +1 -1
  56. package/dest/wallet/account_wallet.js +3 -3
  57. package/dest/wallet/base_wallet.d.ts +2 -2
  58. package/dest/wallet/base_wallet.d.ts.map +1 -1
  59. package/dest/wallet/signerless_wallet.d.ts +3 -3
  60. package/dest/wallet/signerless_wallet.d.ts.map +1 -1
  61. package/dest/wallet/signerless_wallet.js +3 -3
  62. package/package.json +7 -7
  63. package/src/account/contract.ts +7 -1
  64. package/src/account_manager/deploy_account_method.ts +74 -0
  65. package/src/account_manager/deploy_account_sent_tx.ts +6 -5
  66. package/src/account_manager/index.ts +39 -23
  67. package/src/contract/batch_call.ts +4 -1
  68. package/src/contract/contract_function_interaction.ts +11 -7
  69. package/src/contract/deploy_method.ts +44 -22
  70. package/src/contract/deploy_sent_tx.ts +1 -1
  71. package/src/entrypoint/default_entrypoint.ts +18 -11
  72. package/src/entrypoint/default_multi_call_entrypoint.ts +89 -0
  73. package/src/entrypoint/entrypoint.ts +19 -14
  74. package/src/entrypoint/payload.ts +144 -0
  75. package/src/fee/fee_payment_method.ts +3 -4
  76. package/src/fee/native_fee_payment_method.ts +5 -6
  77. package/src/fee/private_fee_payment_method.ts +4 -3
  78. package/src/fee/public_fee_payment_method.ts +4 -4
  79. package/src/index.ts +2 -2
  80. package/src/utils/authwit.ts +2 -2
  81. package/src/utils/cheat_codes.ts +10 -10
  82. package/src/utils/pxe.ts +2 -2
  83. package/src/wallet/account_wallet.ts +3 -3
  84. package/src/wallet/base_wallet.ts +2 -2
  85. package/src/wallet/signerless_wallet.ts +4 -4
@@ -1,4 +1,4 @@
1
- import { type TxHash, type TxReceipt } from '@aztec/circuit-types';
1
+ import { type PXE, type TxHash, type TxReceipt } from '@aztec/circuit-types';
2
2
  import { type FieldsOf } from '@aztec/foundation/types';
3
3
 
4
4
  import { type Wallet } from '../account/index.js';
@@ -15,8 +15,8 @@ export type DeployAccountTxReceipt = FieldsOf<TxReceipt> & {
15
15
  * A deployment transaction for an account contract sent to the network, extending SentTx with methods to get the resulting wallet.
16
16
  */
17
17
  export class DeployAccountSentTx extends SentTx {
18
- constructor(private wallet: Wallet, txHashPromise: Promise<TxHash>) {
19
- super(wallet, txHashPromise);
18
+ constructor(pxe: PXE, txHashPromise: Promise<TxHash>, private getWalletPromise: Promise<Wallet>) {
19
+ super(pxe, txHashPromise);
20
20
  }
21
21
 
22
22
  /**
@@ -36,7 +36,8 @@ export class DeployAccountSentTx extends SentTx {
36
36
  */
37
37
  public async wait(opts: WaitOpts = DefaultWaitOpts): Promise<DeployAccountTxReceipt> {
38
38
  const receipt = await super.wait(opts);
39
- await waitForAccountSynch(this.pxe, this.wallet.getCompleteAddress(), opts);
40
- return { ...receipt, wallet: this.wallet };
39
+ const wallet = await this.getWalletPromise;
40
+ await waitForAccountSynch(this.pxe, wallet.getCompleteAddress(), opts);
41
+ return { ...receipt, wallet };
41
42
  }
42
43
  }
@@ -6,14 +6,20 @@ import { type ContractInstanceWithAddress } from '@aztec/types/contracts';
6
6
  import { type AccountContract } from '../account/contract.js';
7
7
  import { type Salt } from '../account/index.js';
8
8
  import { type AccountInterface } from '../account/interface.js';
9
- import { type DeployMethod } from '../contract/deploy_method.js';
9
+ import { type DeployOptions } from '../contract/deploy_method.js';
10
10
  import { DefaultWaitOpts, type WaitOpts } from '../contract/sent_tx.js';
11
- import { ContractDeployer } from '../deployment/contract_deployer.js';
11
+ import { DefaultMultiCallEntrypoint } from '../entrypoint/default_multi_call_entrypoint.js';
12
12
  import { waitForAccountSynch } from '../utils/account.js';
13
13
  import { generatePublicKey } from '../utils/index.js';
14
14
  import { AccountWalletWithPrivateKey, SignerlessWallet } from '../wallet/index.js';
15
+ import { DeployAccountMethod } from './deploy_account_method.js';
15
16
  import { DeployAccountSentTx } from './deploy_account_sent_tx.js';
16
17
 
18
+ /**
19
+ * Options to deploy an account contract.
20
+ */
21
+ export type DeployAccountOptions = Pick<DeployOptions, 'fee' | 'skipClassRegistration' | 'skipPublicDeployment'>;
22
+
17
23
  /**
18
24
  * Manages a user account. Provides methods for calculating the account's address, deploying the account contract,
19
25
  * and creating and registering the user wallet in the PXE Service.
@@ -26,7 +32,7 @@ export class AccountManager {
26
32
  private completeAddress?: CompleteAddress;
27
33
  private instance?: ContractInstanceWithAddress;
28
34
  private encryptionPublicKey?: PublicKey;
29
- private deployMethod?: DeployMethod;
35
+ private deployMethod?: DeployAccountMethod;
30
36
 
31
37
  constructor(
32
38
  private pxe: PXE,
@@ -34,7 +40,7 @@ export class AccountManager {
34
40
  private accountContract: AccountContract,
35
41
  salt?: Salt,
36
42
  ) {
37
- this.salt = salt ? new Fr(salt) : Fr.random();
43
+ this.salt = salt !== undefined ? new Fr(salt) : Fr.random();
38
44
  }
39
45
 
40
46
  protected getEncryptionPublicKey() {
@@ -128,17 +134,22 @@ export class AccountManager {
128
134
  }
129
135
  await this.#register();
130
136
  const encryptionPublicKey = this.getEncryptionPublicKey();
131
- // We use a signerless wallet so we hit the account contract directly and it deploys itself.
137
+ const { chainId, protocolVersion } = await this.pxe.getNodeInfo();
138
+ const deployWallet = new SignerlessWallet(this.pxe, new DefaultMultiCallEntrypoint(chainId, protocolVersion));
139
+
140
+ // We use a signerless wallet with the multi call entrypoint in order to make multiple calls in one go
132
141
  // If we used getWallet, the deployment would get routed via the account contract entrypoint
133
- // instead of directly hitting the initializer.
134
- const deployWallet = new SignerlessWallet(this.pxe);
135
- const deployer = new ContractDeployer(
136
- this.accountContract.getContractArtifact(),
137
- deployWallet,
142
+ // and it can't be used unless the contract is initialized
143
+ const args = this.accountContract.getDeploymentArgs() ?? [];
144
+ this.deployMethod = new DeployAccountMethod(
145
+ this.accountContract.getAuthWitnessProvider(this.getCompleteAddress()),
138
146
  encryptionPublicKey,
147
+ deployWallet,
148
+ this.accountContract.getContractArtifact(),
149
+ args,
150
+ 'constructor',
151
+ 'entrypoint',
139
152
  );
140
- const args = this.accountContract.getDeploymentArgs() ?? [];
141
- this.deployMethod = deployer.deploy(...args);
142
153
  }
143
154
  return this.deployMethod;
144
155
  }
@@ -148,18 +159,23 @@ export class AccountManager {
148
159
  * Does not register the associated class nor publicly deploy the instance by default.
149
160
  * Uses the salt provided in the constructor or a randomly generated one.
150
161
  * Registers the account in the PXE Service before deploying the contract.
162
+ * @param opts - Fee options to be used for the deployment.
151
163
  * @returns A SentTx object that can be waited to get the associated Wallet.
152
164
  */
153
- public async deploy(): Promise<DeployAccountSentTx> {
154
- const deployMethod = await this.getDeployMethod();
155
- const wallet = await this.getWallet();
156
- const sentTx = deployMethod.send({
157
- contractAddressSalt: this.salt,
158
- skipClassRegistration: true,
159
- skipPublicDeployment: true,
160
- universalDeploy: true,
161
- });
162
- return new DeployAccountSentTx(wallet, sentTx.getTxHash());
165
+ public deploy(opts?: DeployAccountOptions): DeployAccountSentTx {
166
+ const sentTx = this.getDeployMethod()
167
+ .then(deployMethod =>
168
+ deployMethod.send({
169
+ contractAddressSalt: this.salt,
170
+ skipClassRegistration: opts?.skipClassRegistration ?? true,
171
+ skipPublicDeployment: opts?.skipPublicDeployment ?? true,
172
+ skipInitialization: false,
173
+ universalDeploy: true,
174
+ fee: opts?.fee,
175
+ }),
176
+ )
177
+ .then(tx => tx.getTxHash());
178
+ return new DeployAccountSentTx(this.pxe, sentTx, this.getWallet());
163
179
  }
164
180
 
165
181
  /**
@@ -170,7 +186,7 @@ export class AccountManager {
170
186
  * @returns A Wallet instance.
171
187
  */
172
188
  public async waitSetup(opts: WaitOpts = DefaultWaitOpts): Promise<AccountWalletWithPrivateKey> {
173
- await (this.isDeployable() ? this.deploy().then(tx => tx.wait(opts)) : this.register());
189
+ await (this.isDeployable() ? this.deploy().wait(opts) : this.register());
174
190
  return this.getWallet();
175
191
  }
176
192
 
@@ -17,7 +17,10 @@ export class BatchCall extends BaseContractInteraction {
17
17
  */
18
18
  public async create(opts?: SendMethodOptions): Promise<TxExecutionRequest> {
19
19
  if (!this.txRequest) {
20
- this.txRequest = await this.wallet.createTxExecutionRequest(this.calls, opts?.fee);
20
+ this.txRequest = await this.wallet.createTxExecutionRequest({
21
+ calls: this.calls,
22
+ fee: opts?.fee,
23
+ });
21
24
  }
22
25
  return this.txRequest;
23
26
  }
@@ -1,5 +1,5 @@
1
- import { type FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types';
2
- import { type AztecAddress, FunctionData, TxContext } from '@aztec/circuits.js';
1
+ import { type FunctionCall, PackedValues, TxExecutionRequest } from '@aztec/circuit-types';
2
+ import { type AztecAddress, FunctionData, GasSettings, TxContext } from '@aztec/circuits.js';
3
3
  import { type FunctionAbi, FunctionType, encodeArguments } from '@aztec/foundation/abi';
4
4
 
5
5
  import { type Wallet } from '../account/wallet.js';
@@ -13,10 +13,10 @@ export { SendMethodOptions };
13
13
  * Disregarded for simulation of public functions
14
14
  */
15
15
  export type SimulateMethodOptions = {
16
- /**
17
- * The sender's Aztec address.
18
- */
16
+ /** The sender's Aztec address. */
19
17
  from?: AztecAddress;
18
+ /** Gas settings for the simulation. */
19
+ gasSettings?: GasSettings;
20
20
  };
21
21
 
22
22
  /**
@@ -47,7 +47,10 @@ export class ContractFunctionInteraction extends BaseContractInteraction {
47
47
  throw new Error("Can't call `create` on an unconstrained function.");
48
48
  }
49
49
  if (!this.txRequest) {
50
- this.txRequest = await this.wallet.createTxExecutionRequest([this.request()], opts?.fee);
50
+ this.txRequest = await this.wallet.createTxExecutionRequest({
51
+ calls: [this.request()],
52
+ fee: opts?.fee,
53
+ });
51
54
  }
52
55
  return this.txRequest;
53
56
  }
@@ -89,7 +92,7 @@ export class ContractFunctionInteraction extends BaseContractInteraction {
89
92
 
90
93
  if (this.functionDao.functionType == FunctionType.SECRET) {
91
94
  const nodeInfo = await this.wallet.getNodeInfo();
92
- const packedArgs = PackedArguments.fromArgs(encodeArguments(this.functionDao, this.args));
95
+ const packedArgs = PackedValues.fromValues(encodeArguments(this.functionDao, this.args));
93
96
 
94
97
  const txRequest = TxExecutionRequest.from({
95
98
  argsHash: packedArgs.hash,
@@ -98,6 +101,7 @@ export class ContractFunctionInteraction extends BaseContractInteraction {
98
101
  txContext: TxContext.empty(nodeInfo.chainId, nodeInfo.protocolVersion),
99
102
  packedArguments: [packedArgs],
100
103
  authWitnesses: [],
104
+ gasSettings: options.gasSettings ?? GasSettings.simulation(),
101
105
  });
102
106
  const simulatedTx = await this.pxe.simulateTx(txRequest, false, options.from ?? this.wallet.getAddress());
103
107
  return simulatedTx.privateReturnValues?.[0];
@@ -14,6 +14,7 @@ import { type ContractInstanceWithAddress } from '@aztec/types/contracts';
14
14
  import { type Wallet } from '../account/index.js';
15
15
  import { deployInstance } from '../deployment/deploy_instance.js';
16
16
  import { registerContractClass } from '../deployment/register_class.js';
17
+ import { type ExecutionRequestInit } from '../entrypoint/entrypoint.js';
17
18
  import { BaseContractInteraction, type SendMethodOptions } from './base_contract_interaction.js';
18
19
  import { type Contract } from './contract.js';
19
20
  import { type ContractBase } from './contract_base.js';
@@ -53,7 +54,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
53
54
  private constructorArtifact: FunctionArtifact | undefined;
54
55
 
55
56
  /** Cached call to request() */
56
- private functionCalls: FunctionCall[] | undefined;
57
+ private functionCalls?: ExecutionRequestInit;
57
58
 
58
59
  private log = createDebugLogger('aztec:js:deploy_method');
59
60
 
@@ -80,10 +81,6 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
80
81
  */
81
82
  public async create(options: DeployOptions = {}): Promise<TxExecutionRequest> {
82
83
  if (!this.txRequest) {
83
- const calls = await this.request(options);
84
- if (calls.length === 0) {
85
- throw new Error(`No function calls needed to deploy contract ${this.artifact.name}`);
86
- }
87
84
  this.txRequest = await this.wallet.createTxExecutionRequest(await this.request(options));
88
85
  // TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined?
89
86
  await this.pxe.registerContract({ artifact: this.artifact, instance: this.instance! });
@@ -99,20 +96,21 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
99
96
  * @remarks This method does not have the same return type as the `request` in the ContractInteraction object,
100
97
  * it returns a promise for an array instead of a function call directly.
101
98
  */
102
- public async request(options: DeployOptions = {}): Promise<FunctionCall[]> {
99
+ public async request(options: DeployOptions = {}): Promise<ExecutionRequestInit> {
103
100
  if (!this.functionCalls) {
104
- const { address } = this.getInstance(options);
105
- const calls = await this.getDeploymentFunctionCalls(options);
106
- if (this.constructorArtifact && !options.skipInitialization) {
107
- const constructorCall = new ContractFunctionInteraction(
108
- this.wallet,
109
- address,
110
- this.constructorArtifact,
111
- this.args,
112
- );
113
- calls.push(constructorCall.request());
101
+ const deployment = await this.getDeploymentFunctionCalls(options);
102
+ const bootstrap = await this.getInitializeFunctionCalls(options);
103
+
104
+ if (deployment.calls.length + bootstrap.calls.length === 0) {
105
+ throw new Error(`No function calls needed to deploy contract ${this.artifact.name}`);
114
106
  }
115
- this.functionCalls = calls;
107
+
108
+ this.functionCalls = {
109
+ calls: [...deployment.calls, ...bootstrap.calls],
110
+ authWitnesses: [...(deployment.authWitnesses ?? []), ...(bootstrap.authWitnesses ?? [])],
111
+ packedArguments: [...(deployment.packedArguments ?? []), ...(bootstrap.packedArguments ?? [])],
112
+ fee: options.fee,
113
+ };
116
114
  }
117
115
  return this.functionCalls;
118
116
  }
@@ -122,7 +120,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
122
120
  * @param options - Deployment options.
123
121
  * @returns A function call array with potentially requests to the class registerer and instance deployer.
124
122
  */
125
- protected async getDeploymentFunctionCalls(options: DeployOptions = {}): Promise<FunctionCall[]> {
123
+ protected async getDeploymentFunctionCalls(options: DeployOptions = {}): Promise<ExecutionRequestInit> {
126
124
  const calls: FunctionCall[] = [];
127
125
 
128
126
  // Set contract instance object so it's available for populating the DeploySendTx object
@@ -140,11 +138,11 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
140
138
  // Register the contract class if it hasn't been published already.
141
139
  if (!options.skipClassRegistration) {
142
140
  if (await this.pxe.isContractClassPubliclyRegistered(contractClass.id)) {
143
- this.log(
141
+ this.log.debug(
144
142
  `Skipping registration of already registered contract class ${contractClass.id.toString()} for ${instance.address.toString()}`,
145
143
  );
146
144
  } else {
147
- this.log(
145
+ this.log.info(
148
146
  `Creating request for registering contract class ${contractClass.id.toString()} as part of deployment for ${instance.address.toString()}`,
149
147
  );
150
148
  calls.push((await registerContractClass(this.wallet, this.artifact)).request());
@@ -156,7 +154,31 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
156
154
  calls.push(deployInstance(this.wallet, instance).request());
157
155
  }
158
156
 
159
- return calls;
157
+ return {
158
+ calls,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Returns the calls necessary to initialize the contract.
164
+ * @param options - Deployment options.
165
+ * @returns - An array of function calls.
166
+ */
167
+ protected getInitializeFunctionCalls(options: DeployOptions): Promise<ExecutionRequestInit> {
168
+ const { address } = this.getInstance(options);
169
+ const calls: FunctionCall[] = [];
170
+ if (this.constructorArtifact && !options.skipInitialization) {
171
+ const constructorCall = new ContractFunctionInteraction(
172
+ this.wallet,
173
+ address,
174
+ this.constructorArtifact,
175
+ this.args,
176
+ );
177
+ calls.push(constructorCall.request());
178
+ }
179
+ return Promise.resolve({
180
+ calls,
181
+ });
160
182
  }
161
183
 
162
184
  /**
@@ -170,7 +192,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas
170
192
  public send(options: DeployOptions = {}): DeploySentTx<TContract> {
171
193
  const txHashPromise = super.send(options).getTxHash();
172
194
  const instance = this.getInstance(options);
173
- this.log(
195
+ this.log.debug(
174
196
  `Sent deployment tx of ${this.artifact.name} contract with deployment address ${instance.address.toString()}`,
175
197
  );
176
198
  return new DeploySentTx(this.pxe, txHashPromise, this.postDeployCtor, instance);
@@ -44,7 +44,7 @@ export class DeploySentTx<TContract extends Contract = Contract> extends SentTx
44
44
  */
45
45
  public async deployed(opts?: DeployedWaitOpts): Promise<TContract> {
46
46
  const receipt = await this.wait(opts);
47
- this.log(`Contract ${this.instance.address.toString()} successfully deployed.`);
47
+ this.log.info(`Contract ${this.instance.address.toString()} successfully deployed.`);
48
48
  return receipt.contract;
49
49
  }
50
50
 
@@ -1,7 +1,7 @@
1
- import { type FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types';
2
- import { TxContext } from '@aztec/circuits.js';
1
+ import { PackedValues, TxExecutionRequest } from '@aztec/circuit-types';
2
+ import { GasSettings, TxContext } from '@aztec/circuits.js';
3
3
 
4
- import { type EntrypointInterface } from './entrypoint.js';
4
+ import { type EntrypointInterface, type ExecutionRequestInit } from './entrypoint.js';
5
5
 
6
6
  /**
7
7
  * Default implementation of the entrypoint interface. It calls a function on a contract directly
@@ -9,18 +9,25 @@ import { type EntrypointInterface } from './entrypoint.js';
9
9
  export class DefaultEntrypoint implements EntrypointInterface {
10
10
  constructor(private chainId: number, private protocolVersion: number) {}
11
11
 
12
- createTxExecutionRequest(executions: FunctionCall[]): Promise<TxExecutionRequest> {
13
- const [execution] = executions;
14
- const packedArguments = PackedArguments.fromArgs(execution.args);
12
+ createTxExecutionRequest(exec: ExecutionRequestInit): Promise<TxExecutionRequest> {
13
+ const { calls, authWitnesses = [], packedArguments = [] } = exec;
14
+
15
+ if (calls.length > 1) {
16
+ throw new Error(`Expected a single call, got ${calls.length}`);
17
+ }
18
+
19
+ const call = calls[0];
20
+ const entrypointPackedValues = PackedValues.fromValues(call.args);
15
21
  const txContext = TxContext.empty(this.chainId, this.protocolVersion);
16
22
  return Promise.resolve(
17
23
  new TxExecutionRequest(
18
- execution.to,
19
- execution.functionData,
20
- packedArguments.hash,
24
+ call.to,
25
+ call.functionData,
26
+ entrypointPackedValues.hash,
21
27
  txContext,
22
- [packedArguments],
23
- [],
28
+ [...packedArguments, entrypointPackedValues],
29
+ authWitnesses,
30
+ exec.fee?.gasSettings ?? GasSettings.default(),
24
31
  ),
25
32
  );
26
33
  }
@@ -0,0 +1,89 @@
1
+ import { type EntrypointInterface, EntrypointPayload, type ExecutionRequestInit } from '@aztec/aztec.js/entrypoint';
2
+ import { PackedValues, TxExecutionRequest } from '@aztec/circuit-types';
3
+ import { type AztecAddress, FunctionData, GasSettings, TxContext } from '@aztec/circuits.js';
4
+ import { type FunctionAbi, encodeArguments } from '@aztec/foundation/abi';
5
+ import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint';
6
+
7
+ /**
8
+ * Implementation for an entrypoint interface that can execute multiple function calls in a single transaction
9
+ */
10
+ export class DefaultMultiCallEntrypoint implements EntrypointInterface {
11
+ constructor(
12
+ private chainId: number,
13
+ private version: number,
14
+ private address: AztecAddress = getCanonicalMultiCallEntrypointAddress(),
15
+ ) {}
16
+
17
+ createTxExecutionRequest(executions: ExecutionRequestInit): Promise<TxExecutionRequest> {
18
+ const { calls, authWitnesses = [], packedArguments = [] } = executions;
19
+ const payload = EntrypointPayload.fromAppExecution(calls);
20
+ const abi = this.getEntrypointAbi();
21
+ const entrypointPackedArgs = PackedValues.fromValues(encodeArguments(abi, [payload]));
22
+
23
+ const txRequest = TxExecutionRequest.from({
24
+ argsHash: entrypointPackedArgs.hash,
25
+ origin: this.address,
26
+ functionData: FunctionData.fromAbi(abi),
27
+ txContext: TxContext.empty(this.chainId, this.version),
28
+ packedArguments: [...payload.packedArguments, ...packedArguments, entrypointPackedArgs],
29
+ authWitnesses,
30
+ gasSettings: executions.fee?.gasSettings ?? GasSettings.default(),
31
+ });
32
+
33
+ return Promise.resolve(txRequest);
34
+ }
35
+
36
+ private getEntrypointAbi() {
37
+ return {
38
+ name: 'entrypoint',
39
+ isInitializer: false,
40
+ functionType: 'secret',
41
+ isInternal: false,
42
+ parameters: [
43
+ {
44
+ name: 'app_payload',
45
+ type: {
46
+ kind: 'struct',
47
+ path: 'authwit::entrypoint::app::AppPayload',
48
+ fields: [
49
+ {
50
+ name: 'function_calls',
51
+ type: {
52
+ kind: 'array',
53
+ length: 4,
54
+ type: {
55
+ kind: 'struct',
56
+ path: 'authwit::entrypoint::function_call::FunctionCall',
57
+ fields: [
58
+ { name: 'args_hash', type: { kind: 'field' } },
59
+ {
60
+ name: 'function_selector',
61
+ type: {
62
+ kind: 'struct',
63
+ path: 'authwit::aztec::protocol_types::abis::function_selector::FunctionSelector',
64
+ fields: [{ name: 'inner', type: { kind: 'integer', sign: 'unsigned', width: 32 } }],
65
+ },
66
+ },
67
+ {
68
+ name: 'target_address',
69
+ type: {
70
+ kind: 'struct',
71
+ path: 'authwit::aztec::protocol_types::address::AztecAddress',
72
+ fields: [{ name: 'inner', type: { kind: 'field' } }],
73
+ },
74
+ },
75
+ { name: 'is_public', type: { kind: 'boolean' } },
76
+ ],
77
+ },
78
+ },
79
+ },
80
+ { name: 'nonce', type: { kind: 'field' } },
81
+ ],
82
+ },
83
+ visibility: 'public',
84
+ },
85
+ ],
86
+ returnTypes: [],
87
+ } as FunctionAbi;
88
+ }
89
+ }
@@ -1,25 +1,30 @@
1
- import { type FunctionCall, type TxExecutionRequest } from '@aztec/circuit-types';
2
- import { type Fr } from '@aztec/foundation/fields';
1
+ import { type AuthWitness, type FunctionCall, type PackedValues, type TxExecutionRequest } from '@aztec/circuit-types';
3
2
 
4
- import { type FeePaymentMethod } from '../fee/fee_payment_method.js';
3
+ import { EntrypointPayload, type FeeOptions } from './payload.js';
5
4
 
6
- /**
7
- * Fee payment options for a transaction.
8
- */
9
- export type FeeOptions = {
10
- /** The fee payment method to use */
11
- paymentMethod: FeePaymentMethod;
12
- /** The fee limit to pay */
13
- maxFee: bigint | number | Fr;
5
+ export { EntrypointPayload, FeeOptions };
6
+
7
+ export { DefaultEntrypoint } from './default_entrypoint.js';
8
+ export { DefaultMultiCallEntrypoint } from './default_multi_call_entrypoint.js';
9
+
10
+ /** Encodes the calls to be done in a transaction. */
11
+ export type ExecutionRequestInit = {
12
+ /** The function calls to be executed. */
13
+ calls: FunctionCall[];
14
+ /** Any transient auth witnesses needed for this execution */
15
+ authWitnesses?: AuthWitness[];
16
+ /** Any transient packed arguments for this execution */
17
+ packedArguments?: PackedValues[];
18
+ /** How the fee is going to be payed */
19
+ fee?: FeeOptions;
14
20
  };
15
21
 
16
22
  /** Creates transaction execution requests out of a set of function calls. */
17
23
  export interface EntrypointInterface {
18
24
  /**
19
25
  * Generates an execution request out of set of function calls.
20
- * @param executions - The execution intents to be run.
21
- * @param feeOpts - The fee to be paid for the transaction.
26
+ * @param execution - The execution intents to be run.
22
27
  * @returns The authenticated transaction execution request.
23
28
  */
24
- createTxExecutionRequest(executions: FunctionCall[], feeOpts?: FeeOptions): Promise<TxExecutionRequest>;
29
+ createTxExecutionRequest(execution: ExecutionRequestInit): Promise<TxExecutionRequest>;
25
30
  }
@@ -0,0 +1,144 @@
1
+ import { type FunctionCall, PackedValues, emptyFunctionCall } from '@aztec/circuit-types';
2
+ import { Fr, type GasSettings, GeneratorIndex } from '@aztec/circuits.js';
3
+ import { padArrayEnd } from '@aztec/foundation/collection';
4
+ import { pedersenHash } from '@aztec/foundation/crypto';
5
+ import { type Tuple } from '@aztec/foundation/serialize';
6
+
7
+ import { type FeePaymentMethod } from '../fee/fee_payment_method.js';
8
+
9
+ /**
10
+ * Fee payment options for a transaction.
11
+ */
12
+ export type FeeOptions = {
13
+ /** The fee payment method to use */
14
+ paymentMethod: FeePaymentMethod;
15
+ /** The gas settings */
16
+ gasSettings: GasSettings;
17
+ };
18
+
19
+ // These must match the values defined in:
20
+ // - noir-projects/aztec-nr/aztec/src/entrypoint/app.nr
21
+ const APP_MAX_CALLS = 4;
22
+ // - and noir-projects/aztec-nr/aztec/src/entrypoint/fee.nr
23
+ const FEE_MAX_CALLS = 2;
24
+
25
+ /* eslint-disable camelcase */
26
+ /** Encoded function call for account contract entrypoint */
27
+ type EncodedFunctionCall = {
28
+ /** Arguments hash for the call */
29
+ args_hash: Fr;
30
+ /** Selector of the function to call */
31
+ function_selector: Fr;
32
+ /** Address of the contract to call */
33
+ target_address: Fr;
34
+ /** Whether the function is public or private */
35
+ is_public: boolean;
36
+ };
37
+ /* eslint-enable camelcase */
38
+
39
+ /** Assembles an entrypoint payload */
40
+ export class EntrypointPayload {
41
+ #packedArguments: PackedValues[] = [];
42
+ #functionCalls: EncodedFunctionCall[] = [];
43
+ #nonce = Fr.random();
44
+ #generatorIndex: number;
45
+
46
+ private constructor(functionCalls: FunctionCall[], generatorIndex: number) {
47
+ for (const call of functionCalls) {
48
+ this.#packedArguments.push(PackedValues.fromValues(call.args));
49
+ }
50
+
51
+ /* eslint-disable camelcase */
52
+ this.#functionCalls = functionCalls.map((call, index) => ({
53
+ args_hash: this.#packedArguments[index].hash,
54
+ function_selector: call.functionData.selector.toField(),
55
+ target_address: call.to.toField(),
56
+ is_public: !call.functionData.isPrivate,
57
+ }));
58
+ /* eslint-enable camelcase */
59
+
60
+ this.#generatorIndex = generatorIndex;
61
+ }
62
+
63
+ /* eslint-disable camelcase */
64
+ /**
65
+ * The function calls to execute. This uses snake_case naming so that it is compatible with Noir encoding
66
+ * @internal
67
+ */
68
+ get function_calls() {
69
+ return this.#functionCalls;
70
+ }
71
+ /* eslint-enable camelcase */
72
+
73
+ /**
74
+ * The nonce
75
+ * @internal
76
+ */
77
+ get nonce() {
78
+ return this.#nonce;
79
+ }
80
+
81
+ /**
82
+ * The packed arguments for the function calls
83
+ */
84
+ get packedArguments() {
85
+ return this.#packedArguments;
86
+ }
87
+
88
+ /**
89
+ * Serializes the payload to an array of fields
90
+ * @returns The fields of the payload
91
+ */
92
+ toFields(): Fr[] {
93
+ return [
94
+ ...this.#functionCalls.flatMap(call => [
95
+ call.args_hash,
96
+ call.function_selector,
97
+ call.target_address,
98
+ new Fr(call.is_public),
99
+ ]),
100
+ this.#nonce,
101
+ ];
102
+ }
103
+
104
+ /**
105
+ * Hashes the payload
106
+ * @returns The hash of the payload
107
+ */
108
+ hash() {
109
+ return pedersenHash(this.toFields(), this.#generatorIndex);
110
+ }
111
+
112
+ /**
113
+ * Creates an execution payload from a set of function calls
114
+ * @param functionCalls - The function calls to execute
115
+ * @returns The execution payload
116
+ */
117
+ static fromFunctionCalls(functionCalls: FunctionCall[]) {
118
+ return new EntrypointPayload(functionCalls, 0);
119
+ }
120
+
121
+ /**
122
+ * Creates an execution payload for the app-portion of a transaction from a set of function calls
123
+ * @param functionCalls - The function calls to execute
124
+ * @returns The execution payload
125
+ */
126
+ static fromAppExecution(functionCalls: FunctionCall[] | Tuple<FunctionCall, 4>) {
127
+ if (functionCalls.length > APP_MAX_CALLS) {
128
+ throw new Error(`Expected at most ${APP_MAX_CALLS} function calls, got ${functionCalls.length}`);
129
+ }
130
+ const paddedCalls = padArrayEnd(functionCalls, emptyFunctionCall(), APP_MAX_CALLS);
131
+ return new EntrypointPayload(paddedCalls, GeneratorIndex.SIGNATURE_PAYLOAD);
132
+ }
133
+
134
+ /**
135
+ * Creates an execution payload to pay the fee for a transaction
136
+ * @param feeOpts - The fee payment options
137
+ * @returns The execution payload
138
+ */
139
+ static async fromFeeOptions(feeOpts?: FeeOptions) {
140
+ const calls = feeOpts ? await feeOpts.paymentMethod.getFunctionCalls(feeOpts?.gasSettings) : [];
141
+ const paddedCalls = padArrayEnd(calls, emptyFunctionCall(), FEE_MAX_CALLS);
142
+ return new EntrypointPayload(paddedCalls, GeneratorIndex.FEE_PAYLOAD);
143
+ }
144
+ }