@aztec/aztec.js 0.1.0-alpha23 → 0.1.0-alpha25

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 (82) hide show
  1. package/.tsbuildinfo +1 -1
  2. package/dest/abis/ecdsa_account_contract.json +150 -0
  3. package/dest/abis/schnorr_account_contract.json +96 -0
  4. package/dest/abis/schnorr_single_key_account_contract.json +96 -0
  5. package/dest/account_impl/account_collection.d.ts.map +1 -1
  6. package/dest/account_impl/account_collection.js +1 -1
  7. package/dest/account_impl/entrypoint_payload.d.ts +26 -0
  8. package/dest/account_impl/entrypoint_payload.d.ts.map +1 -0
  9. package/dest/account_impl/entrypoint_payload.js +46 -0
  10. package/dest/account_impl/index.d.ts +2 -1
  11. package/dest/account_impl/index.d.ts.map +1 -1
  12. package/dest/account_impl/index.js +3 -2
  13. package/dest/account_impl/single_key_account_contract.d.ts +23 -0
  14. package/dest/account_impl/single_key_account_contract.d.ts.map +1 -0
  15. package/dest/account_impl/single_key_account_contract.js +66 -0
  16. package/dest/account_impl/stored_key_account_contract.d.ts +22 -0
  17. package/dest/account_impl/stored_key_account_contract.d.ts.map +1 -0
  18. package/dest/account_impl/stored_key_account_contract.js +65 -0
  19. package/dest/aztec_rpc_client/aztec_rpc_client.d.ts +2 -1
  20. package/dest/aztec_rpc_client/aztec_rpc_client.d.ts.map +1 -1
  21. package/dest/aztec_rpc_client/aztec_rpc_client.js +5 -5
  22. package/dest/aztec_rpc_client/wallet.d.ts +8 -6
  23. package/dest/aztec_rpc_client/wallet.d.ts.map +1 -1
  24. package/dest/aztec_rpc_client/wallet.js +19 -10
  25. package/dest/contract/contract.d.ts +3 -4
  26. package/dest/contract/contract.d.ts.map +1 -1
  27. package/dest/contract/contract.js +1 -1
  28. package/dest/contract/contract.test.js +3 -3
  29. package/dest/contract/contract_function_interaction.d.ts +1 -1
  30. package/dest/contract/contract_function_interaction.d.ts.map +1 -1
  31. package/dest/contract/contract_function_interaction.js +6 -6
  32. package/dest/contract_deployer/contract_deployer.d.ts.map +1 -1
  33. package/dest/contract_deployer/contract_deployer.js +2 -1
  34. package/dest/contract_deployer/contract_deployer.test.js +3 -3
  35. package/dest/contract_deployer/deploy_method.d.ts.map +1 -1
  36. package/dest/contract_deployer/deploy_method.js +5 -13
  37. package/dest/index.d.ts +1 -1
  38. package/dest/index.d.ts.map +1 -1
  39. package/dest/index.js +2 -2
  40. package/dest/utils/account.d.ts +3 -2
  41. package/dest/utils/account.d.ts.map +1 -1
  42. package/dest/utils/account.js +13 -17
  43. package/dest/utils/l1_contracts.d.ts +8 -0
  44. package/dest/utils/l1_contracts.d.ts.map +1 -1
  45. package/dest/utils/l1_contracts.js +10 -2
  46. package/package.json +4 -5
  47. package/src/abis/ecdsa_account_contract.json +150 -0
  48. package/src/abis/schnorr_account_contract.json +96 -0
  49. package/src/abis/schnorr_single_key_account_contract.json +96 -0
  50. package/src/account_impl/account_collection.ts +1 -0
  51. package/src/account_impl/entrypoint_payload.ts +76 -0
  52. package/src/account_impl/index.ts +2 -1
  53. package/src/account_impl/single_key_account_contract.ts +82 -0
  54. package/src/account_impl/stored_key_account_contract.ts +80 -0
  55. package/src/aztec_rpc_client/aztec_rpc_client.ts +6 -4
  56. package/src/aztec_rpc_client/wallet.ts +22 -15
  57. package/src/contract/contract.test.ts +5 -3
  58. package/src/contract/contract.ts +4 -3
  59. package/src/contract/contract_function_interaction.ts +4 -4
  60. package/src/contract_deployer/contract_deployer.test.ts +4 -3
  61. package/src/contract_deployer/contract_deployer.ts +1 -0
  62. package/src/contract_deployer/deploy_method.ts +5 -17
  63. package/src/index.ts +1 -1
  64. package/src/utils/account.ts +19 -35
  65. package/src/utils/l1_contracts.ts +21 -1
  66. package/tsconfig.json +1 -4
  67. package/dest/account_impl/account_contract.d.ts +0 -44
  68. package/dest/account_impl/account_contract.d.ts.map +0 -1
  69. package/dest/account_impl/account_contract.js +0 -107
  70. package/dest/auth/ecdsa.d.ts +0 -13
  71. package/dest/auth/ecdsa.d.ts.map +0 -1
  72. package/dest/auth/ecdsa.js +0 -17
  73. package/dest/auth/index.d.ts +0 -19
  74. package/dest/auth/index.d.ts.map +0 -1
  75. package/dest/auth/index.js +0 -14
  76. package/dest/auth/schnorr.d.ts +0 -13
  77. package/dest/auth/schnorr.d.ts.map +0 -1
  78. package/dest/auth/schnorr.js +0 -14
  79. package/src/account_impl/account_contract.ts +0 -171
  80. package/src/auth/ecdsa.ts +0 -18
  81. package/src/auth/index.ts +0 -25
  82. package/src/auth/schnorr.ts +0 -14
@@ -0,0 +1,80 @@
1
+ import { AztecAddress, CircuitsWasm, FunctionData, TxContext } from '@aztec/circuits.js';
2
+ import { Signer } from '@aztec/circuits.js/barretenberg';
3
+ import { ContractAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
4
+ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
5
+ import { ExecutionRequest, PackedArguments, TxExecutionRequest } from '@aztec/types';
6
+
7
+ import partition from 'lodash.partition';
8
+
9
+ import EcdsaAccountContractAbi from '../abis/ecdsa_account_contract.json' assert { type: 'json' };
10
+ import { buildPayload, hashPayload } from './entrypoint_payload.js';
11
+ import { AccountImplementation } from './index.js';
12
+
13
+ /**
14
+ * Account contract implementation that keeps a signing public key in storage, and is retrieved on
15
+ * every new request in order to validate the payload signature.
16
+ */
17
+ export class StoredKeyAccountContract implements AccountImplementation {
18
+ private log: DebugLogger;
19
+
20
+ constructor(private address: AztecAddress, private privateKey: Buffer, private signer: Signer) {
21
+ this.log = createDebugLogger('aztec:client:accounts:stored_key');
22
+ }
23
+
24
+ getAddress(): AztecAddress {
25
+ return this.address;
26
+ }
27
+
28
+ async createAuthenticatedTxRequest(
29
+ executions: ExecutionRequest[],
30
+ txContext: TxContext,
31
+ ): Promise<TxExecutionRequest> {
32
+ this.checkSender(executions);
33
+ this.checkIsNotDeployment(txContext);
34
+
35
+ const [privateCalls, publicCalls] = partition(executions, exec => exec.functionData.isPrivate);
36
+ const wasm = await CircuitsWasm.get();
37
+ const { payload, packedArguments: callsPackedArguments } = await buildPayload(privateCalls, publicCalls);
38
+ const hash = hashPayload(payload);
39
+ const signature = this.signer.constructSignature(hash, this.privateKey).toBuffer();
40
+ this.log(`Signed challenge ${hash.toString('hex')} as ${signature.toString('hex')}`);
41
+
42
+ const args = [payload, signature];
43
+ const abi = this.getEntrypointAbi();
44
+ const selector = generateFunctionSelector(abi.name, abi.parameters);
45
+ const packedArgs = await PackedArguments.fromArgs(encodeArguments(abi, args), wasm);
46
+ const txRequest = TxExecutionRequest.from({
47
+ argsHash: packedArgs.hash,
48
+ origin: this.address,
49
+ functionData: new FunctionData(selector, true, false),
50
+ txContext,
51
+ packedArguments: [...callsPackedArguments, packedArgs],
52
+ });
53
+
54
+ return txRequest;
55
+ }
56
+
57
+ private getEntrypointAbi() {
58
+ // We use the EcdsaAccountContractAbi because it implements the interface we need, but ideally
59
+ // we should have an interface that defines the entrypoint for StoredKeyAccountContracts and
60
+ // load the abi from it.
61
+ const abi = (EcdsaAccountContractAbi as any as ContractAbi).functions.find(f => f.name === 'entrypoint');
62
+ if (!abi) throw new Error(`Entrypoint abi for account contract not found`);
63
+ return abi;
64
+ }
65
+
66
+ private checkIsNotDeployment(txContext: TxContext) {
67
+ if (txContext.isContractDeploymentTx) {
68
+ throw new Error(`Cannot yet deploy contracts from an account contract`);
69
+ }
70
+ }
71
+
72
+ private checkSender(executions: ExecutionRequest[]) {
73
+ const wrongSender = executions.find(e => !e.from.equals(this.address));
74
+ if (wrongSender) {
75
+ throw new Error(
76
+ `Sender ${wrongSender.from.toString()} does not match account address ${this.address.toString()}`,
77
+ );
78
+ }
79
+ }
80
+ }
@@ -1,16 +1,17 @@
1
1
  import { AztecAddress, EthAddress, Fr, Point } from '@aztec/circuits.js';
2
- import { createJsonRpcClient } from '@aztec/foundation/json-rpc';
2
+ import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc';
3
3
  import {
4
4
  AztecRPC,
5
5
  ContractData,
6
6
  ContractDeploymentTx,
7
7
  ContractPublicData,
8
+ Tx,
8
9
  TxExecutionRequest,
9
10
  TxHash,
10
- Tx,
11
+ TxReceipt,
11
12
  } from '@aztec/types';
12
13
 
13
- export const createAztecRpcClient = (url: string): AztecRPC =>
14
+ export const createAztecRpcClient = (url: string, fetch = defaultFetch): AztecRPC =>
14
15
  createJsonRpcClient<AztecRPC>(
15
16
  url,
16
17
  {
@@ -23,6 +24,7 @@ export const createAztecRpcClient = (url: string): AztecRPC =>
23
24
  Point,
24
25
  Fr,
25
26
  },
26
- { Tx, ContractDeploymentTx },
27
+ { Tx, ContractDeploymentTx, TxReceipt },
27
28
  false,
29
+ fetch,
28
30
  );
@@ -1,5 +1,4 @@
1
- import { AztecAddress, Fr, Point, TxContext } from '@aztec/circuits.js';
2
- import { ContractAbi } from '@aztec/foundation/abi';
1
+ import { AztecAddress, Fr, PartialContractAddress, Point, PublicKey, TxContext } from '@aztec/circuits.js';
3
2
  import {
4
3
  AztecRPC,
5
4
  ContractData,
@@ -31,22 +30,21 @@ export abstract class BaseWallet implements Wallet {
31
30
  executions: ExecutionRequest[],
32
31
  txContext: TxContext,
33
32
  ): Promise<TxExecutionRequest>;
34
- addAccount(
35
- privKey: Buffer,
33
+ addAccount(privKey: Buffer, address: AztecAddress, partialContractAddress: Fr): Promise<AztecAddress> {
34
+ return this.rpc.addAccount(privKey, address, partialContractAddress);
35
+ }
36
+ addPublicKeyAndPartialAddress(
36
37
  address: AztecAddress,
37
- partialContractAddress: Fr,
38
- abi?: ContractAbi | undefined,
39
- ): Promise<AztecAddress> {
40
- return this.rpc.addAccount(privKey, address, partialContractAddress, abi);
38
+ publicKey: PublicKey,
39
+ partialAddress: PartialContractAddress,
40
+ ): Promise<void> {
41
+ return this.rpc.addPublicKeyAndPartialAddress(address, publicKey, partialAddress);
41
42
  }
42
43
  getAccounts(): Promise<AztecAddress[]> {
43
44
  return this.rpc.getAccounts();
44
45
  }
45
- getAccountPublicKey(address: AztecAddress): Promise<Point> {
46
- return this.rpc.getAccountPublicKey(address);
47
- }
48
- getAccountAddress(publicKey: Point): Promise<AztecAddress> {
49
- return this.rpc.getAccountAddress(publicKey);
46
+ getPublicKey(address: AztecAddress): Promise<Point> {
47
+ return this.rpc.getPublicKey(address);
50
48
  }
51
49
  addContracts(contracts: DeployedContract[]): Promise<void> {
52
50
  return this.rpc.addContracts(contracts);
@@ -54,8 +52,8 @@ export abstract class BaseWallet implements Wallet {
54
52
  isContractDeployed(contract: AztecAddress): Promise<boolean> {
55
53
  return this.rpc.isContractDeployed(contract);
56
54
  }
57
- simulateTx(txRequest: TxExecutionRequest, optionalFromAddress?: AztecAddress | undefined): Promise<Tx> {
58
- return this.rpc.simulateTx(txRequest, optionalFromAddress);
55
+ simulateTx(txRequest: TxExecutionRequest): Promise<Tx> {
56
+ return this.rpc.simulateTx(txRequest);
59
57
  }
60
58
  sendTx(tx: Tx): Promise<TxHash> {
61
59
  return this.rpc.sendTx(tx);
@@ -66,6 +64,9 @@ export abstract class BaseWallet implements Wallet {
66
64
  getStorageAt(contract: AztecAddress, storageSlot: Fr): Promise<any> {
67
65
  return this.rpc.getStorageAt(contract, storageSlot);
68
66
  }
67
+ getPublicStorageAt(contract: AztecAddress, storageSlot: Fr): Promise<any> {
68
+ return this.rpc.getPublicStorageAt(contract, storageSlot);
69
+ }
69
70
  viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise<any> {
70
71
  return this.rpc.viewTx(functionName, args, to, from);
71
72
  }
@@ -84,6 +85,12 @@ export abstract class BaseWallet implements Wallet {
84
85
  getNodeInfo(): Promise<NodeInfo> {
85
86
  return this.rpc.getNodeInfo();
86
87
  }
88
+ getPublicKeyAndPartialAddress(address: AztecAddress): Promise<[Point, PartialContractAddress]> {
89
+ return this.rpc.getPublicKeyAndPartialAddress(address);
90
+ }
91
+ isAccountSynchronised(account: AztecAddress) {
92
+ return this.rpc.isAccountSynchronised(account);
93
+ }
87
94
  }
88
95
 
89
96
  /**
@@ -1,11 +1,13 @@
1
- import { MockProxy, mock } from 'jest-mock-extended';
2
- import { DeployedContract, NodeInfo, Tx, TxHash, TxReceipt } from '@aztec/types';
1
+ import { AztecAddress, EthAddress } from '@aztec/circuits.js';
3
2
  import { ABIParameterVisibility, ContractAbi, FunctionType } from '@aztec/foundation/abi';
4
3
  import { randomBytes } from '@aztec/foundation/crypto';
4
+ import { DeployedContract, NodeInfo, Tx, TxHash, TxReceipt } from '@aztec/types';
5
5
  import { TxExecutionRequest } from '@aztec/types';
6
+
7
+ import { MockProxy, mock } from 'jest-mock-extended';
8
+
6
9
  import { Wallet } from '../aztec_rpc_client/wallet.js';
7
10
  import { Contract } from './contract.js';
8
- import { AztecAddress, EthAddress } from '@aztec/circuits.js';
9
11
 
10
12
  describe('Contract Class', () => {
11
13
  let wallet: MockProxy<Wallet>;
@@ -1,15 +1,16 @@
1
1
  import { ContractAbi, FunctionAbi, generateFunctionSelector } from '@aztec/foundation/abi';
2
2
  import { AztecAddress } from '@aztec/foundation/aztec-address';
3
3
  import { EthAddress } from '@aztec/foundation/eth-address';
4
+ import { DeployedContract } from '@aztec/types';
5
+
4
6
  import { Wallet } from '../aztec_rpc_client/wallet.js';
5
7
  import { ContractFunctionInteraction } from './contract_function_interaction.js';
6
- import { DeployedContract } from '@aztec/types';
7
8
 
8
9
  /**
9
10
  * Type representing a contract method that returns a ContractFunctionInteraction instance
10
11
  * and has a readonly 'selector' property of type Buffer. Takes any number of arguments.
11
12
  */
12
- type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & {
13
+ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & {
13
14
  /**
14
15
  * The unique identifier for a contract function in bytecode.
15
16
  */
@@ -41,7 +42,7 @@ export class Contract {
41
42
  /**
42
43
  * The wallet.
43
44
  */
44
- private wallet: Wallet,
45
+ protected wallet: Wallet,
45
46
  ) {
46
47
  abi.functions.forEach((f: FunctionAbi) => {
47
48
  const interactionFunction = (...args: any[]) => {
@@ -74,15 +74,15 @@ export class ContractFunctionInteraction {
74
74
  * @param options - optional arguments to be used in the creation of the transaction
75
75
  * @returns The resulting transaction
76
76
  */
77
- public async simulate(options: SendMethodOptions): Promise<Tx> {
77
+ public async simulate(options: SendMethodOptions = {}): Promise<Tx> {
78
78
  const txRequest = this.txRequest ?? (await this.create(options));
79
- // TODO: Why do we need from separately, and cannot get it from txRequest.origin? When would they differ?
80
- this.tx = await this.wallet.simulateTx(txRequest, txRequest.origin);
79
+ this.tx = await this.wallet.simulateTx(txRequest);
81
80
  return this.tx;
82
81
  }
83
82
 
84
83
  protected getExecutionRequest(to: AztecAddress, from?: AztecAddress): ExecutionRequest {
85
84
  const flatArgs = encodeArguments(this.functionDao, this.args);
85
+ from = from ?? this.wallet.getAddress();
86
86
 
87
87
  const functionData = new FunctionData(
88
88
  generateFunctionSelector(this.functionDao.name, this.functionDao.parameters),
@@ -94,7 +94,7 @@ export class ContractFunctionInteraction {
94
94
  args: flatArgs,
95
95
  functionData,
96
96
  to,
97
- from: from || AztecAddress.ZERO,
97
+ from,
98
98
  };
99
99
  }
100
100
 
@@ -1,8 +1,9 @@
1
- import { randomBytes } from 'crypto';
2
- import { MockProxy, mock } from 'jest-mock-extended';
3
1
  import { AztecAddress, EthAddress, Fr, Point } from '@aztec/circuits.js';
4
2
  import { ContractAbi, FunctionType } from '@aztec/foundation/abi';
5
- import { AztecRPC, Tx, TxHash, TxReceipt, PublicKey } from '@aztec/types';
3
+ import { AztecRPC, PublicKey, Tx, TxHash, TxReceipt } from '@aztec/types';
4
+
5
+ import { randomBytes } from 'crypto';
6
+ import { MockProxy, mock } from 'jest-mock-extended';
6
7
 
7
8
  import { ContractDeployer } from './contract_deployer.js';
8
9
 
@@ -8,6 +8,7 @@ import { DeployMethod } from './deploy_method.js';
8
8
  * A class for deploying contract.
9
9
  */
10
10
  export class ContractDeployer {
11
+ // TODO: remove this?
11
12
  constructor(private abi: ContractAbi, private arc: AztecRPC, private publicKey?: PublicKey) {}
12
13
 
13
14
  /**
@@ -86,10 +86,10 @@ export class DeployMethod extends ContractFunctionInteraction {
86
86
  * @returns A Promise resolving to an object containing the signed transaction data and other relevant information.
87
87
  */
88
88
  public async create(options: DeployOptions = {}) {
89
- const { portalContract, contractAddressSalt } = Object.assign(
90
- { portalContract: EthAddress.ZERO, contractAddressSalt: Fr.random() },
91
- options,
92
- );
89
+ const portalContract = options.portalContract ?? EthAddress.ZERO;
90
+ const contractAddressSalt = options.contractAddressSalt ?? Fr.random();
91
+
92
+ const { chainId, version } = await this.wallet.getNodeInfo();
93
93
 
94
94
  const { address, constructorHash, functionTreeRoot, partialAddress } = await getContractDeploymentInfo(
95
95
  this.abi,
@@ -106,8 +106,6 @@ export class DeployMethod extends ContractFunctionInteraction {
106
106
  portalContract,
107
107
  );
108
108
 
109
- const { chainId, version } = await this.wallet.getNodeInfo();
110
-
111
109
  const txContext = new TxContext(false, false, true, contractDeploymentData, new Fr(chainId), new Fr(version));
112
110
  const executionRequest = this.getExecutionRequest(address, AztecAddress.ZERO);
113
111
  const txRequest = await this.wallet.createAuthenticatedTxRequest([executionRequest], txContext);
@@ -142,17 +140,7 @@ export class DeployMethod extends ContractFunctionInteraction {
142
140
  public async simulate(options: DeployOptions): Promise<Tx> {
143
141
  const txRequest = this.txRequest ?? (await this.create(options));
144
142
 
145
- // We need to tell the rpc server which account state to use to simulate
146
- // the tx. In the context of a deployment, we need to use an account state
147
- // that matches the account contract being deployed. But if what we deploy is
148
- // an "application" contract, then there's no account state associated with it,
149
- // so we just let the rpc server use whichever it wants. This is an accident
150
- // of all simulations happening over an account state, which should not be necessary.
151
- const rpcServerRegisteredAccounts = await this.wallet.getAccounts();
152
- const deploymentAddress = this.completeContractAddress!;
153
- const accountStateAddress = rpcServerRegisteredAccounts.includes(deploymentAddress) ? deploymentAddress : undefined;
154
-
155
- this.tx = await this.wallet.simulateTx(txRequest, accountStateAddress);
143
+ this.tx = await this.wallet.simulateTx(txRequest);
156
144
  return this.tx;
157
145
  }
158
146
 
package/src/index.ts CHANGED
@@ -2,8 +2,8 @@ export * from './contract/index.js';
2
2
  export * from './contract_deployer/index.js';
3
3
  export * from './utils/index.js';
4
4
  export * from './aztec_rpc_client/index.js';
5
- export * from './auth/index.js';
6
5
  export * from './account_impl/index.js';
6
+ export * from './contract_deployer/deploy_method.js';
7
7
 
8
8
  // TODO - only export necessary stuffs
9
9
  // export * from '@aztec/aztec-rpc';
@@ -1,18 +1,12 @@
1
- import { CircuitsWasm, Fr, getContractDeploymentInfo } from '@aztec/circuits.js';
1
+ import { Fr, getContractDeploymentInfo } from '@aztec/circuits.js';
2
+ import { Schnorr } from '@aztec/circuits.js/barretenberg';
3
+ import { ContractAbi } from '@aztec/foundation/abi';
2
4
  import { randomBytes } from '@aztec/foundation/crypto';
3
5
  import { createDebugLogger } from '@aztec/foundation/log';
4
6
  import { AztecRPC, TxStatus } from '@aztec/types';
5
- import { SchnorrAccountContractAbi } from '@aztec/noir-contracts/examples';
6
- import { Schnorr } from '@aztec/circuits.js/barretenberg';
7
7
 
8
8
  import { AccountWallet, Wallet } from '../aztec_rpc_client/wallet.js';
9
- import {
10
- AccountCollection,
11
- AccountContract,
12
- ContractDeployer,
13
- SchnorrAuthProvider,
14
- generatePublicKey,
15
- } from '../index.js';
9
+ import { AccountCollection, ContractDeployer, SingleKeyAccountContract, generatePublicKey } from '../index.js';
16
10
 
17
11
  /**
18
12
  * Creates an Aztec Account.
@@ -20,21 +14,21 @@ import {
20
14
  */
21
15
  export async function createAccounts(
22
16
  aztecRpcClient: AztecRPC,
17
+ accountContractAbi: ContractAbi,
23
18
  privateKey?: Buffer,
24
19
  salt = Fr.random(),
25
20
  numberOfAccounts = 1,
26
21
  logger = createDebugLogger('aztec:aztec.js:accounts'),
27
22
  ): Promise<Wallet> {
28
- const accountAbi = SchnorrAccountContractAbi;
29
23
  const accountImpls = new AccountCollection();
30
- const wasm = await CircuitsWasm.get();
24
+
31
25
  for (let i = 0; i < numberOfAccounts; ++i) {
32
26
  // TODO(#662): Let the aztec rpc server generate the keypair rather than hardcoding the private key
33
27
  const privKey = i == 0 && privateKey ? privateKey : randomBytes(32);
34
28
  const publicKey = await generatePublicKey(privKey);
35
- const deploymentInfo = await getContractDeploymentInfo(accountAbi, [], salt, publicKey);
36
- await aztecRpcClient.addAccount(privKey, deploymentInfo.address, deploymentInfo.partialAddress, accountAbi);
37
- const contractDeployer = new ContractDeployer(accountAbi, aztecRpcClient, publicKey);
29
+ const deploymentInfo = await getContractDeploymentInfo(accountContractAbi, [], salt, publicKey);
30
+ await aztecRpcClient.addAccount(privKey, deploymentInfo.address, deploymentInfo.partialAddress);
31
+ const contractDeployer = new ContractDeployer(accountContractAbi, aztecRpcClient, publicKey);
38
32
  const tx = contractDeployer.deploy().send({ contractAddressSalt: salt });
39
33
  await tx.isMined(0, 0.5);
40
34
  const receipt = await tx.getReceipt();
@@ -50,14 +44,7 @@ export async function createAccounts(
50
44
  logger(`Created account ${address.toString()} with public key ${publicKey.toString()}`);
51
45
  accountImpls.registerAccount(
52
46
  address,
53
- new AccountContract(
54
- address,
55
- publicKey,
56
- new SchnorrAuthProvider(await Schnorr.new(), privKey),
57
- deploymentInfo.partialAddress,
58
- accountAbi,
59
- wasm,
60
- ),
47
+ new SingleKeyAccountContract(address, deploymentInfo.partialAddress, privKey, await Schnorr.new()),
61
48
  );
62
49
  }
63
50
  return new AccountWallet(aztecRpcClient, accountImpls);
@@ -69,23 +56,20 @@ export async function createAccounts(
69
56
  * @param numberOfAccounts - The number of accounts to fetch.
70
57
  * @returns An AccountWallet implementation that includes all the accounts found.
71
58
  */
72
- export async function getAccountWallet(aztecRpcClient: AztecRPC, privateKey: Buffer, salt: Fr) {
73
- const wasm = await CircuitsWasm.get();
59
+ export async function getAccountWallet(
60
+ aztecRpcClient: AztecRPC,
61
+ accountContractAbi: ContractAbi,
62
+ privateKey: Buffer,
63
+ salt: Fr,
64
+ ) {
74
65
  const accountCollection = new AccountCollection();
75
66
  const publicKey = await generatePublicKey(privateKey);
76
- const address = await aztecRpcClient.getAccountAddress(publicKey);
77
- const deploymentInfo = await getContractDeploymentInfo(SchnorrAccountContractAbi, [], salt, publicKey);
67
+ const deploymentInfo = await getContractDeploymentInfo(accountContractAbi, [], salt, publicKey);
68
+ const address = deploymentInfo.address;
78
69
 
79
70
  accountCollection.registerAccount(
80
71
  address,
81
- new AccountContract(
82
- address,
83
- publicKey,
84
- new SchnorrAuthProvider(await Schnorr.new(), privateKey),
85
- deploymentInfo.partialAddress,
86
- SchnorrAccountContractAbi,
87
- wasm,
88
- ),
72
+ new SingleKeyAccountContract(address, deploymentInfo.partialAddress, privateKey, await Schnorr.new()),
89
73
  );
90
74
  return new AccountWallet(aztecRpcClient, accountCollection);
91
75
  }
@@ -1,4 +1,5 @@
1
1
  import { EthAddress } from '@aztec/circuits.js';
2
+ import { retryUntil } from '@aztec/foundation/retry';
2
3
 
3
4
  /**
4
5
  * A dictionary of the Aztec-deployed L1 contracts.
@@ -16,6 +17,14 @@ export type L1ContractAddresses = {
16
17
  * Address of the L1/L2 messaging inbox contract.
17
18
  */
18
19
  inbox: EthAddress;
20
+ /**
21
+ * Address of the L1/L2 messaging outbox contract.
22
+ */
23
+ outbox: EthAddress;
24
+ /**
25
+ * Address of the decoder helper contract
26
+ */
27
+ decoderHelper?: EthAddress;
19
28
 
20
29
  /**
21
30
  * Registry Address.
@@ -32,7 +41,18 @@ type L1ContractAddressesResp = {
32
41
 
33
42
  export const getL1ContractAddresses = async (url: string): Promise<L1ContractAddresses> => {
34
43
  const reqUrl = new URL(`${url}/api/l1-contract-addresses`);
35
- const response = (await (await fetch(reqUrl.toString())).json()) as unknown as L1ContractAddressesResp;
44
+ const response = await retryUntil(
45
+ async () => {
46
+ try {
47
+ return (await (await fetch(reqUrl.toString())).json()) as unknown as L1ContractAddressesResp;
48
+ } catch (err) {
49
+ // do nothing
50
+ }
51
+ },
52
+ 'isSandboxReady',
53
+ 120,
54
+ 1,
55
+ );
36
56
  const result = Object.fromEntries(
37
57
  Object.entries(response).map(([key, value]) => [key, EthAddress.fromString(value)]),
38
58
  );
package/tsconfig.json CHANGED
@@ -12,12 +12,9 @@
12
12
  {
13
13
  "path": "../foundation"
14
14
  },
15
- {
16
- "path": "../noir-contracts"
17
- },
18
15
  {
19
16
  "path": "../types"
20
17
  }
21
18
  ],
22
- "include": ["src"]
19
+ "include": ["src", "src/**/*.json"]
23
20
  }
@@ -1,44 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { AztecAddress, CircuitsWasm, Fr, PartialContractAddress, TxContext } from '@aztec/circuits.js';
3
- import { ExecutionRequest, PublicKey, TxExecutionRequest } from '@aztec/types';
4
- import { ContractAbi } from '@aztec/foundation/abi';
5
- import { AccountImplementation } from './index.js';
6
- import { EcdsaAuthProvider, SchnorrAuthProvider } from '../auth/index.js';
7
- /**
8
- * Account backed by an account contract
9
- */
10
- export declare class AccountContract implements AccountImplementation {
11
- private address;
12
- private pubKey;
13
- private authProvider;
14
- private partialContractAddress;
15
- private contractAbi;
16
- private wasm;
17
- constructor(address: AztecAddress, pubKey: PublicKey, authProvider: EcdsaAuthProvider | SchnorrAuthProvider, partialContractAddress: PartialContractAddress, contractAbi: ContractAbi, wasm: CircuitsWasm);
18
- getAddress(): AztecAddress;
19
- createAuthenticatedTxRequest(executions: ExecutionRequest[], txContext: TxContext): Promise<TxExecutionRequest>;
20
- private getEntrypointAbi;
21
- private checkIsNotDeployment;
22
- private checkSender;
23
- }
24
- /** A call to a function in a noir contract */
25
- export type FunctionCall = {
26
- /** The encoded arguments */
27
- args: Fr[];
28
- /** The function selector */
29
- selector: Buffer;
30
- /** The address of the contract */
31
- target: AztecAddress;
32
- };
33
- /** Encoded payload for the account contract entrypoint */
34
- export type EntrypointPayload = {
35
- /** Concatenated arguments for every call */
36
- flattened_args_hashes: Fr[];
37
- /** Concatenated selectors for every call */
38
- flattened_selectors: Fr[];
39
- /** Concatenated target addresses for every call */
40
- flattened_targets: Fr[];
41
- /** A nonce for replay protection */
42
- nonce: Fr;
43
- };
44
- //# sourceMappingURL=account_contract.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"account_contract.d.ts","sourceRoot":"","sources":["../../src/account_impl/account_contract.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,EAAgB,sBAAsB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGrH,OAAO,EAAE,gBAAgB,EAAmB,SAAS,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EAAE,WAAW,EAA6C,MAAM,uBAAuB,CAAC;AAE/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;GAEG;AACH,qBAAa,eAAgB,YAAW,qBAAqB;IAEzD,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,IAAI;gBALJ,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,iBAAiB,GAAG,mBAAmB,EACrD,sBAAsB,EAAE,sBAAsB,EAC9C,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,YAAY;IAG5B,UAAU,IAAI,YAAY;IAIpB,4BAA4B,CAChC,UAAU,EAAE,gBAAgB,EAAE,EAC9B,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,kBAAkB,CAAC;IAiC9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,WAAW;CAQpB;AAKD,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG;IACzB,4BAA4B;IAC5B,IAAI,EAAE,EAAE,EAAE,CAAC;IACX,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,iBAAiB,GAAG;IAE9B,4CAA4C;IAC5C,qBAAqB,EAAE,EAAE,EAAE,CAAC;IAE5B,4CAA4C;IAC5C,mBAAmB,EAAE,EAAE,EAAE,CAAC;IAE1B,mDAAmD;IACnD,iBAAiB,EAAE,EAAE,EAAE,CAAC;IACxB,oCAAoC;IACpC,KAAK,EAAE,EAAE,CAAC;CACX,CAAC"}
@@ -1,107 +0,0 @@
1
- import partition from 'lodash.partition';
2
- import { AztecAddress, Fr, FunctionData } from '@aztec/circuits.js';
3
- import { padArrayEnd } from '@aztec/foundation/collection';
4
- import { sha256 } from '@aztec/foundation/crypto';
5
- import { PackedArguments, TxExecutionRequest } from '@aztec/types';
6
- import { encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
7
- /**
8
- * Account backed by an account contract
9
- */
10
- export class AccountContract {
11
- constructor(address, pubKey, authProvider, partialContractAddress, contractAbi, wasm) {
12
- this.address = address;
13
- this.pubKey = pubKey;
14
- this.authProvider = authProvider;
15
- this.partialContractAddress = partialContractAddress;
16
- this.contractAbi = contractAbi;
17
- this.wasm = wasm;
18
- }
19
- getAddress() {
20
- return this.address;
21
- }
22
- async createAuthenticatedTxRequest(executions, txContext) {
23
- this.checkSender(executions);
24
- this.checkIsNotDeployment(txContext);
25
- const [privateCalls, publicCalls] = partition(executions, exec => exec.functionData.isPrivate).map(execs => execs.map(exec => ({
26
- args: exec.args,
27
- selector: exec.functionData.functionSelectorBuffer,
28
- target: exec.to,
29
- })));
30
- const { payload, packedArguments: callsPackedArguments } = await buildPayload(privateCalls, publicCalls, this.wasm);
31
- const hash = hashPayload(payload);
32
- const signature = await this.authProvider.authenticateTx(payload, hash, this.address);
33
- const signatureAsFrArray = signature.toFields();
34
- const publicKeyAsBuffer = this.pubKey.toBuffer();
35
- const args = [payload, publicKeyAsBuffer, signatureAsFrArray, this.partialContractAddress];
36
- const abi = this.getEntrypointAbi();
37
- const selector = generateFunctionSelector(abi.name, abi.parameters);
38
- const packedArgs = await PackedArguments.fromArgs(encodeArguments(abi, args), this.wasm);
39
- const txRequest = TxExecutionRequest.from({
40
- argsHash: packedArgs.hash,
41
- origin: this.address,
42
- functionData: new FunctionData(selector, true, false),
43
- txContext,
44
- packedArguments: [...callsPackedArguments, packedArgs],
45
- });
46
- return txRequest;
47
- }
48
- getEntrypointAbi() {
49
- const abi = this.contractAbi.functions.find(f => f.name === 'entrypoint');
50
- if (!abi)
51
- throw new Error(`Entrypoint abi for account contract not found`);
52
- return abi;
53
- }
54
- checkIsNotDeployment(txContext) {
55
- if (txContext.isContractDeploymentTx) {
56
- throw new Error(`Cannot yet deploy contracts from an account contract`);
57
- }
58
- }
59
- checkSender(executions) {
60
- const wrongSender = executions.find(e => !e.from.equals(this.address));
61
- if (wrongSender) {
62
- throw new Error(`Sender ${wrongSender.from.toString()} does not match account address ${this.address.toString()}`);
63
- }
64
- }
65
- }
66
- const ACCOUNT_MAX_PRIVATE_CALLS = 1;
67
- const ACCOUNT_MAX_PUBLIC_CALLS = 1;
68
- /** Assembles an entrypoint payload from a set of private and public function calls */
69
- async function buildPayload(privateCalls, publicCalls, wasm) {
70
- const nonce = Fr.random();
71
- const emptyCall = { args: [], selector: Buffer.alloc(32), target: AztecAddress.ZERO };
72
- const calls = [
73
- ...padArrayEnd(privateCalls, emptyCall, ACCOUNT_MAX_PRIVATE_CALLS),
74
- ...padArrayEnd(publicCalls, emptyCall, ACCOUNT_MAX_PUBLIC_CALLS),
75
- ];
76
- const packedArguments = [];
77
- for (const call of calls) {
78
- packedArguments.push(await PackedArguments.fromArgs(call.args, wasm));
79
- }
80
- return {
81
- payload: {
82
- // eslint-disable-next-line camelcase
83
- flattened_args_hashes: packedArguments.map(args => args.hash),
84
- // eslint-disable-next-line camelcase
85
- flattened_selectors: calls.map(call => Fr.fromBuffer(call.selector)),
86
- // eslint-disable-next-line camelcase
87
- flattened_targets: calls.map(call => call.target.toField()),
88
- nonce,
89
- },
90
- packedArguments,
91
- };
92
- }
93
- /** Hashes an entrypoint payload (useful for signing) */
94
- function hashPayload(payload) {
95
- // TODO: Switch to keccak when avaiable in Noir
96
- return sha256(Buffer.concat(flattenPayload(payload).map(fr => fr.toBuffer())));
97
- }
98
- /** Flattens an entrypoint payload */
99
- function flattenPayload(payload) {
100
- return [
101
- ...payload.flattened_args_hashes,
102
- ...payload.flattened_selectors,
103
- ...payload.flattened_targets,
104
- payload.nonce,
105
- ];
106
- }
107
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3VudF9jb250cmFjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hY2NvdW50X2ltcGwvYWNjb3VudF9jb250cmFjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVMsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFnQixFQUFFLEVBQUUsWUFBWSxFQUFxQyxNQUFNLG9CQUFvQixDQUFDO0FBQ3JILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDbEQsT0FBTyxFQUFvQixlQUFlLEVBQWEsa0JBQWtCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDaEcsT0FBTyxFQUFlLGVBQWUsRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBSy9GOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFDMUIsWUFDVSxPQUFxQixFQUNyQixNQUFpQixFQUNqQixZQUFxRCxFQUNyRCxzQkFBOEMsRUFDOUMsV0FBd0IsRUFDeEIsSUFBa0I7UUFMbEIsWUFBTyxHQUFQLE9BQU8sQ0FBYztRQUNyQixXQUFNLEdBQU4sTUFBTSxDQUFXO1FBQ2pCLGlCQUFZLEdBQVosWUFBWSxDQUF5QztRQUNyRCwyQkFBc0IsR0FBdEIsc0JBQXNCLENBQXdCO1FBQzlDLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLFNBQUksR0FBSixJQUFJLENBQWM7SUFDekIsQ0FBQztJQUVKLFVBQVU7UUFDUixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVELEtBQUssQ0FBQyw0QkFBNEIsQ0FDaEMsVUFBOEIsRUFDOUIsU0FBb0I7UUFFcEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM3QixJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7UUFF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