@aboutcircles/sdk-utils 0.1.5 → 0.1.7

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/dist/abi.d.ts CHANGED
@@ -28,4 +28,28 @@ export declare function decodeErrorResult(config: {
28
28
  errorName: string;
29
29
  args?: any[];
30
30
  } | null;
31
+ /**
32
+ * IMPORTANT: This is a lightweight encoding utility for SIMPLE cases only.
33
+ * It supports basic types: address, bytes, uint*, int*, bool, string
34
+ *
35
+ * For complex use cases with tuples, nested arrays, or advanced types,
36
+ * use viem's encodeAbiParameters instead.
37
+ *
38
+ * This function is provided to avoid bundling the entire viem library
39
+ * for simple encoding scenarios like encoding (address, bytes) tuples.
40
+ *
41
+ * @param types - Array of parameter types (e.g., ['address', 'bytes'])
42
+ * @param values - Array of values to encode
43
+ * @returns Hex-encoded parameters with 0x prefix
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // Encode (address, bytes) tuple
48
+ * const encoded = encodeAbiParameters(
49
+ * ['address', 'bytes'],
50
+ * ['0x1234...', '0xabcd...']
51
+ * );
52
+ * ```
53
+ */
54
+ export declare function encodeAbiParameters(types: string[], values: unknown[]): Hex;
31
55
  //# sourceMappingURL=abi.d.ts.map
package/dist/abi.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../src/abi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAe,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAwCnD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASvD;AAoXD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3B,GAAG,GAAG,CA+DN;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CA0CV;AAmBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;CACd,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,GAAG,IAAI,CA+C7C"}
1
+ {"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../src/abi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAe,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAwCnD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASvD;AAoXD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3B,GAAG,GAAG,CA+DN;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CA0CV;AAmBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;CACd,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,GAAG,IAAI,CA+C7C;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CA+C3E"}
package/dist/abi.js CHANGED
@@ -446,3 +446,68 @@ export function decodeErrorResult(config) {
446
446
  }
447
447
  return null; // No matching error found
448
448
  }
449
+ // ============================================================================
450
+ // SIMPLE ABI PARAMETER ENCODING (LIMITED USE CASE)
451
+ // ============================================================================
452
+ /**
453
+ * IMPORTANT: This is a lightweight encoding utility for SIMPLE cases only.
454
+ * It supports basic types: address, bytes, uint*, int*, bool, string
455
+ *
456
+ * For complex use cases with tuples, nested arrays, or advanced types,
457
+ * use viem's encodeAbiParameters instead.
458
+ *
459
+ * This function is provided to avoid bundling the entire viem library
460
+ * for simple encoding scenarios like encoding (address, bytes) tuples.
461
+ *
462
+ * @param types - Array of parameter types (e.g., ['address', 'bytes'])
463
+ * @param values - Array of values to encode
464
+ * @returns Hex-encoded parameters with 0x prefix
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * // Encode (address, bytes) tuple
469
+ * const encoded = encodeAbiParameters(
470
+ * ['address', 'bytes'],
471
+ * ['0x1234...', '0xabcd...']
472
+ * );
473
+ * ```
474
+ */
475
+ export function encodeAbiParameters(types, values) {
476
+ if (types.length !== values.length) {
477
+ throw new Error(`Type/value length mismatch: ${types.length} types, ${values.length} values`);
478
+ }
479
+ const encodings = [];
480
+ const dynamicData = [];
481
+ const isDynamic = [];
482
+ // First pass: encode all parameters
483
+ for (let i = 0; i < types.length; i++) {
484
+ const type = types[i];
485
+ const dynamic = isDynamicType(type);
486
+ isDynamic.push(dynamic);
487
+ if (dynamic) {
488
+ encodings.push('');
489
+ dynamicData.push(encodeParam(type, values[i]));
490
+ }
491
+ else {
492
+ encodings.push(encodeParam(type, values[i]));
493
+ }
494
+ }
495
+ // Second pass: calculate offsets and build result
496
+ if (dynamicData.length === 0) {
497
+ return ('0x' + encodings.join(''));
498
+ }
499
+ let offset = encodings.reduce((sum, enc, i) => sum + (isDynamic[i] ? BYTES_PER_WORD : enc.length / 2), 0);
500
+ let result = '';
501
+ let dynamicIndex = 0;
502
+ for (let i = 0; i < types.length; i++) {
503
+ if (isDynamic[i]) {
504
+ result += toHex64(offset);
505
+ offset += dynamicData[dynamicIndex].length / 2;
506
+ dynamicIndex++;
507
+ }
508
+ else {
509
+ result += encodings[i];
510
+ }
511
+ }
512
+ return ('0x' + result + dynamicData.join(''));
513
+ }
package/dist/bytes.d.ts CHANGED
@@ -2,4 +2,8 @@
2
2
  * Convert a Uint8Array to a hex string with 0x prefix
3
3
  */
4
4
  export declare function bytesToHex(bytes: Uint8Array): string;
5
+ /**
6
+ * Convert a hex string (with or without 0x prefix) to a Uint8Array
7
+ */
8
+ export declare function hexToBytes(hex: string): Uint8Array;
5
9
  //# sourceMappingURL=bytes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMpD"}
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CASlD"}
package/dist/bytes.js CHANGED
@@ -13,3 +13,14 @@ export function bytesToHex(bytes) {
13
13
  }
14
14
  return hex;
15
15
  }
16
+ /**
17
+ * Convert a hex string (with or without 0x prefix) to a Uint8Array
18
+ */
19
+ export function hexToBytes(hex) {
20
+ const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
21
+ const bytes = new Uint8Array(cleanHex.length / 2);
22
+ for (let i = 0; i < cleanHex.length; i += 2) {
23
+ bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
24
+ }
25
+ return bytes;
26
+ }
@@ -0,0 +1,11 @@
1
+ import type { CirclesConfig } from '@aboutcircles/sdk-types';
2
+ /**
3
+ * Default Circles configurations by chain ID
4
+ *
5
+ * Chain IDs:
6
+ * - 100: Gnosis Chain (mainnet)
7
+ */
8
+ export declare const circlesConfig: {
9
+ [chainId: number]: CirclesConfig;
10
+ };
11
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE;IAAE,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAA;CAmB7D,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Default Circles configurations by chain ID
3
+ *
4
+ * Chain IDs:
5
+ * - 100: Gnosis Chain (mainnet)
6
+ */
7
+ export const circlesConfig = {
8
+ 100: {
9
+ circlesRpcUrl: "https://rpc.aboutcircles.com/",
10
+ pathfinderUrl: "https://pathfinder.aboutcircles.com",
11
+ profileServiceUrl: "https://rpc.aboutcircles.com/profiles/",
12
+ referralsServiceUrl: "https://staging.circlesubi.network/referrals",
13
+ v1HubAddress: "0x29b9a7fbb8995b2423a71cc17cf9810798f6c543",
14
+ v2HubAddress: "0xc12C1E50ABB450d6205Ea2C3Fa861b3B834d13e8",
15
+ nameRegistryAddress: "0xA27566fD89162cC3D40Cb59c87AAaA49B85F3474",
16
+ baseGroupMintPolicy: "0xcCa27c26CF7BAC2a9928f42201d48220F0e3a549",
17
+ standardTreasury: "0x08F90aB73A515308f03A718257ff9887ED330C6e",
18
+ coreMembersGroupDeployer: "0xFEca40Eb02FB1f4F5F795fC7a03c1A27819B1Ded",
19
+ baseGroupFactoryAddress: "0xD0B5Bd9962197BEaC4cbA24244ec3587f19Bd06d",
20
+ liftERC20Address: "0x5F99a795dD2743C36D63511f0D4bc667e6d3cDB5",
21
+ invitationEscrowAddress: "0x8F8B74fa13eaaff4176D061a0F98ad5c8E19c903",
22
+ invitationFarmAddress: "0x0000000000000000000000000000000000000000",
23
+ referralsModuleAddress: "0xd6dF7cc2C2DB03ec91761f4469D8dBAac7e538C9",
24
+ invitationModuleAddress: "0x00738aca013B7B2e6cfE1690F0021C3182Fa40B5"
25
+ }
26
+ };
@@ -6,4 +6,25 @@ import type { Address } from '@aboutcircles/sdk-types';
6
6
  * The zero address (0x0000000000000000000000000000000000000000)
7
7
  */
8
8
  export declare const ZERO_ADDRESS: Address;
9
+ /**
10
+ * The invitation fee required to invite a new user (96 CRC)
11
+ */
12
+ export declare const INVITATION_FEE: bigint;
13
+ /**
14
+ * Maximum target flow value used for pathfinding to find the maximum possible flow
15
+ * This represents an extremely large number that effectively means "find max flow"
16
+ */
17
+ export declare const MAX_FLOW: bigint;
18
+ /**
19
+ * Safe Proxy Factory address used to deploy Safe proxies
20
+ */
21
+ export declare const SAFE_PROXY_FACTORY: Address;
22
+ /**
23
+ * Hash of the account initializer used in CREATE2 salt calculation
24
+ */
25
+ export declare const ACCOUNT_INITIALIZER_HASH: `0x${string}`;
26
+ /**
27
+ * Hash of the account creation code used in CREATE2 address calculation
28
+ */
29
+ export declare const ACCOUNT_CREATION_CODE_HASH: `0x${string}`;
9
30
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,OAAsD,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,OAAsD,CAAC;AAElF;;GAEG;AACH,eAAO,MAAM,cAAc,QAAgC,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,OAAsD,CAAC;AAExF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,MAAM,EAAyE,CAAC;AAE5H;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,KAAK,MAAM,EAAyE,CAAC"}
package/dist/constants.js CHANGED
@@ -5,3 +5,24 @@
5
5
  * The zero address (0x0000000000000000000000000000000000000000)
6
6
  */
7
7
  export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
8
+ /**
9
+ * The invitation fee required to invite a new user (96 CRC)
10
+ */
11
+ export const INVITATION_FEE = BigInt(96) * BigInt(10 ** 18);
12
+ /**
13
+ * Maximum target flow value used for pathfinding to find the maximum possible flow
14
+ * This represents an extremely large number that effectively means "find max flow"
15
+ */
16
+ export const MAX_FLOW = BigInt('9999999999999999999999999999999999999');
17
+ /**
18
+ * Safe Proxy Factory address used to deploy Safe proxies
19
+ */
20
+ export const SAFE_PROXY_FACTORY = '0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67';
21
+ /**
22
+ * Hash of the account initializer used in CREATE2 salt calculation
23
+ */
24
+ export const ACCOUNT_INITIALIZER_HASH = '0x440ea2f93c9703f7d456d48796f7bc25b8721582535a492ce0a09df32146242a';
25
+ /**
26
+ * Hash of the account creation code used in CREATE2 address calculation
27
+ */
28
+ export const ACCOUNT_CREATION_CODE_HASH = '0xe298282cefe913ab5d282047161268a8222e4bd4ed106300c547894bbefd31ee';
@@ -0,0 +1,19 @@
1
+ import type { Address, Hex } from '@aboutcircles/sdk-types';
2
+ /**
3
+ * Generate a random private key (32 bytes / 64 hex chars)
4
+ * @returns Private key as hex string with 0x prefix
5
+ */
6
+ export declare function generatePrivateKey(): Hex;
7
+ /**
8
+ * Derive Ethereum address from private key
9
+ * @param privateKey - Private key as hex string (with or without 0x prefix)
10
+ * @returns Checksummed Ethereum address
11
+ */
12
+ export declare function privateKeyToAddress(privateKey: string): Address;
13
+ /**
14
+ * Calculate keccak256 hash of data
15
+ * @param data - Hex string or Uint8Array to hash
16
+ * @returns Hash as hex string with 0x prefix
17
+ */
18
+ export declare function keccak256(data: Hex | Uint8Array): Hex;
19
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAG5D;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,GAAG,CAGxC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAe/D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,GAAG,UAAU,GAAG,GAAG,CAYrD"}
package/dist/crypto.js ADDED
@@ -0,0 +1,45 @@
1
+ import { secp256k1 } from '@noble/curves/secp256k1';
2
+ import { keccak_256 } from '@noble/hashes/sha3';
3
+ import { checksumAddress } from './abi';
4
+ /**
5
+ * Generate a random private key (32 bytes / 64 hex chars)
6
+ * @returns Private key as hex string with 0x prefix
7
+ */
8
+ export function generatePrivateKey() {
9
+ const privateKeyBytes = secp256k1.utils.randomPrivateKey();
10
+ return ('0x' + Buffer.from(privateKeyBytes).toString('hex'));
11
+ }
12
+ /**
13
+ * Derive Ethereum address from private key
14
+ * @param privateKey - Private key as hex string (with or without 0x prefix)
15
+ * @returns Checksummed Ethereum address
16
+ */
17
+ export function privateKeyToAddress(privateKey) {
18
+ const cleanKey = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey;
19
+ const keyBytes = Buffer.from(cleanKey, 'hex');
20
+ // Get uncompressed public key (65 bytes: 0x04 + 64 bytes)
21
+ const publicKey = secp256k1.getPublicKey(keyBytes, false);
22
+ // Hash the public key (excluding the 0x04 prefix byte)
23
+ const hash = keccak_256(publicKey.slice(1));
24
+ // Take last 20 bytes as address
25
+ const addressBytes = hash.slice(-20);
26
+ const address = '0x' + Buffer.from(addressBytes).toString('hex');
27
+ return checksumAddress(address);
28
+ }
29
+ /**
30
+ * Calculate keccak256 hash of data
31
+ * @param data - Hex string or Uint8Array to hash
32
+ * @returns Hash as hex string with 0x prefix
33
+ */
34
+ export function keccak256(data) {
35
+ let bytes;
36
+ if (typeof data === 'string') {
37
+ const cleanData = data.startsWith('0x') ? data.slice(2) : data;
38
+ bytes = Buffer.from(cleanData, 'hex');
39
+ }
40
+ else {
41
+ bytes = data;
42
+ }
43
+ const hash = keccak_256(bytes);
44
+ return ('0x' + Buffer.from(hash).toString('hex'));
45
+ }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export { CirclesConverter } from './circlesConverter';
2
- export { bytesToHex } from './bytes';
3
- export { encodeFunctionData, decodeFunctionResult, decodeErrorResult, checksumAddress } from './abi';
2
+ export { bytesToHex, hexToBytes } from './bytes';
3
+ export { encodeFunctionData, decodeFunctionResult, decodeErrorResult, checksumAddress, encodeAbiParameters } from './abi';
4
4
  export { cidV0ToHex, cidV0ToUint8Array } from './cid';
5
5
  export { uint256ToAddress } from './address';
6
- export { ZERO_ADDRESS } from './constants';
6
+ export { ZERO_ADDRESS, INVITATION_FEE, MAX_FLOW, SAFE_PROXY_FACTORY, ACCOUNT_INITIALIZER_HASH, ACCOUNT_CREATION_CODE_HASH } from './constants';
7
+ export { circlesConfig } from './config';
7
8
  export { parseContractError, ContractError } from './contractErrors';
9
+ export { generatePrivateKey, privateKeyToAddress, keccak256 } from './crypto';
8
10
  export { CirclesError, ValidationError, EncodingError, wrapError, isCirclesError, getErrorMessage, } from './errors';
9
11
  export type { BaseErrorSource, UtilsErrorSource } from './errors';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AACrG,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGrE,OAAO,EACL,YAAY,EACZ,eAAe,EACf,aAAa,EACb,SAAS,EACT,cAAc,EACd,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC1H,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAC/I,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG9E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,aAAa,EACb,SAAS,EACT,cAAc,EACd,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}