@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.
- package/.tsbuildinfo +1 -1
- package/dest/abis/ecdsa_account_contract.json +150 -0
- package/dest/abis/schnorr_account_contract.json +96 -0
- package/dest/abis/schnorr_single_key_account_contract.json +96 -0
- package/dest/account_impl/account_collection.d.ts.map +1 -1
- package/dest/account_impl/account_collection.js +1 -1
- package/dest/account_impl/entrypoint_payload.d.ts +26 -0
- package/dest/account_impl/entrypoint_payload.d.ts.map +1 -0
- package/dest/account_impl/entrypoint_payload.js +46 -0
- package/dest/account_impl/index.d.ts +2 -1
- package/dest/account_impl/index.d.ts.map +1 -1
- package/dest/account_impl/index.js +3 -2
- package/dest/account_impl/single_key_account_contract.d.ts +23 -0
- package/dest/account_impl/single_key_account_contract.d.ts.map +1 -0
- package/dest/account_impl/single_key_account_contract.js +66 -0
- package/dest/account_impl/stored_key_account_contract.d.ts +22 -0
- package/dest/account_impl/stored_key_account_contract.d.ts.map +1 -0
- package/dest/account_impl/stored_key_account_contract.js +65 -0
- package/dest/aztec_rpc_client/aztec_rpc_client.d.ts +2 -1
- package/dest/aztec_rpc_client/aztec_rpc_client.d.ts.map +1 -1
- package/dest/aztec_rpc_client/aztec_rpc_client.js +5 -5
- package/dest/aztec_rpc_client/wallet.d.ts +8 -6
- package/dest/aztec_rpc_client/wallet.d.ts.map +1 -1
- package/dest/aztec_rpc_client/wallet.js +19 -10
- package/dest/contract/contract.d.ts +3 -4
- package/dest/contract/contract.d.ts.map +1 -1
- package/dest/contract/contract.js +1 -1
- package/dest/contract/contract.test.js +3 -3
- package/dest/contract/contract_function_interaction.d.ts +1 -1
- package/dest/contract/contract_function_interaction.d.ts.map +1 -1
- package/dest/contract/contract_function_interaction.js +6 -6
- package/dest/contract_deployer/contract_deployer.d.ts.map +1 -1
- package/dest/contract_deployer/contract_deployer.js +2 -1
- package/dest/contract_deployer/contract_deployer.test.js +3 -3
- package/dest/contract_deployer/deploy_method.d.ts.map +1 -1
- package/dest/contract_deployer/deploy_method.js +5 -13
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -2
- package/dest/utils/account.d.ts +3 -2
- package/dest/utils/account.d.ts.map +1 -1
- package/dest/utils/account.js +13 -17
- package/dest/utils/l1_contracts.d.ts +8 -0
- package/dest/utils/l1_contracts.d.ts.map +1 -1
- package/dest/utils/l1_contracts.js +10 -2
- package/package.json +4 -5
- package/src/abis/ecdsa_account_contract.json +150 -0
- package/src/abis/schnorr_account_contract.json +96 -0
- package/src/abis/schnorr_single_key_account_contract.json +96 -0
- package/src/account_impl/account_collection.ts +1 -0
- package/src/account_impl/entrypoint_payload.ts +76 -0
- package/src/account_impl/index.ts +2 -1
- package/src/account_impl/single_key_account_contract.ts +82 -0
- package/src/account_impl/stored_key_account_contract.ts +80 -0
- package/src/aztec_rpc_client/aztec_rpc_client.ts +6 -4
- package/src/aztec_rpc_client/wallet.ts +22 -15
- package/src/contract/contract.test.ts +5 -3
- package/src/contract/contract.ts +4 -3
- package/src/contract/contract_function_interaction.ts +4 -4
- package/src/contract_deployer/contract_deployer.test.ts +4 -3
- package/src/contract_deployer/contract_deployer.ts +1 -0
- package/src/contract_deployer/deploy_method.ts +5 -17
- package/src/index.ts +1 -1
- package/src/utils/account.ts +19 -35
- package/src/utils/l1_contracts.ts +21 -1
- package/tsconfig.json +1 -4
- package/dest/account_impl/account_contract.d.ts +0 -44
- package/dest/account_impl/account_contract.d.ts.map +0 -1
- package/dest/account_impl/account_contract.js +0 -107
- package/dest/auth/ecdsa.d.ts +0 -13
- package/dest/auth/ecdsa.d.ts.map +0 -1
- package/dest/auth/ecdsa.js +0 -17
- package/dest/auth/index.d.ts +0 -19
- package/dest/auth/index.d.ts.map +0 -1
- package/dest/auth/index.js +0 -14
- package/dest/auth/schnorr.d.ts +0 -13
- package/dest/auth/schnorr.d.ts.map +0 -1
- package/dest/auth/schnorr.js +0 -14
- package/src/account_impl/account_contract.ts +0 -171
- package/src/auth/ecdsa.ts +0 -18
- package/src/auth/index.ts +0 -25
- 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
|
-
|
|
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
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
): Promise<
|
|
40
|
-
return this.rpc.
|
|
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
|
-
|
|
46
|
-
return this.rpc.
|
|
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
|
|
58
|
-
return this.rpc.simulateTx(txRequest
|
|
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 {
|
|
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>;
|
package/src/contract/contract.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
|
@@ -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
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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';
|
package/src/utils/account.ts
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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(
|
|
36
|
-
await aztecRpcClient.addAccount(privKey, deploymentInfo.address, deploymentInfo.partialAddress
|
|
37
|
-
const contractDeployer = new ContractDeployer(
|
|
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
|
|
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(
|
|
73
|
-
|
|
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
|
|
77
|
-
const
|
|
67
|
+
const deploymentInfo = await getContractDeploymentInfo(accountContractAbi, [], salt, publicKey);
|
|
68
|
+
const address = deploymentInfo.address;
|
|
78
69
|
|
|
79
70
|
accountCollection.registerAccount(
|
|
80
71
|
address,
|
|
81
|
-
new
|
|
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 =
|
|
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
|
@@ -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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
|