@aztec/aztec.js 0.47.1 → 0.49.2

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 (56) hide show
  1. package/dest/api/fee.d.ts +2 -2
  2. package/dest/api/fee.d.ts.map +1 -1
  3. package/dest/api/fee.js +3 -3
  4. package/dest/contract/base_contract_interaction.d.ts +1 -1
  5. package/dest/contract/base_contract_interaction.d.ts.map +1 -1
  6. package/dest/contract/contract_function_interaction.d.ts +2 -0
  7. package/dest/contract/contract_function_interaction.d.ts.map +1 -1
  8. package/dest/contract/contract_function_interaction.js +2 -2
  9. package/dest/contract/sent_tx.d.ts +6 -0
  10. package/dest/contract/sent_tx.d.ts.map +1 -1
  11. package/dest/contract/sent_tx.js +12 -1
  12. package/dest/entrypoint/payload.js +3 -3
  13. package/dest/fee/{native_fee_payment_method.d.ts → fee_juice_payment_method.d.ts} +3 -3
  14. package/dest/fee/fee_juice_payment_method.d.ts.map +1 -0
  15. package/dest/fee/fee_juice_payment_method.js +19 -0
  16. package/dest/fee/{native_fee_payment_method_with_claim.d.ts → fee_juice_payment_method_with_claim.d.ts} +5 -5
  17. package/dest/fee/fee_juice_payment_method_with_claim.d.ts.map +1 -0
  18. package/dest/fee/fee_juice_payment_method_with_claim.js +32 -0
  19. package/dest/index.d.ts +2 -2
  20. package/dest/index.d.ts.map +1 -1
  21. package/dest/index.js +3 -3
  22. package/dest/rpc_clients/index.d.ts +1 -0
  23. package/dest/rpc_clients/index.d.ts.map +1 -1
  24. package/dest/rpc_clients/index.js +2 -1
  25. package/dest/rpc_clients/node/index.d.ts +11 -0
  26. package/dest/rpc_clients/node/index.d.ts.map +1 -0
  27. package/dest/rpc_clients/node/index.js +62 -0
  28. package/dest/rpc_clients/pxe_client.d.ts.map +1 -1
  29. package/dest/rpc_clients/pxe_client.js +5 -2
  30. package/dest/utils/authwit.js +4 -4
  31. package/dest/utils/cheat_codes.d.ts +15 -6
  32. package/dest/utils/cheat_codes.d.ts.map +1 -1
  33. package/dest/utils/cheat_codes.js +34 -18
  34. package/dest/wallet/account_wallet.js +2 -2
  35. package/dest/wallet/base_wallet.d.ts +7 -6
  36. package/dest/wallet/base_wallet.d.ts.map +1 -1
  37. package/dest/wallet/base_wallet.js +10 -10
  38. package/package.json +8 -7
  39. package/src/api/fee.ts +2 -2
  40. package/src/contract/contract_function_interaction.ts +3 -1
  41. package/src/contract/sent_tx.ts +21 -0
  42. package/src/entrypoint/payload.ts +2 -2
  43. package/src/fee/{native_fee_payment_method.ts → fee_juice_payment_method.ts} +4 -4
  44. package/src/fee/{native_fee_payment_method_with_claim.ts → fee_juice_payment_method_with_claim.ts} +6 -6
  45. package/src/index.ts +2 -1
  46. package/src/rpc_clients/index.ts +1 -0
  47. package/src/rpc_clients/node/index.ts +69 -0
  48. package/src/rpc_clients/pxe_client.ts +4 -0
  49. package/src/utils/authwit.ts +3 -3
  50. package/src/utils/cheat_codes.ts +35 -17
  51. package/src/wallet/account_wallet.ts +1 -1
  52. package/src/wallet/base_wallet.ts +17 -11
  53. package/dest/fee/native_fee_payment_method.d.ts.map +0 -1
  54. package/dest/fee/native_fee_payment_method.js +0 -19
  55. package/dest/fee/native_fee_payment_method_with_claim.d.ts.map +0 -1
  56. package/dest/fee/native_fee_payment_method_with_claim.js +0 -32
@@ -0,0 +1,69 @@
1
+ import { type PXE } from '@aztec/circuit-types';
2
+ import { type DebugLogger } from '@aztec/foundation/log';
3
+ import { NoRetryError } from '@aztec/foundation/retry';
4
+
5
+ import axios, { type AxiosError, type AxiosResponse } from 'axios';
6
+
7
+ import { createPXEClient } from '../pxe_client.js';
8
+
9
+ /**
10
+ * A fetch implementation using axios.
11
+ * @param host - The URL of the host.
12
+ * @param rpcMethod - The RPC method to call.
13
+ * @param body - The body of the request.
14
+ * @param useApiEndpoints - Whether to use the API endpoints or inject the method in the body.
15
+ * @param _noRetry - Whether to retry on non-server errors.
16
+ * @returns The response data.
17
+ */
18
+ async function axiosFetch(host: string, rpcMethod: string, body: any, useApiEndpoints: boolean, _noRetry = true) {
19
+ let resp: AxiosResponse;
20
+ if (useApiEndpoints) {
21
+ resp = await axios
22
+ .post(`${host}/${rpcMethod}`, body, {
23
+ headers: { 'content-type': 'application/json' },
24
+ })
25
+ .catch((error: AxiosError) => {
26
+ if (error.response) {
27
+ return error.response;
28
+ }
29
+ throw error;
30
+ });
31
+ } else {
32
+ resp = await axios
33
+ .post(
34
+ host,
35
+ { ...body, method: rpcMethod },
36
+ {
37
+ headers: { 'content-type': 'application/json' },
38
+ },
39
+ )
40
+ .catch((error: AxiosError) => {
41
+ if (error.response) {
42
+ return error.response;
43
+ }
44
+ throw error;
45
+ });
46
+ }
47
+
48
+ const isOK = resp.status >= 200 && resp.status < 300;
49
+ if (isOK) {
50
+ return resp.data;
51
+ } else if (resp.status >= 400 && resp.status < 500) {
52
+ throw new NoRetryError('(JSON-RPC PROPAGATED) ' + resp.data.error.message);
53
+ } else {
54
+ throw new Error('(JSON-RPC PROPAGATED) ' + resp.data.error.message);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Creates a PXE client with a given set of retries on non-server errors.
60
+ * Checks that PXE matches the expected version, and warns if not.
61
+ * @param rpcUrl - URL of the RPC server wrapping the PXE.
62
+ * @param _logger - Debug logger to warn version incompatibilities.
63
+ * @returns A PXE client.
64
+ */
65
+ export function createCompatibleClient(rpcUrl: string, _logger: DebugLogger): Promise<PXE> {
66
+ // Use axios due to timeout issues with fetch when proving TXs.
67
+ const pxe = createPXEClient(rpcUrl, axiosFetch);
68
+ return Promise.resolve(pxe);
69
+ }
@@ -15,6 +15,7 @@ import {
15
15
  TxHash,
16
16
  TxReceipt,
17
17
  UnencryptedL2BlockL2Logs,
18
+ UniqueNote,
18
19
  } from '@aztec/circuit-types';
19
20
  import {
20
21
  AztecAddress,
@@ -26,6 +27,7 @@ import {
26
27
  Point,
27
28
  } from '@aztec/circuits.js';
28
29
  import { NoteSelector } from '@aztec/foundation/abi';
30
+ import { BaseHashType } from '@aztec/foundation/hash';
29
31
  import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client';
30
32
 
31
33
  /**
@@ -44,6 +46,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false)
44
46
  FunctionSelector,
45
47
  EthAddress,
46
48
  ExtendedNote,
49
+ UniqueNote,
47
50
  ExtendedUnencryptedL2Log,
48
51
  Fr,
49
52
  GrumpkinScalar,
@@ -54,6 +57,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false)
54
57
  Point,
55
58
  TxExecutionRequest,
56
59
  TxHash,
60
+ BaseHashType,
57
61
  },
58
62
  {
59
63
  EncryptedNoteL2BlockL2Logs,
@@ -1,6 +1,6 @@
1
1
  import { type FunctionCall, PackedValues } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, Fr, GeneratorIndex } from '@aztec/circuits.js';
3
- import { pedersenHash } from '@aztec/foundation/crypto';
3
+ import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
4
4
 
5
5
  import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js';
6
6
 
@@ -81,7 +81,7 @@ export const computeInnerAuthWitHashFromAction = (caller: AztecAddress, action:
81
81
  * @returns The inner hash for the witness
82
82
  */
83
83
  export const computeInnerAuthWitHash = (args: Fr[]) => {
84
- return pedersenHash(args, GeneratorIndex.AUTHWIT_INNER);
84
+ return poseidon2HashWithSeparator(args, GeneratorIndex.AUTHWIT_INNER);
85
85
  };
86
86
 
87
87
  /**
@@ -99,5 +99,5 @@ export const computeInnerAuthWitHash = (args: Fr[]) => {
99
99
  * @returns The outer hash for the witness
100
100
  */
101
101
  const computeOuterAuthWitHash = (consumer: AztecAddress, chainId: Fr, version: Fr, innerHash: Fr) => {
102
- return pedersenHash([consumer.toField(), chainId, version, innerHash], GeneratorIndex.AUTHWIT_OUTER);
102
+ return poseidon2HashWithSeparator([consumer.toField(), chainId, version, innerHash], GeneratorIndex.AUTHWIT_OUTER);
103
103
  };
@@ -1,7 +1,8 @@
1
1
  import { type Note, type PXE } from '@aztec/circuit-types';
2
2
  import { type AztecAddress, type EthAddress, Fr } from '@aztec/circuits.js';
3
+ import { deriveStorageSlotInMap } from '@aztec/circuits.js/hash';
3
4
  import { toBigIntBE, toHex } from '@aztec/foundation/bigint-buffer';
4
- import { keccak256, pedersenHash } from '@aztec/foundation/crypto';
5
+ import { keccak256 } from '@aztec/foundation/crypto';
5
6
  import { createDebugLogger } from '@aztec/foundation/log';
6
7
 
7
8
  import fs from 'fs';
@@ -93,6 +94,18 @@ export class EthCheatCodes {
93
94
  this.logger.info(`Mined ${numberOfBlocks} blocks`);
94
95
  }
95
96
 
97
+ /**
98
+ * Set the interval between blocks (block time)
99
+ * @param interval - The interval to use between blocks
100
+ */
101
+ public async setBlockInterval(interval: number): Promise<void> {
102
+ const res = await this.rpcCall('anvil_setBlockTimestampInterval', [interval]);
103
+ if (res.error) {
104
+ throw new Error(`Error setting block interval: ${res.error.message}`);
105
+ }
106
+ this.logger.info(`Set block interval to ${interval}`);
107
+ }
108
+
96
109
  /**
97
110
  * Set the next block timestamp
98
111
  * @param timestamp - The timestamp to set the next block to
@@ -105,6 +118,19 @@ export class EthCheatCodes {
105
118
  this.logger.info(`Set next block timestamp to ${timestamp}`);
106
119
  }
107
120
 
121
+ /**
122
+ * Set the next block timestamp and mines the block
123
+ * @param timestamp - The timestamp to set the next block to
124
+ */
125
+ public async warp(timestamp: number): Promise<void> {
126
+ const res = await this.rpcCall('evm_setNextBlockTimestamp', [timestamp]);
127
+ if (res.error) {
128
+ throw new Error(`Error warping: ${res.error.message}`);
129
+ }
130
+ await this.mine();
131
+ this.logger.info(`Warped to ${timestamp}`);
132
+ }
133
+
108
134
  /**
109
135
  * Dumps the current chain state to a file.
110
136
  * @param fileName - The file name to dump state into
@@ -239,14 +265,12 @@ export class AztecCheatCodes {
239
265
 
240
266
  /**
241
267
  * Computes the slot value for a given map and key.
242
- * @param baseSlot - The base slot of the map (specified in Aztec.nr contract)
268
+ * @param mapSlot - The slot of the map (specified in Aztec.nr contract)
243
269
  * @param key - The key to lookup in the map
244
270
  * @returns The storage slot of the value in the map
245
271
  */
246
- public computeSlotInMap(baseSlot: Fr | bigint, key: Fr | bigint | AztecAddress): Fr {
247
- // Based on `at` function in
248
- // aztec3-packages/aztec-nr/aztec/src/state_vars/map.nr
249
- return pedersenHash([new Fr(baseSlot), new Fr(key)]);
272
+ public computeSlotInMap(mapSlot: Fr | bigint, key: Fr | bigint | AztecAddress): Fr {
273
+ return deriveStorageSlotInMap(mapSlot, new Fr(key));
250
274
  }
251
275
 
252
276
  /**
@@ -258,18 +282,12 @@ export class AztecCheatCodes {
258
282
  }
259
283
 
260
284
  /**
261
- * Set time of the next execution on aztec.
262
- * It also modifies time on eth for next execution and stores this time as the last rollup block on the rollup contract.
263
- * @param to - The timestamp to set the next block to (must be greater than current time)
285
+ * Get the current timestamp
286
+ * @returns The current timestamp
264
287
  */
265
- public async warp(to: number): Promise<void> {
266
- const rollupContract = (await this.pxe.getNodeInfo()).l1ContractAddresses.rollupAddress;
267
- await this.eth.setNextBlockTimestamp(to);
268
- // also store this time on the rollup contract (slot 2 tracks `lastBlockTs`).
269
- // This is because when the sequencer executes public functions, it uses the timestamp stored in the rollup contract.
270
- await this.eth.store(rollupContract, 7n, BigInt(to));
271
- // also store this on slot of the rollup contract (`lastWarpedBlockTs`) which tracks the last time warp was used.
272
- await this.eth.store(rollupContract, 8n, BigInt(to));
288
+ public async timestamp(): Promise<number> {
289
+ const res = await this.pxe.getBlock(await this.blockNumber());
290
+ return res?.header.globalVariables.timestamp.toNumber() ?? 0;
273
291
  }
274
292
 
275
293
  /**
@@ -19,7 +19,7 @@ import { BaseWallet } from './base_wallet.js';
19
19
  */
20
20
  export class AccountWallet extends BaseWallet {
21
21
  constructor(pxe: PXE, protected account: AccountInterface) {
22
- super(pxe);
22
+ super(pxe, [account.getAddress()]);
23
23
  }
24
24
 
25
25
  createTxExecutionRequest(exec: ExecutionRequestInit): Promise<TxExecutionRequest> {
@@ -17,6 +17,7 @@ import {
17
17
  type TxExecutionRequest,
18
18
  type TxHash,
19
19
  type TxReceipt,
20
+ type UniqueNote,
20
21
  } from '@aztec/circuit-types';
21
22
  import { type NoteProcessorStats } from '@aztec/circuit-types/stats';
22
23
  import {
@@ -39,7 +40,7 @@ import { type IntentAction, type IntentInnerHash } from '../utils/authwit.js';
39
40
  * A base class for Wallet implementations
40
41
  */
41
42
  export abstract class BaseWallet implements Wallet {
42
- constructor(protected readonly pxe: PXE) {}
43
+ constructor(protected readonly pxe: PXE, private scopes?: AztecAddress[]) {}
43
44
 
44
45
  abstract getCompleteAddress(): CompleteAddress;
45
46
 
@@ -53,6 +54,10 @@ export abstract class BaseWallet implements Wallet {
53
54
 
54
55
  abstract rotateNullifierKeys(newNskM: Fq): Promise<void>;
55
56
 
57
+ setScopes(scopes: AztecAddress[]) {
58
+ this.scopes = scopes;
59
+ }
60
+
56
61
  getAddress() {
57
62
  return this.getCompleteAddress().address;
58
63
  }
@@ -102,10 +107,15 @@ export abstract class BaseWallet implements Wallet {
102
107
  return this.pxe.getContracts();
103
108
  }
104
109
  proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx> {
105
- return this.pxe.proveTx(txRequest, simulatePublic);
110
+ return this.pxe.proveTx(txRequest, simulatePublic, this.scopes);
106
111
  }
107
- simulateTx(txRequest: TxExecutionRequest, simulatePublic: boolean, msgSender?: AztecAddress): Promise<SimulatedTx> {
108
- return this.pxe.simulateTx(txRequest, simulatePublic, msgSender);
112
+ simulateTx(
113
+ txRequest: TxExecutionRequest,
114
+ simulatePublic: boolean,
115
+ msgSender?: AztecAddress,
116
+ skipTxValidation?: boolean,
117
+ ): Promise<SimulatedTx> {
118
+ return this.pxe.simulateTx(txRequest, simulatePublic, msgSender, skipTxValidation, this.scopes);
109
119
  }
110
120
  sendTx(tx: Tx): Promise<TxHash> {
111
121
  return this.pxe.sendTx(tx);
@@ -116,21 +126,17 @@ export abstract class BaseWallet implements Wallet {
116
126
  getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
117
127
  return this.pxe.getTxReceipt(txHash);
118
128
  }
119
- getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
129
+ getIncomingNotes(filter: IncomingNotesFilter): Promise<UniqueNote[]> {
120
130
  return this.pxe.getIncomingNotes(filter);
121
131
  }
122
- getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]> {
132
+ getOutgoingNotes(filter: OutgoingNotesFilter): Promise<UniqueNote[]> {
123
133
  return this.pxe.getOutgoingNotes(filter);
124
134
  }
125
- // TODO(#4956): Un-expose this
126
- getNoteNonces(note: ExtendedNote): Promise<Fr[]> {
127
- return this.pxe.getNoteNonces(note);
128
- }
129
135
  getPublicStorageAt(contract: AztecAddress, storageSlot: Fr): Promise<any> {
130
136
  return this.pxe.getPublicStorageAt(contract, storageSlot);
131
137
  }
132
138
  addNote(note: ExtendedNote): Promise<void> {
133
- return this.pxe.addNote(note);
139
+ return this.pxe.addNote(note, this.getAddress());
134
140
  }
135
141
  addNullifiedNote(note: ExtendedNote): Promise<void> {
136
142
  return this.pxe.addNullifiedNote(note);
@@ -1 +0,0 @@
1
- {"version":3,"file":"native_fee_payment_method.d.ts","sourceRoot":"","sources":["../../src/fee/native_fee_payment_method.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;GAEG;AACH,qBAAa,sBAAuB,YAAW,gBAAgB;IACjD,SAAS,CAAC,MAAM,EAAE,YAAY;gBAApB,MAAM,EAAE,YAAY;IAE1C,QAAQ;IAIR,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI3C,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;CAGrC"}
@@ -1,19 +0,0 @@
1
- import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
2
- /**
3
- * Pay fee directly in the native gas token.
4
- */
5
- export class NativeFeePaymentMethod {
6
- constructor(sender) {
7
- this.sender = sender;
8
- }
9
- getAsset() {
10
- return GasTokenAddress;
11
- }
12
- getFunctionCalls() {
13
- return Promise.resolve([]);
14
- }
15
- getFeePayer() {
16
- return Promise.resolve(this.sender);
17
- }
18
- }
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX2ZlZV9wYXltZW50X21ldGhvZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mZWUvbmF0aXZlX2ZlZV9wYXltZW50X21ldGhvZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFJdEU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sc0JBQXNCO0lBQ2pDLFlBQXNCLE1BQW9CO1FBQXBCLFdBQU0sR0FBTixNQUFNLENBQWM7SUFBRyxDQUFDO0lBRTlDLFFBQVE7UUFDTixPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFFRCxXQUFXO1FBQ1QsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN0QyxDQUFDO0NBQ0YifQ==
@@ -1 +0,0 @@
1
- {"version":3,"file":"native_fee_payment_method_with_claim.d.ts","sourceRoot":"","sources":["../../src/fee/native_fee_payment_method_with_claim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAE,EAAE,EAAoB,MAAM,oBAAoB,CAAC;AAI7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE;;GAEG;AACH,qBAAa,+BAAgC,SAAQ,sBAAsB;IACvC,OAAO,CAAC,WAAW;IAAe,OAAO,CAAC,WAAW;gBAA3E,MAAM,EAAE,YAAY,EAAU,WAAW,EAAE,MAAM,GAAG,EAAE,EAAU,WAAW,EAAE,EAAE;IAI3F;;;OAGG;IACM,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAarD"}
@@ -1,32 +0,0 @@
1
- import { Fr, FunctionSelector } from '@aztec/circuits.js';
2
- import { FunctionType } from '@aztec/foundation/abi';
3
- import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token';
4
- import { NativeFeePaymentMethod } from './native_fee_payment_method.js';
5
- /**
6
- * Pay fee directly with native gas token claimed on the same tx.
7
- */
8
- export class NativeFeePaymentMethodWithClaim extends NativeFeePaymentMethod {
9
- constructor(sender, claimAmount, claimSecret) {
10
- super(sender);
11
- this.claimAmount = claimAmount;
12
- this.claimSecret = claimSecret;
13
- }
14
- /**
15
- * Creates a function call to pay the fee in gas token.
16
- * @returns A function call
17
- */
18
- getFunctionCalls() {
19
- return Promise.resolve([
20
- {
21
- to: GasTokenAddress,
22
- name: 'claim',
23
- selector: FunctionSelector.fromSignature('claim((Field),Field,Field)'),
24
- isStatic: false,
25
- args: [this.sender, new Fr(this.claimAmount), this.claimSecret],
26
- returnTypes: [],
27
- type: FunctionType.PRIVATE,
28
- },
29
- ]);
30
- }
31
- }
32
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmF0aXZlX2ZlZV9wYXltZW50X21ldGhvZF93aXRoX2NsYWltLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZlZS9uYXRpdmVfZmVlX3BheW1lbnRfbWV0aG9kX3dpdGhfY2xhaW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFxQixFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM3RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBRXRFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXhFOztHQUVHO0FBQ0gsTUFBTSxPQUFPLCtCQUFnQyxTQUFRLHNCQUFzQjtJQUN6RSxZQUFZLE1BQW9CLEVBQVUsV0FBd0IsRUFBVSxXQUFlO1FBQ3pGLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUQwQixnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUFVLGdCQUFXLEdBQVgsV0FBVyxDQUFJO0lBRTNGLENBQUM7SUFFRDs7O09BR0c7SUFDTSxnQkFBZ0I7UUFDdkIsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDO1lBQ3JCO2dCQUNFLEVBQUUsRUFBRSxlQUFlO2dCQUNuQixJQUFJLEVBQUUsT0FBTztnQkFDYixRQUFRLEVBQUUsZ0JBQWdCLENBQUMsYUFBYSxDQUFDLDRCQUE0QixDQUFDO2dCQUN0RSxRQUFRLEVBQUUsS0FBSztnQkFDZixJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDO2dCQUMvRCxXQUFXLEVBQUUsRUFBRTtnQkFDZixJQUFJLEVBQUUsWUFBWSxDQUFDLE9BQU87YUFDM0I7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0YifQ==