@aztec/accounts 0.23.0 → 0.26.1
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.
- package/dest/artifacts/EcdsaAccount.json +1 -3218
- package/dest/artifacts/SchnorrAccount.json +1 -3210
- package/dest/artifacts/SchnorrSingleKeyAccount.json +1 -3123
- package/dest/defaults/account_interface.d.ts +3 -3
- package/dest/defaults/account_interface.d.ts.map +1 -1
- package/dest/defaults/account_interface.js +5 -5
- package/dest/defaults/index.d.ts +0 -3
- package/dest/defaults/index.d.ts.map +1 -1
- package/dest/defaults/index.js +1 -4
- package/dest/testing/configuration.d.ts.map +1 -1
- package/dest/testing/configuration.js +6 -2
- package/dest/testing/create_account.d.ts.map +1 -1
- package/dest/testing/create_account.js +6 -2
- package/package.json +10 -9
- package/src/artifacts/EcdsaAccount.json +1 -0
- package/src/artifacts/SchnorrAccount.json +1 -0
- package/src/artifacts/SchnorrSingleKeyAccount.json +1 -0
- package/src/defaults/account_contract.ts +25 -0
- package/src/defaults/account_interface.ts +38 -0
- package/src/defaults/index.ts +10 -0
- package/src/ecdsa/account_contract.ts +38 -0
- package/src/ecdsa/artifact.ts +5 -0
- package/src/ecdsa/index.ts +42 -0
- package/src/schnorr/account_contract.ts +38 -0
- package/src/schnorr/artifact.ts +5 -0
- package/src/schnorr/index.ts +47 -0
- package/src/single_key/account_contract.ts +45 -0
- package/src/single_key/artifact.ts +7 -0
- package/src/single_key/index.ts +52 -0
- package/src/testing/configuration.ts +85 -0
- package/src/testing/create_account.ts +45 -0
- package/src/testing/index.ts +11 -0
- package/dest/defaults/account_entrypoint.d.ts +0 -17
- package/dest/defaults/account_entrypoint.d.ts.map +0 -1
- package/dest/defaults/account_entrypoint.js +0 -117
- package/dest/defaults/constants.d.ts +0 -5
- package/dest/defaults/constants.d.ts.map +0 -1
- package/dest/defaults/constants.js +0 -5
- package/dest/defaults/entrypoint_payload.d.ts +0 -32
- package/dest/defaults/entrypoint_payload.d.ts.map +0 -1
- package/dest/defaults/entrypoint_payload.js +0 -50
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AccountContract, AccountInterface, AuthWitnessProvider } from '@aztec/aztec.js/account';
|
|
2
|
+
import { CompleteAddress } from '@aztec/circuit-types';
|
|
3
|
+
import { ContractArtifact } from '@aztec/foundation/abi';
|
|
4
|
+
import { NodeInfo } from '@aztec/types/interfaces';
|
|
5
|
+
|
|
6
|
+
import { DefaultAccountInterface } from '../defaults/account_interface.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Base class for implementing an account contract. Requires that the account uses the
|
|
10
|
+
* default entrypoint method signature.
|
|
11
|
+
*/
|
|
12
|
+
export abstract class DefaultAccountContract implements AccountContract {
|
|
13
|
+
abstract getAuthWitnessProvider(address: CompleteAddress): AuthWitnessProvider;
|
|
14
|
+
abstract getDeploymentArgs(): any[];
|
|
15
|
+
|
|
16
|
+
constructor(private artifact: ContractArtifact) {}
|
|
17
|
+
|
|
18
|
+
getContractArtifact(): ContractArtifact {
|
|
19
|
+
return this.artifact;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getInterface(address: CompleteAddress, nodeInfo: NodeInfo): AccountInterface {
|
|
23
|
+
return new DefaultAccountInterface(this.getAuthWitnessProvider(address), address, nodeInfo);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account';
|
|
2
|
+
import { AuthWitness, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types';
|
|
3
|
+
import { CompleteAddress, Fr } from '@aztec/circuits.js';
|
|
4
|
+
import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account';
|
|
5
|
+
import { NodeInfo } from '@aztec/types/interfaces';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default implementation for an account interface. Requires that the account uses the default
|
|
9
|
+
* entrypoint signature, which accept an AppPayload and a FeePayload as defined in noir-libs/aztec-noir/src/entrypoint module
|
|
10
|
+
*/
|
|
11
|
+
export class DefaultAccountInterface implements AccountInterface {
|
|
12
|
+
private entrypoint: EntrypointInterface;
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
private authWitnessProvider: AuthWitnessProvider,
|
|
16
|
+
private address: CompleteAddress,
|
|
17
|
+
nodeInfo: Pick<NodeInfo, 'chainId' | 'protocolVersion'>,
|
|
18
|
+
) {
|
|
19
|
+
this.entrypoint = new DefaultAccountEntrypoint(
|
|
20
|
+
address.address,
|
|
21
|
+
authWitnessProvider,
|
|
22
|
+
nodeInfo.chainId,
|
|
23
|
+
nodeInfo.protocolVersion,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
createTxExecutionRequest(executions: FunctionCall[], fee?: FeeOptions): Promise<TxExecutionRequest> {
|
|
28
|
+
return this.entrypoint.createTxExecutionRequest(executions, fee);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
createAuthWitness(message: Fr): Promise<AuthWitness> {
|
|
32
|
+
return this.authWitnessProvider.createAuthWitness(message);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getCompleteAddress(): CompleteAddress {
|
|
36
|
+
return this.address;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@aztec/accounts/defaults` export provides the base class {@link DefaultAccountContract} for implementing account contracts that use the default entrypoint payload module.
|
|
3
|
+
*
|
|
4
|
+
* Read more in {@link https://docs.aztec.network/developers/wallets/writing_an_account_contract | Writing an account contract}.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './account_interface.js';
|
|
10
|
+
export * from './account_contract.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AuthWitnessProvider } from '@aztec/aztec.js/account';
|
|
2
|
+
import { AuthWitness, CompleteAddress } from '@aztec/circuit-types';
|
|
3
|
+
import { Ecdsa } from '@aztec/circuits.js/barretenberg';
|
|
4
|
+
import { ContractArtifact } from '@aztec/foundation/abi';
|
|
5
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
6
|
+
|
|
7
|
+
import { DefaultAccountContract } from '../defaults/account_contract.js';
|
|
8
|
+
import { EcdsaAccountContractArtifact } from './artifact.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Account contract that authenticates transactions using ECDSA signatures
|
|
12
|
+
* verified against a secp256k1 public key stored in an immutable encrypted note.
|
|
13
|
+
*/
|
|
14
|
+
export class EcdsaAccountContract extends DefaultAccountContract {
|
|
15
|
+
constructor(private signingPrivateKey: Buffer) {
|
|
16
|
+
super(EcdsaAccountContractArtifact as ContractArtifact);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getDeploymentArgs() {
|
|
20
|
+
const signingPublicKey = new Ecdsa().computePublicKey(this.signingPrivateKey);
|
|
21
|
+
return [signingPublicKey.subarray(0, 32), signingPublicKey.subarray(32, 64)];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider {
|
|
25
|
+
return new EcdsaAuthWitnessProvider(this.signingPrivateKey);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Creates auth witnesses using ECDSA signatures. */
|
|
30
|
+
class EcdsaAuthWitnessProvider implements AuthWitnessProvider {
|
|
31
|
+
constructor(private signingPrivateKey: Buffer) {}
|
|
32
|
+
|
|
33
|
+
createAuthWitness(message: Fr): Promise<AuthWitness> {
|
|
34
|
+
const ecdsa = new Ecdsa();
|
|
35
|
+
const signature = ecdsa.constructSignature(message.toBuffer(), this.signingPrivateKey);
|
|
36
|
+
return Promise.resolve(new AuthWitness(message, [...signature.r, ...signature.s]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js';
|
|
2
|
+
|
|
3
|
+
import EcdsaAccountContractJson from '../artifacts/EcdsaAccount.json' assert { type: 'json' };
|
|
4
|
+
|
|
5
|
+
export const EcdsaAccountContractArtifact = loadContractArtifact(EcdsaAccountContractJson as NoirCompiledContract);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@aztec/accounts/ecdsa` export provides an ECDSA account contract implementation, that uses an ECDSA private key for authentication, and a Grumpkin key for encryption.
|
|
3
|
+
* Consider using this account type when working with integrations with Ethereum wallets.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
import { AccountManager, Salt } from '@aztec/aztec.js/account';
|
|
8
|
+
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
|
|
9
|
+
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
|
|
10
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
11
|
+
|
|
12
|
+
import { EcdsaAccountContract } from './account_contract.js';
|
|
13
|
+
|
|
14
|
+
export { EcdsaAccountContractArtifact } from './artifact.js';
|
|
15
|
+
export { EcdsaAccountContract };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates an Account that relies on an ECDSA signing key for authentication.
|
|
19
|
+
* @param pxe - An PXE server instance.
|
|
20
|
+
* @param encryptionPrivateKey - Grumpkin key used for note encryption.
|
|
21
|
+
* @param signingPrivateKey - Secp256k1 key used for signing transactions.
|
|
22
|
+
* @param salt - Deployment salt.
|
|
23
|
+
*/
|
|
24
|
+
export function getEcdsaAccount(
|
|
25
|
+
pxe: PXE,
|
|
26
|
+
encryptionPrivateKey: GrumpkinPrivateKey,
|
|
27
|
+
signingPrivateKey: Buffer,
|
|
28
|
+
salt?: Salt,
|
|
29
|
+
): AccountManager {
|
|
30
|
+
return new AccountManager(pxe, encryptionPrivateKey, new EcdsaAccountContract(signingPrivateKey), salt);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets a wallet for an already registered account using ECDSA signatures.
|
|
35
|
+
* @param pxe - An PXE server instance.
|
|
36
|
+
* @param address - Address for the account.
|
|
37
|
+
* @param signingPrivateKey - ECDSA key used for signing transactions.
|
|
38
|
+
* @returns A wallet for this account that can be used to interact with a contract instance.
|
|
39
|
+
*/
|
|
40
|
+
export function getEcdsaWallet(pxe: PXE, address: AztecAddress, signingPrivateKey: Buffer): Promise<AccountWallet> {
|
|
41
|
+
return getWallet(pxe, address, new EcdsaAccountContract(signingPrivateKey));
|
|
42
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AuthWitnessProvider } from '@aztec/aztec.js/account';
|
|
2
|
+
import { AuthWitness, CompleteAddress, GrumpkinPrivateKey } from '@aztec/circuit-types';
|
|
3
|
+
import { Schnorr } from '@aztec/circuits.js/barretenberg';
|
|
4
|
+
import { ContractArtifact } from '@aztec/foundation/abi';
|
|
5
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
6
|
+
|
|
7
|
+
import { DefaultAccountContract } from '../defaults/account_contract.js';
|
|
8
|
+
import { SchnorrAccountContractArtifact } from './artifact.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Account contract that authenticates transactions using Schnorr signatures
|
|
12
|
+
* verified against a Grumpkin public key stored in an immutable encrypted note.
|
|
13
|
+
*/
|
|
14
|
+
export class SchnorrAccountContract extends DefaultAccountContract {
|
|
15
|
+
constructor(private signingPrivateKey: GrumpkinPrivateKey) {
|
|
16
|
+
super(SchnorrAccountContractArtifact as ContractArtifact);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getDeploymentArgs() {
|
|
20
|
+
const signingPublicKey = new Schnorr().computePublicKey(this.signingPrivateKey);
|
|
21
|
+
return [signingPublicKey.x, signingPublicKey.y];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider {
|
|
25
|
+
return new SchnorrAuthWitnessProvider(this.signingPrivateKey);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Creates auth witnesses using Schnorr signatures. */
|
|
30
|
+
class SchnorrAuthWitnessProvider implements AuthWitnessProvider {
|
|
31
|
+
constructor(private signingPrivateKey: GrumpkinPrivateKey) {}
|
|
32
|
+
|
|
33
|
+
createAuthWitness(message: Fr): Promise<AuthWitness> {
|
|
34
|
+
const schnorr = new Schnorr();
|
|
35
|
+
const signature = schnorr.constructSignature(message.toBuffer(), this.signingPrivateKey).toBuffer();
|
|
36
|
+
return Promise.resolve(new AuthWitness(message, [...signature]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js';
|
|
2
|
+
|
|
3
|
+
import SchnorrAccountContractJson from '../artifacts/SchnorrAccount.json' assert { type: 'json' };
|
|
4
|
+
|
|
5
|
+
export const SchnorrAccountContractArtifact = loadContractArtifact(SchnorrAccountContractJson as NoirCompiledContract);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@aztec/accounts/schnorr` export provides an account contract implementation that uses Schnorr signatures with a Grumpkin key for authentication, and a separate Grumpkin key for encryption.
|
|
3
|
+
* This is the suggested account contract type for most use cases within Aztec.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
import { AccountManager, Salt } from '@aztec/aztec.js/account';
|
|
8
|
+
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
|
|
9
|
+
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
|
|
10
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
11
|
+
|
|
12
|
+
import { SchnorrAccountContract } from './account_contract.js';
|
|
13
|
+
|
|
14
|
+
export { SchnorrAccountContract };
|
|
15
|
+
|
|
16
|
+
export { SchnorrAccountContractArtifact } from './artifact.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates an Account Manager that relies on a Grumpkin signing key for authentication.
|
|
20
|
+
* @param pxe - An PXE server instance.
|
|
21
|
+
* @param encryptionPrivateKey - Grumpkin key used for note encryption.
|
|
22
|
+
* @param signingPrivateKey - Grumpkin key used for signing transactions.
|
|
23
|
+
* @param salt - Deployment salt.
|
|
24
|
+
*/
|
|
25
|
+
export function getSchnorrAccount(
|
|
26
|
+
pxe: PXE,
|
|
27
|
+
encryptionPrivateKey: GrumpkinPrivateKey,
|
|
28
|
+
signingPrivateKey: GrumpkinPrivateKey,
|
|
29
|
+
salt?: Salt,
|
|
30
|
+
): AccountManager {
|
|
31
|
+
return new AccountManager(pxe, encryptionPrivateKey, new SchnorrAccountContract(signingPrivateKey), salt);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gets a wallet for an already registered account using Schnorr signatures.
|
|
36
|
+
* @param pxe - An PXE server instance.
|
|
37
|
+
* @param address - Address for the account.
|
|
38
|
+
* @param signingPrivateKey - Grumpkin key used for signing transactions.
|
|
39
|
+
* @returns A wallet for this account that can be used to interact with a contract instance.
|
|
40
|
+
*/
|
|
41
|
+
export function getSchnorrWallet(
|
|
42
|
+
pxe: PXE,
|
|
43
|
+
address: AztecAddress,
|
|
44
|
+
signingPrivateKey: GrumpkinPrivateKey,
|
|
45
|
+
): Promise<AccountWallet> {
|
|
46
|
+
return getWallet(pxe, address, new SchnorrAccountContract(signingPrivateKey));
|
|
47
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { generatePublicKey } from '@aztec/aztec.js';
|
|
2
|
+
import { AuthWitnessProvider } from '@aztec/aztec.js/account';
|
|
3
|
+
import { AuthWitness, CompleteAddress, GrumpkinPrivateKey } from '@aztec/circuit-types';
|
|
4
|
+
import { PartialAddress } from '@aztec/circuits.js';
|
|
5
|
+
import { Schnorr } from '@aztec/circuits.js/barretenberg';
|
|
6
|
+
import { ContractArtifact } from '@aztec/foundation/abi';
|
|
7
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
8
|
+
|
|
9
|
+
import { DefaultAccountContract } from '../defaults/account_contract.js';
|
|
10
|
+
import { SchnorrSingleKeyAccountContractArtifact } from './artifact.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Account contract that authenticates transactions using Schnorr signatures verified against
|
|
14
|
+
* the note encryption key, relying on a single private key for both encryption and authentication.
|
|
15
|
+
*/
|
|
16
|
+
export class SingleKeyAccountContract extends DefaultAccountContract {
|
|
17
|
+
constructor(private encryptionPrivateKey: GrumpkinPrivateKey) {
|
|
18
|
+
super(SchnorrSingleKeyAccountContractArtifact as ContractArtifact);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getDeploymentArgs(): any[] {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getAuthWitnessProvider({ partialAddress }: CompleteAddress): AuthWitnessProvider {
|
|
26
|
+
return new SingleKeyAuthWitnessProvider(this.encryptionPrivateKey, partialAddress);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates auth witnesses using Schnorr signatures and including the partial address and public key
|
|
32
|
+
* in the witness, so verifiers do not need to store the public key and can instead validate it
|
|
33
|
+
* by reconstructing the current address.
|
|
34
|
+
*/
|
|
35
|
+
class SingleKeyAuthWitnessProvider implements AuthWitnessProvider {
|
|
36
|
+
constructor(private privateKey: GrumpkinPrivateKey, private partialAddress: PartialAddress) {}
|
|
37
|
+
|
|
38
|
+
createAuthWitness(message: Fr): Promise<AuthWitness> {
|
|
39
|
+
const schnorr = new Schnorr();
|
|
40
|
+
const signature = schnorr.constructSignature(message.toBuffer(), this.privateKey);
|
|
41
|
+
const publicKey = generatePublicKey(this.privateKey);
|
|
42
|
+
const witness = [...publicKey.toFields(), ...signature.toBuffer(), this.partialAddress];
|
|
43
|
+
return Promise.resolve(new AuthWitness(message, witness));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js';
|
|
2
|
+
|
|
3
|
+
import SchnorrSingleKeyAccountContractJson from '../artifacts/SchnorrSingleKeyAccount.json' assert { type: 'json' };
|
|
4
|
+
|
|
5
|
+
export const SchnorrSingleKeyAccountContractArtifact = loadContractArtifact(
|
|
6
|
+
SchnorrSingleKeyAccountContractJson as NoirCompiledContract,
|
|
7
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@aztec/accounts/single_key` export provides a testing account contract implementation that uses a single Grumpkin key for both authentication and encryption.
|
|
3
|
+
* It is not recommended to use this account type in production.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
import { AccountManager, Salt } from '@aztec/aztec.js/account';
|
|
8
|
+
import { AccountWallet, getWallet } from '@aztec/aztec.js/wallet';
|
|
9
|
+
import { GrumpkinPrivateKey, PXE } from '@aztec/circuit-types';
|
|
10
|
+
import { AztecAddress } from '@aztec/circuits.js';
|
|
11
|
+
|
|
12
|
+
import { SingleKeyAccountContract } from './account_contract.js';
|
|
13
|
+
|
|
14
|
+
export { SingleKeyAccountContract };
|
|
15
|
+
|
|
16
|
+
export { SchnorrSingleKeyAccountContractArtifact as SingleKeyAccountContractArtifact } from './artifact.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates an Account that uses the same Grumpkin key for encryption and authentication.
|
|
20
|
+
* @param pxe - An PXE server instance.
|
|
21
|
+
* @param encryptionAndSigningPrivateKey - Grumpkin key used for note encryption and signing transactions.
|
|
22
|
+
* @param salt - Deployment salt .
|
|
23
|
+
*/
|
|
24
|
+
export function getSingleKeyAccount(
|
|
25
|
+
pxe: PXE,
|
|
26
|
+
encryptionAndSigningPrivateKey: GrumpkinPrivateKey,
|
|
27
|
+
salt?: Salt,
|
|
28
|
+
): AccountManager {
|
|
29
|
+
return new AccountManager(
|
|
30
|
+
pxe,
|
|
31
|
+
encryptionAndSigningPrivateKey,
|
|
32
|
+
new SingleKeyAccountContract(encryptionAndSigningPrivateKey),
|
|
33
|
+
salt,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets a wallet for an already registered account using Schnorr signatures with a single key for encryption and authentication.
|
|
39
|
+
* @param pxe - An PXE server instance.
|
|
40
|
+
* @param address - Address for the account.
|
|
41
|
+
* @param signingPrivateKey - Grumpkin key used for note encryption and signing transactions.
|
|
42
|
+
* @returns A wallet for this account that can be used to interact with a contract instance.
|
|
43
|
+
*/
|
|
44
|
+
export function getSingleKeyWallet(
|
|
45
|
+
pxe: PXE,
|
|
46
|
+
address: AztecAddress,
|
|
47
|
+
signingKey: GrumpkinPrivateKey,
|
|
48
|
+
): Promise<AccountWallet> {
|
|
49
|
+
return getWallet(pxe, address, new SingleKeyAccountContract(signingKey));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { getSingleKeyAccount as getUnsafeSchnorrAccount, getSingleKeyWallet as getUnsafeSchnorrWallet };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { generatePublicKey } from '@aztec/aztec.js';
|
|
2
|
+
import { AccountWalletWithPrivateKey } from '@aztec/aztec.js/wallet';
|
|
3
|
+
import { PXE } from '@aztec/circuit-types';
|
|
4
|
+
import { Fr, GrumpkinScalar } from '@aztec/foundation/fields';
|
|
5
|
+
|
|
6
|
+
import { getSchnorrAccount } from '../schnorr/index.js';
|
|
7
|
+
|
|
8
|
+
export const INITIAL_TEST_ENCRYPTION_KEYS = [
|
|
9
|
+
GrumpkinScalar.fromString('2153536ff6628eee01cf4024889ff977a18d9fa61d0e414422f7681cf085c281'),
|
|
10
|
+
GrumpkinScalar.fromString('aebd1b4be76efa44f5ee655c20bf9ea60f7ae44b9a7fd1fd9f189c7a0b0cdae'),
|
|
11
|
+
GrumpkinScalar.fromString('0f6addf0da06c33293df974a565b03d1ab096090d907d98055a8b7f4954e120c'),
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const INITIAL_TEST_SIGNING_KEYS = INITIAL_TEST_ENCRYPTION_KEYS;
|
|
15
|
+
|
|
16
|
+
export const INITIAL_TEST_ACCOUNT_SALTS = [Fr.ZERO, Fr.ZERO, Fr.ZERO];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets a collection of wallets for the Aztec accounts that are initially stored in the test environment.
|
|
20
|
+
* @param pxe - PXE instance.
|
|
21
|
+
* @returns A set of AccountWallet implementations for each of the initial accounts.
|
|
22
|
+
*/
|
|
23
|
+
export function getInitialTestAccountsWallets(pxe: PXE): Promise<AccountWalletWithPrivateKey[]> {
|
|
24
|
+
return Promise.all(
|
|
25
|
+
INITIAL_TEST_ENCRYPTION_KEYS.map((encryptionKey, i) =>
|
|
26
|
+
getSchnorrAccount(pxe, encryptionKey!, INITIAL_TEST_SIGNING_KEYS[i]!, INITIAL_TEST_ACCOUNT_SALTS[i]).getWallet(),
|
|
27
|
+
),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Queries a PXE for it's registered accounts and returns wallets for those accounts using keys in the initial test accounts.
|
|
33
|
+
* @param pxe - PXE instance.
|
|
34
|
+
* @returns A set of AccountWallet implementations for each of the initial accounts.
|
|
35
|
+
*/
|
|
36
|
+
export async function getDeployedTestAccountsWallets(pxe: PXE): Promise<AccountWalletWithPrivateKey[]> {
|
|
37
|
+
const registeredAccounts = await pxe.getRegisteredAccounts();
|
|
38
|
+
return Promise.all(
|
|
39
|
+
INITIAL_TEST_ENCRYPTION_KEYS.filter(initialKey => {
|
|
40
|
+
const publicKey = generatePublicKey(initialKey);
|
|
41
|
+
return registeredAccounts.find(registered => registered.publicKey.equals(publicKey)) != undefined;
|
|
42
|
+
}).map((encryptionKey, i) =>
|
|
43
|
+
getSchnorrAccount(pxe, encryptionKey!, INITIAL_TEST_SIGNING_KEYS[i]!, INITIAL_TEST_ACCOUNT_SALTS[i]).getWallet(),
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Deploys the initial set of schnorr signature accounts to the test environment
|
|
50
|
+
* @param pxe - PXE instance.
|
|
51
|
+
* @returns The set of deployed Account objects and associated private encryption keys
|
|
52
|
+
*/
|
|
53
|
+
export async function deployInitialTestAccounts(pxe: PXE) {
|
|
54
|
+
const accounts = INITIAL_TEST_ENCRYPTION_KEYS.map((privateKey, i) => {
|
|
55
|
+
const account = getSchnorrAccount(pxe, privateKey, INITIAL_TEST_SIGNING_KEYS[i], INITIAL_TEST_ACCOUNT_SALTS[i]);
|
|
56
|
+
return {
|
|
57
|
+
account,
|
|
58
|
+
privateKey,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
// Attempt to get as much parallelism as possible
|
|
62
|
+
const deployMethods = await Promise.all(
|
|
63
|
+
accounts.map(async x => {
|
|
64
|
+
const deployMethod = await x.account.getDeployMethod();
|
|
65
|
+
await deployMethod.create({
|
|
66
|
+
contractAddressSalt: x.account.salt,
|
|
67
|
+
skipClassRegistration: true,
|
|
68
|
+
skipPublicDeployment: true,
|
|
69
|
+
});
|
|
70
|
+
await deployMethod.simulate({});
|
|
71
|
+
return deployMethod;
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
// Send tx together to try and get them in the same rollup
|
|
75
|
+
const sentTxs = deployMethods.map(dm => {
|
|
76
|
+
return dm.send();
|
|
77
|
+
});
|
|
78
|
+
await Promise.all(
|
|
79
|
+
sentTxs.map(async (tx, i) => {
|
|
80
|
+
const wallet = await accounts[i].account.getWallet();
|
|
81
|
+
return tx.wait({ wallet });
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
return accounts;
|
|
85
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { AccountWalletWithPrivateKey } from '@aztec/aztec.js/wallet';
|
|
2
|
+
import { PXE } from '@aztec/circuit-types';
|
|
3
|
+
import { GrumpkinScalar } from '@aztec/circuits.js';
|
|
4
|
+
|
|
5
|
+
import { getSchnorrAccount } from '../schnorr/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Deploys and registers a new account using random private keys and returns the associated Schnorr account wallet. Useful for testing.
|
|
9
|
+
* @param pxe - PXE.
|
|
10
|
+
* @returns - A wallet for a fresh account.
|
|
11
|
+
*/
|
|
12
|
+
export function createAccount(pxe: PXE): Promise<AccountWalletWithPrivateKey> {
|
|
13
|
+
return getSchnorrAccount(pxe, GrumpkinScalar.random(), GrumpkinScalar.random()).waitDeploy();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a given number of random accounts using the Schnorr account wallet.
|
|
18
|
+
* @param pxe - PXE.
|
|
19
|
+
* @param numberOfAccounts - How many accounts to create.
|
|
20
|
+
* @returns The created account wallets.
|
|
21
|
+
*/
|
|
22
|
+
export async function createAccounts(pxe: PXE, numberOfAccounts = 1): Promise<AccountWalletWithPrivateKey[]> {
|
|
23
|
+
const accounts = [];
|
|
24
|
+
|
|
25
|
+
// Prepare deployments
|
|
26
|
+
for (let i = 0; i < numberOfAccounts; ++i) {
|
|
27
|
+
const account = getSchnorrAccount(pxe, GrumpkinScalar.random(), GrumpkinScalar.random());
|
|
28
|
+
// Unfortunately the function below is not stateless and we call it here because it takes a long time to run and
|
|
29
|
+
// the results get stored within the account object. By calling it here we increase the probability of all the
|
|
30
|
+
// accounts being deployed in the same block because it makes the deploy() method basically instant.
|
|
31
|
+
await account.getDeployMethod().then(d =>
|
|
32
|
+
d.simulate({
|
|
33
|
+
contractAddressSalt: account.salt,
|
|
34
|
+
skipClassRegistration: true,
|
|
35
|
+
skipPublicDeployment: true,
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
accounts.push(account);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Send them and await them to be mined
|
|
42
|
+
const txs = await Promise.all(accounts.map(account => account.deploy()));
|
|
43
|
+
await Promise.all(txs.map(tx => tx.wait({ interval: 0.1 })));
|
|
44
|
+
return Promise.all(accounts.map(account => account.getWallet()));
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `@aztec/accounts/testing` export provides utility methods for testing, in particular in a Sandbox environment.
|
|
3
|
+
*
|
|
4
|
+
* Use the {@link createAccount} and {@link createAccounts} methods to create new sample accounts for testing,
|
|
5
|
+
* or use {@link getInitialTestAccountsWallets} to obtain a list of wallets for the Sandbox pre-seeded accounts.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './create_account.js';
|
|
11
|
+
export * from './configuration.js';
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { AuthWitnessProvider, EntrypointInterface } from '@aztec/aztec.js/account';
|
|
2
|
-
import { FunctionCall, TxExecutionRequest } from '@aztec/circuit-types';
|
|
3
|
-
import { AztecAddress } from '@aztec/circuits.js';
|
|
4
|
-
/**
|
|
5
|
-
* Implementation for an entrypoint interface that follows the default entrypoint signature
|
|
6
|
-
* for an account, which accepts an EntrypointPayload as defined in noir-libs/aztec-noir/src/entrypoint.nr.
|
|
7
|
-
*/
|
|
8
|
-
export declare class DefaultAccountEntrypoint implements EntrypointInterface {
|
|
9
|
-
private address;
|
|
10
|
-
private auth;
|
|
11
|
-
private chainId;
|
|
12
|
-
private version;
|
|
13
|
-
constructor(address: AztecAddress, auth: AuthWitnessProvider, chainId?: number, version?: number);
|
|
14
|
-
createTxExecutionRequest(executions: FunctionCall[]): Promise<TxExecutionRequest>;
|
|
15
|
-
private getEntrypointAbi;
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=account_entrypoint.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"account_entrypoint.d.ts","sourceRoot":"","sources":["../../src/defaults/account_entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAmB,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,YAAY,EAA+B,MAAM,oBAAoB,CAAC;AAM/E;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,mBAAmB;IAEhE,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBAHP,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,mBAAmB,EACzB,OAAO,GAAE,MAAyB,EAClC,OAAO,GAAE,MAAwB;IAGrC,wBAAwB,CAAC,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkBvF,OAAO,CAAC,gBAAgB;CAmFzB"}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { PackedArguments, TxExecutionRequest } from '@aztec/circuit-types';
|
|
2
|
-
import { Fr, FunctionData, TxContext } from '@aztec/circuits.js';
|
|
3
|
-
import { encodeArguments } from '@aztec/foundation/abi';
|
|
4
|
-
import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from './constants.js';
|
|
5
|
-
import { buildPayload, hashPayload } from './entrypoint_payload.js';
|
|
6
|
-
/**
|
|
7
|
-
* Implementation for an entrypoint interface that follows the default entrypoint signature
|
|
8
|
-
* for an account, which accepts an EntrypointPayload as defined in noir-libs/aztec-noir/src/entrypoint.nr.
|
|
9
|
-
*/
|
|
10
|
-
export class DefaultAccountEntrypoint {
|
|
11
|
-
constructor(address, auth, chainId = DEFAULT_CHAIN_ID, version = DEFAULT_VERSION) {
|
|
12
|
-
this.address = address;
|
|
13
|
-
this.auth = auth;
|
|
14
|
-
this.chainId = chainId;
|
|
15
|
-
this.version = version;
|
|
16
|
-
}
|
|
17
|
-
async createTxExecutionRequest(executions) {
|
|
18
|
-
const { payload, packedArguments: callsPackedArguments } = buildPayload(executions);
|
|
19
|
-
const abi = this.getEntrypointAbi();
|
|
20
|
-
const packedArgs = PackedArguments.fromArgs(encodeArguments(abi, [payload]));
|
|
21
|
-
const message = Fr.fromBuffer(hashPayload(payload));
|
|
22
|
-
const authWitness = await this.auth.createAuthWitness(message);
|
|
23
|
-
const txRequest = TxExecutionRequest.from({
|
|
24
|
-
argsHash: packedArgs.hash,
|
|
25
|
-
origin: this.address,
|
|
26
|
-
functionData: FunctionData.fromAbi(abi),
|
|
27
|
-
txContext: TxContext.empty(this.chainId, this.version),
|
|
28
|
-
packedArguments: [...callsPackedArguments, packedArgs],
|
|
29
|
-
authWitnesses: [authWitness],
|
|
30
|
-
});
|
|
31
|
-
return txRequest;
|
|
32
|
-
}
|
|
33
|
-
getEntrypointAbi() {
|
|
34
|
-
return {
|
|
35
|
-
name: 'entrypoint',
|
|
36
|
-
functionType: 'secret',
|
|
37
|
-
isInternal: false,
|
|
38
|
-
parameters: [
|
|
39
|
-
{
|
|
40
|
-
name: 'payload',
|
|
41
|
-
type: {
|
|
42
|
-
kind: 'struct',
|
|
43
|
-
path: 'authwit::entrypoint::EntrypointPayload',
|
|
44
|
-
fields: [
|
|
45
|
-
{
|
|
46
|
-
name: 'function_calls',
|
|
47
|
-
type: {
|
|
48
|
-
kind: 'array',
|
|
49
|
-
length: 4,
|
|
50
|
-
type: {
|
|
51
|
-
kind: 'struct',
|
|
52
|
-
path: 'authwit::entrypoint::FunctionCall',
|
|
53
|
-
fields: [
|
|
54
|
-
{
|
|
55
|
-
name: 'args_hash',
|
|
56
|
-
type: {
|
|
57
|
-
kind: 'field',
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'function_selector',
|
|
62
|
-
type: {
|
|
63
|
-
kind: 'struct',
|
|
64
|
-
path: 'aztec::protocol_types::abis::function_selector::FunctionSelector',
|
|
65
|
-
fields: [
|
|
66
|
-
{
|
|
67
|
-
name: 'inner',
|
|
68
|
-
type: {
|
|
69
|
-
kind: 'integer',
|
|
70
|
-
sign: 'unsigned',
|
|
71
|
-
width: 32,
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: 'target_address',
|
|
79
|
-
type: {
|
|
80
|
-
kind: 'struct',
|
|
81
|
-
path: 'aztec::protocol_types::address::AztecAddress',
|
|
82
|
-
fields: [
|
|
83
|
-
{
|
|
84
|
-
name: 'inner',
|
|
85
|
-
type: {
|
|
86
|
-
kind: 'field',
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'is_public',
|
|
94
|
-
type: {
|
|
95
|
-
kind: 'boolean',
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'nonce',
|
|
104
|
-
type: {
|
|
105
|
-
kind: 'field',
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
visibility: 'public',
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
returnTypes: [],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3VudF9lbnRyeXBvaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RlZmF1bHRzL2FjY291bnRfZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQWdCLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3pGLE9BQU8sRUFBZ0IsRUFBRSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMvRSxPQUFPLEVBQWUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFckUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsV0FBVyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFcEU7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLHdCQUF3QjtJQUNuQyxZQUNVLE9BQXFCLEVBQ3JCLElBQXlCLEVBQ3pCLFVBQWtCLGdCQUFnQixFQUNsQyxVQUFrQixlQUFlO1FBSGpDLFlBQU8sR0FBUCxPQUFPLENBQWM7UUFDckIsU0FBSSxHQUFKLElBQUksQ0FBcUI7UUFDekIsWUFBTyxHQUFQLE9BQU8sQ0FBMkI7UUFDbEMsWUFBTyxHQUFQLE9BQU8sQ0FBMEI7SUFDeEMsQ0FBQztJQUVKLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxVQUEwQjtRQUN2RCxNQUFNLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxHQUFHLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNwRixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUNwQyxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0UsTUFBTSxPQUFPLEdBQUcsRUFB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
|